/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* libwps
* Version: MPL 2.0 / LGPLv2.1+
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Major Contributor(s):
* Copyright (C) 2015 Sean Young <sean@mess.org>
*
* For minor contributions see the git repository.
*
* Alternatively, the contents of this file may be used under the terms
* of the GNU Lesser General Public License Version 2.1 or later
* (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are
* applicable instead of those above.
*
* For further information visit http://libwps.sourceforge.net
*/
#include <librevenge-stream/librevenge-stream.h>
#include "libwps_internal.h"
#include "WPSContentListener.h"
#include "WPSParagraph.h"
#include "WPSFont.h"
#include "WPSHeader.h"
#include "MSWrite.h"
#include "DosWord.h"
#include <algorithm>
#include <cstring>
#include <cstdio>
namespace DosWordParserInternal
{
struct CHP
{
CHP()
: m_fStyled(0)
, m_fBold(0)
, m_hps(0)
, m_fUline(0)
, m_unused(0)
, m_hpsPos(0)
, m_clr(0)
{
}
uint8_t m_fStyled;
uint8_t m_fBold;
uint8_t m_hps;
uint8_t m_fUline;
uint8_t m_unused;
uint8_t m_hpsPos;
uint8_t m_clr;
};
struct PAP
{
//! constructor
PAP()
: m_style(0)
, m_justification(0)
, m_dxaRight(0)
, m_dxaLeft(0)
, m_dxaLeft1(0)
, m_dyaLine(0)
, m_dyaBefore(0)
, m_dyaAfter(0)
, m_rhc(0)
, m_border(0)
, m_shade(0)
, m_pos(0)
, m_dxaFromText(0)
{
m_reserved2[0]=m_reserved2[1]=0;
}
uint8_t m_style;
uint8_t m_justification;
uint8_t m_reserved2[2];
uint16_t m_dxaRight, m_dxaLeft, m_dxaLeft1, m_dyaLine;
uint16_t m_dyaBefore, m_dyaAfter;
uint8_t m_rhc;
uint8_t m_border;
uint8_t m_shade;
uint8_t m_pos;
uint16_t m_dxaFromText;
struct TBD
{
TBD()
: m_dxa(0)
, m_jcTab(0)
, m_chAlign(0)
{
}
uint16_t m_dxa;
uint8_t m_jcTab;
uint8_t m_chAlign;
} m_TBD[20];
};
// the file header offsets
enum HeaderOffset
{
HEADER_W_WIDENT = 0,
HEADER_W_DTY = 2,
HEADER_W_WTOOL = 4,
HEADER_D_FCMAC = 14,
HEADER_W_PNPARA = 18,
HEADER_W_PNFNTB = 20,
HEADER_W_PNBKMK = 22,
HEADER_W_PNSETB = 24,
HEADER_W_PNBFTB = 26,
HEADER_W_PNSUMD = 28,
HEADER_W_PNMAC = 106,
HEADER_B_VERSION = 116,
HEADER_B_ASV = 117,
HEADER_W_CODEPAGE = 126
};
}
DosWordParser::DosWordParser(RVNGInputStreamPtr &input, WPSHeaderPtr &header,
libwps_tools_win::Font::Type encoding)
: MSWriteParser(input, header, encoding)
{
}
DosWordParser::~DosWordParser()
{
}
void DosWordParser::readFFNTB()
{
// Microsoft Word for DOS does not have this section
WPS_DEBUG_MSG(("DosWordParser::readFFNTB: unexpected\n"));
}
// basic function to check if the header is ok
bool DosWordParser::checkHeader(WPSHeader *header, bool /*strict*/)
{
RVNGInputStreamPtr input = getInput();
if (!input || !checkFilePosition(0x100))
{
WPS_DEBUG_MSG(("DosWordParser::checkHeader: file is too short\n"));
return false;
}
input->seek(DosWordParserInternal::HEADER_B_ASV, librevenge::RVNG_SEEK_SET);
if (libwps::readU8(input) & 2)
{
WPS_DEBUG_MSG(("DosWordParser::checkHeader: file is autosaved\n"));
return false;
}
input->seek(DosWordParserInternal::HEADER_B_VERSION, librevenge::RVNG_SEEK_SET);
uint8_t ver = libwps::readU8(input);
switch (ver)
{
case 0:
WPS_DEBUG_MSG(("DosWordParser::checkHeader: version 4.0 or earlier\n"));
header->setMajorVersion(4);
break;
case 3:
WPS_DEBUG_MSG(("DosWordParser::checkHeader: version 5 OEM\n"));
header->setMajorVersion(5);
break;
case 4:
WPS_DEBUG_MSG(("DosWordParser::checkHeader: version 5\n"));
header->setMajorVersion(5);
break;
case 7:
WPS_DEBUG_MSG(("DosWordParser::checkHeader: version 5.5\n"));
header->setMajorVersion(5);
break;
case 9:
WPS_DEBUG_MSG(("DosWordParser::checkHeader: version 6.0\n"));
header->setMajorVersion(6);
break;
default:
WPS_DEBUG_MSG(("DosWordParser::checkHeader: unknown version %u\n", ver));
break;
}
input->seek(DosWordParserInternal::HEADER_W_CODEPAGE, librevenge::RVNG_SEEK_SET);
uint16_t codepage = libwps::readU16(input);
if (!codepage)
header->setNeedEncoding(true);
return true;
}
libwps_tools_win::Font::Type DosWordParser::getFileEncoding(libwps_tools_win::Font::Type encoding)
{
RVNGInputStreamPtr input = getInput();
input->seek(DosWordParserInternal::HEADER_W_CODEPAGE, librevenge::RVNG_SEEK_SET);
uint16_t codepage = libwps::readU16(input);
WPS_DEBUG_MSG(("DosWordParser::getFileEncoding: codepage %u\n", codepage));
if (codepage)
encoding = libwps_tools_win::Font::getTypeForOEM(codepage);
if (encoding == libwps_tools_win::Font::UNKNOWN)
encoding = libwps_tools_win::Font::CP_437;
return encoding;
}
WPSColor DosWordParser::color(int clr)
{
switch (clr)
{
default:
case 0: // black (default)
return WPSColor(0, 0, 0);
case 1: // red
return WPSColor(255, 0, 0);
case 2: // green
return WPSColor(0, 255, 0);
case 3: // blue
return WPSColor(0, 0, 255);
case 4: // violet
return WPSColor(127, 0, 255);
case 5: // magenta
return WPSColor(255, 0, 255);
case 6: // yellow
return WPSColor(0, 255, 255);
case 7: // white
return WPSColor(255, 255, 255);
}
}
void DosWordParser::readCHP(uint32_t fcFirst, uint32_t fcLim, unsigned cch)
{
RVNGInputStreamPtr input = getInput();
DosWordParserInternal::CHP chp;
chp.m_hps = 24;
if (cch)
{
if (cch > sizeof(chp))
cch = sizeof(chp);
unsigned long read_bytes;
const unsigned char *p = input->read(cch, read_bytes);
if (read_bytes != cch)
{
WPS_DEBUG_MSG(("DosWordParser::readCHP failed to read CHP entry\n"));
throw (libwps::ParseException());
}
memcpy(&chp, p, cch);
}
MSWriteParserInternal::Font font;
if (chp.m_fStyled & 1)
{
switch (chp.m_fStyled / 2)
{
case 13: // footnote reference
font.m_footnote = true;
break;
case 26: // annotation reference
font.m_annotation = true;
break;
default:
WPS_DEBUG_MSG(("Style sheet stc=%u %x-%x\n", chp.m_fStyled / 2, fcFirst, fcLim));
break;
}
}
unsigned ftc = (chp.m_fBold / 4);
// Note the font depends on the printer driver
if (ftc <= 15)
font.m_name.sprintf("modern %c", 'a' + ftc);
else if (ftc <= 31)
font.m_name.sprintf("roman %c", 'a' + (ftc - 16));
else if (ftc <= 39)
font.m_name.sprintf("script %c", 'a' + (ftc - 32));
else if (ftc <= 47)
font.m_name.sprintf("foreign %c", 'a' + (ftc - 40));
else if (ftc <= 55)
font.m_name.sprintf("decor %c", 'a' + (ftc - 48));
else
font.m_name.sprintf("symbol %c", 'a' + (ftc - 56));
font.m_size = chp.m_hps / 2.0;
if (chp.m_fBold & 1)
font.m_attributes |= WPS_BOLD_BIT;
if (chp.m_fBold & 2)
font.m_attributes |= WPS_ITALICS_BIT;
if (chp.m_fUline & 1)
font.m_attributes |= WPS_UNDERLINE_BIT;
if (chp.m_fUline & 2)
font.m_attributes |= WPS_STRIKEOUT_BIT;
if (chp.m_fUline & 4)
font.m_attributes |= WPS_DOUBLE_UNDERLINE_BIT;
// FIXME: if (chp.m_fUline & 8) marks a text new (not accepted)
if ((chp.m_fUline & 0x30) == 0x10)
font.m_attributes |= WPS_ALL_CAPS_BIT;
else if ((chp.m_fUline & 0x30) == 0x30)
font.m_attributes |= WPS_SMALL_CAPS_BIT;
if (chp.m_fUline & 0x40)
font.m_special = true;
if (chp.m_fUline & 0x80)
font.m_attributes |= WPS_HIDDEN_BIT;
if (chp.m_hpsPos)
{
if (chp.m_hpsPos & 0x80)
font.m_attributes |= WPS_SUBSCRIPT_BIT;
else
font.m_attributes |= WPS_SUPERSCRIPT_BIT;
}
font.m_fcFirst = fcFirst;
font.m_fcLim = fcLim;
font.m_encoding = libwps_tools_win::Font::getFontType(font.m_name);
if (font.m_encoding == libwps_tools_win::Font::UNKNOWN)
font.m_encoding = m_fontType;
font.m_color = color(chp.m_clr & 7);
m_fontList.push_back(font);
}
void DosWordParser::readPAP(uint32_t fcFirst, uint32_t fcLim, unsigned cch)
{
RVNGInputStreamPtr input = getInput();
DosWordParserInternal::PAP pap;
WPS_LE_PUT_GUINT16(&pap.m_dyaLine, 240);
if (cch)
{
if (cch > sizeof(pap))
cch = sizeof(pap);
unsigned long read_bytes;
const unsigned char *p = input->read(cch, read_bytes);
if (read_bytes != cch)
{
WPS_DEBUG_MSG(("DosWordParser::readPAP failed to read PAP\n"));
throw (libwps::ParseException());
}
memcpy(&pap, p, cch);
}
auto dxaLeft = (int16_t) WPS_LE_GET_GUINT16(&pap.m_dxaLeft);
auto dxaLeft1 = (int16_t) WPS_LE_GET_GUINT16(&pap.m_dxaLeft1);
auto dxaRight = (int16_t) WPS_LE_GET_GUINT16(&pap.m_dxaRight);
MSWriteParserInternal::Paragraph para;
int i;
for (i=0; i<20; i++)
{
auto pos = WPS_LE_GET_GUINT16(&pap.m_TBD[i].m_dxa);
if (!pos)
break;
WPSTabStop::Alignment align;
switch (pap.m_TBD[i].m_jcTab & 3)
{
default:
case 0:
align = WPSTabStop::LEFT;
break;
case 1:
align = WPSTabStop::CENTER;
break;
case 2:
align = WPSTabStop::RIGHT;
break;
case 3:
align = WPSTabStop::DECIMAL;
break;
}
unsigned leader = (pap.m_TBD[i].m_jcTab >> 3) & 3;
WPSTabStop tab(pos / 1440., align, uint16_t("\0.-_"[leader]));
para.m_tabs.push_back(tab);
if (dxaLeft + dxaLeft1 == pos)
para.m_skiptab = true;
}
switch (pap.m_justification & 3)
{
default:
case 0:
para.m_justify = libwps::JustificationLeft;
break;
case 1:
para.m_justify = libwps::JustificationCenter;
break;
case 2:
para.m_justify = libwps::JustificationRight;
break;
case 3:
para.m_justify = libwps::JustificationFull;
break;
}
para.m_margins[0] = dxaLeft1 / 1440.0;
para.m_margins[1] = dxaLeft / 1440.0;
para.m_margins[2] = dxaRight / 1440.0;
// spacings
auto dyaLine = (int16_t) WPS_LE_GET_GUINT16(&pap.m_dyaLine);
auto dyaBefore = WPS_LE_GET_GUINT16(&pap.m_dyaBefore);
auto dyaAfter = WPS_LE_GET_GUINT16(&pap.m_dyaAfter);
// dyaLine = -40 means "auto"
if (dyaLine > 0)
para.m_spacings[0] = dyaLine / 240.0;
para.m_spacings[1] = dyaBefore / 240.0;
para.m_spacings[2] = dyaAfter / 240.0;
para.m_fcFirst = fcFirst;
para.m_fcLim = fcLim;
if (pap.m_rhc & 0xe)
{
if (pap.m_rhc & 1)
para.m_Location = MSWriteParserInternal::Paragraph::FOOTER;
else
para.m_Location = MSWriteParserInternal::Paragraph::HEADER;
switch ((pap.m_rhc >> 1) & 3)
{
default:
case 3: // all
para.m_HeaderFooterOccurrence = WPSPageSpan::ALL;
break;
case 2: // even
para.m_HeaderFooterOccurrence = WPSPageSpan::EVEN;
break;
case 1: // odd
para.m_HeaderFooterOccurrence = WPSPageSpan::ODD;
break;
case 0: // never; however might be on first page
para.m_HeaderFooterOccurrence = WPSPageSpan::NEVER;
break;
}
para.m_firstpage = (pap.m_rhc & 0x08) != 0;
}
if (pap.m_justification & 0x20)
para.m_headerUseMargin = true;
if (pap.m_style & 1)
{
switch (pap.m_style / 2)
{
case 39: // footnote
case 87: // annotation
para.m_Location = MSWriteParserInternal::Paragraph::FOOTNOTE;
break;
default:
WPS_DEBUG_MSG(("DosWordParser::readPAP pap unknown style stc=%u %x-%x\n", pap.m_style / 2, fcFirst, fcLim));
break;
}
}
// Borders
if (pap.m_rhc & 0x30)
{
if ((pap.m_rhc & 0x30) == 0x10)
para.m_border = 15;
else
para.m_border = pap.m_border & 15;
WPSBorder::Type type = WPSBorder::Single;
int width = 1;
switch (pap.m_rhc & 0xc0)
{
default:
case 0: // normal
break;
case 0x40: // bold
width = 2;
break;
case 0x80: // Double
type = WPSBorder::Double;
break;
case 0xc0: // thick
width = 8;
break;
}
para.m_borderStyle.m_type = type;
para.m_borderStyle.m_width = width;
para.m_borderStyle.m_color = color((pap.m_border / 16) & 7);
}
if (pap.m_justification & 4)
para.m_breakStatus |= libwps::NoBreakBit;
if (pap.m_justification & 8)
para.m_breakStatus |= libwps::NoBreakWithNextBit;
// paragraph shading
if (pap.m_shade & 0x7f)
{
WPSColor c = color((pap.m_pos >> 4) & 7);
unsigned percent = std::min(pap.m_shade & 0x7fu, 100u);
// Use percent to increase brightness
// 100% means color stays the same
// 0% means white
unsigned add = (255 * (100 - percent)) / 100;
para.m_backgroundColor = WPSColor(
(unsigned char)std::min(c.getRed() + add, 255u),
(unsigned char)std::min(c.getGreen() + add, 255u),
(unsigned char)std::min(c.getBlue() + add, 255u));
}
// FIXME: side-by-side
// FIXME: paragraph position
m_paragraphList.push_back(para);
}
void DosWordParser::insertSpecial(uint8_t val, uint32_t fc, MSWriteParserInternal::Paragraph::Location location)
{
librevenge::RVNGString empty;
switch (val)
{
case 1: // page name
m_listener->insertField(WPSField(WPSField::PageNumber));
break;
case 2: // current date
m_listener->insertField(WPSField(WPSField::Date));
break;
case 3: // current time
m_listener->insertField(WPSField(WPSField::Time));
break;
case 4: // annotation reference
if (location == MSWriteParserInternal::Paragraph::MAIN)
insertNote(true, fc, empty);
break;
case 5: // footnote reference
if (location == MSWriteParserInternal::Paragraph::MAIN)
insertNote(false, fc, empty);
break;
case 7: // sequence mark
WPS_DEBUG_MSG(("Sequence mark\n"));
break;
case 8: // sequence reference mark
WPS_DEBUG_MSG(("Sequence reference mark\n"));
break;
case 9: // next page
m_listener->insertField(WPSField(WPSField::PageNumberNext));
break;
default:
WPS_DEBUG_MSG(("DosWordParser::insertSpecial: unknown special %u encountered\n", val));
break;
}
}
void DosWordParser::insertControl(uint8_t val, uint32_t fc)
{
// 0xc4 = normal hyphen, 0xff = nbsp, already handled by cp437
switch (val)
{
case 9:
m_listener->insertTab();
break;
case 10:
case 11:
m_listener->insertEOL();
break;
case 12:
{
// each section is ended with 0x0c but no page break might
// be required
for (auto const &s : m_sections)
{
if (fc + 1 == s.m_fcLim)
{
switch (s.m_bkc)
{
case 0:
break;
case 1:
m_listener->insertBreak(WPS_COLUMN_BREAK);
break;
default:
m_listener->insertBreak(WPS_PAGE_BREAK);
break;
}
return;
}
}
m_listener->insertBreak(WPS_PAGE_BREAK);
break;
}
case 13: // carriage return
break;
case 14: // column break
m_listener->insertBreak(WPS_COLUMN_BREAK);
break;
case 15: // em-hyphen
m_listener->insertUnicode(0x8212);
break;
case 31: // soft hyphen
m_listener->insertUnicode(0xad);
break;
default:
WPS_DEBUG_MSG(("DosWordParser::insertControl: unexpected control %u\n", val));
break;
}
}
void DosWordParser::readSUMD()
{
RVNGInputStreamPtr input = getInput();
input->seek(DosWordParserInternal::HEADER_W_PNSUMD, librevenge::RVNG_SEEK_SET);
uint16_t pnSumd = libwps::readU16(input);
input->seek(DosWordParserInternal::HEADER_W_PNMAC, librevenge::RVNG_SEEK_SET);
uint16_t pnMac = libwps::readU16(input);
if (!pnSumd || pnSumd == pnMac)
{
// No summary page
return;
}
/*
* The page starts with 9 uint16_t values which are offsets. Sometimes
* the page contains garbage; when it does not, the first offset is 0.
*/
uint32_t fc = pnSumd * 0x80;
int i;
if (!checkFilePosition(fc + 20))
{
WPS_DEBUG_MSG(("DosWordParser::readSUMD: summary missing\n"));
return;
}
input->seek(long(fc), librevenge::RVNG_SEEK_SET);
if (libwps::readU16(input) >= 0x80)
{
WPS_DEBUG_MSG(("DosWordParser::readSUMD: garbage\n"));
return;
}
// Step over the offsets; it's packed together anyway.
fc += 0x14;
static const char *sum_types[] =
{
"dc:title", // title
"dc:creator", // author
"dc:publisher", // operator
"meta:keyword", // keywords
"dc:description", // comments
"librevenge:version-number", // version
nullptr
};
input->seek(long(fc), librevenge::RVNG_SEEK_SET);
for (i=0; sum_types[i]; i++)
{
librevenge::RVNGString str;
for (;;)
{
if (!checkFilePosition(++fc))
{
WPS_DEBUG_MSG(("DosWordParser::readSUMD: summary missing\n"));
return;
}
auto ch = char(libwps::readU8(input));
if (!ch)
break;
str.append(ch);
}
if (str.size())
{
librevenge::RVNGString conv = libwps_tools_win::Font::unicodeString((const unsigned char *)str.cstr(), str.size(), m_fontType);
WPS_DEBUG_MSG(("DosWordParser::readSUMD: %d %s\n", i, conv.cstr()));
m_metaData.insert(sum_types[i], conv);
}
}
librevenge::RVNGString creationDate, revisionDate;
int month, day, year;
for (i=0; i<8; i++)
{
if (!checkFilePosition(++fc))
{
WPS_DEBUG_MSG(("DosWordParser::readSUMD: summary missing\n"));
return;
}
auto ch = char(libwps::readU8(input));
if (!ch)
break;
creationDate.append(ch);
}
// Year is given in two decimals since 1900 so fudge any value
// < 50 to be after 2000
if (3 == sscanf(creationDate.cstr(), "%2d/%2d/%4d", &month, &day, &year))
{
librevenge::RVNGString str;
if (year > 50)
year += 1900;
else
year += 2000;
str.sprintf("%d-%d-%d", year, month, day);
m_metaData.insert("meta:creation-date", str);
}
for (i=0; i<8; i++)
{
if (!checkFilePosition(++fc))
{
WPS_DEBUG_MSG(("DosWordParser::readSUMD: summary missing\n"));
return;
}
auto ch = char(libwps::readU8(input));
if (!ch)
break;
revisionDate.append(ch);
}
if (3 == sscanf(revisionDate.cstr(), "%2d/%2d/%4d", &month, &day, &year))
{
librevenge::RVNGString str;
if (year > 50)
year += 1900;
else
year += 2000;
str.sprintf("%d-%d-%d", year, month, day);
m_metaData.insert("dc:date", str);
}
}
void DosWordParser::readFNTB()
{
RVNGInputStreamPtr input = getInput();
input->seek(DosWordParserInternal::HEADER_W_PNFNTB, librevenge::RVNG_SEEK_SET);
uint16_t pnFntb = libwps::readU16(input);
input->seek(DosWordParserInternal::HEADER_W_PNBKMK, librevenge::RVNG_SEEK_SET);
uint16_t pnBkmk = libwps::readU16(input);
if (pnFntb == 0 || pnFntb == pnBkmk)
return;
uint32_t fc = pnFntb * 0x80;
if (!checkFilePosition(fc + 4))
{
WPS_DEBUG_MSG(("DosWordParser::readFNTB: footnote table missing\n"));
return;
}
input->seek(long(fc), librevenge::RVNG_SEEK_SET);
uint16_t noteCount = libwps::readU16(input);
uint16_t noteCountAndDeleted = libwps::readU16(input);
if (noteCount > noteCountAndDeleted)
{
WPS_DEBUG_MSG(("DosWordParser::readFNTB: note counts do not makesense %u %u\n", noteCount, noteCountAndDeleted));
}
for (unsigned note=0; note<noteCount; note++)
{
if (!checkFilePosition(fc + 8))
{
WPS_DEBUG_MSG(("DosWordParser::readFNTB: footnote %u missing\n", note));
return;
}
fc += 8;
MSWriteParserInternal::Footnote footnote;
footnote.m_fcRef = libwps::readU32(input) + 0x80;
footnote.m_fcFtn = libwps::readU32(input) + 0x80;
m_footnotes.push_back(footnote);
}
}
void DosWordParser::readSED()
{
unsigned pnSetb, pnBftb;
RVNGInputStreamPtr input = getInput();
input->seek(DosWordParserInternal::HEADER_W_PNSETB, librevenge::RVNG_SEEK_SET);
pnSetb = libwps::readU16(input);
input->seek(DosWordParserInternal::HEADER_W_PNBFTB, librevenge::RVNG_SEEK_SET);
pnBftb = libwps::readU16(input);
if (pnSetb && pnSetb != pnBftb)
{
if (!checkFilePosition(pnSetb * 0x80 + 4))
{
WPS_DEBUG_MSG(("Section is truncated\n"));
throw (libwps::ParseException());
}
input->seek(long(pnSetb) * 0x80, librevenge::RVNG_SEEK_SET);
uint16_t cset = libwps::readU16(input);
// ignore csetMax
for (unsigned sed = 0; sed<cset; sed++)
{
if (!checkFilePosition(pnSetb * 0x80 + (sed + 1) * 10 + 4))
{
WPS_DEBUG_MSG(("is truncated\n"));
throw (libwps::ParseException());
}
input->seek(long(pnSetb * 0x80 + sed * 10 + 4), librevenge::RVNG_SEEK_SET);
uint32_t fcLim = libwps::readU32(input) + 0x80;
// unknown
input->seek(2, librevenge::RVNG_SEEK_CUR);
uint32_t fcSep = libwps::readU32(input);
if (fcSep == 0xffffffff)
break;
readSECT(fcSep, fcLim);
if (fcLim >= m_fcMac)
break;
}
}
if (m_sections.empty() || m_sections.back().m_fcLim < m_fcMac)
{
// create default section by reading invalid fc
readSECT(m_fileLength, m_fcMac);
}
}
void DosWordParser::readSECT(uint32_t fcSep, uint32_t fcLim)
{
RVNGInputStreamPtr input = getInput();
MSWriteParserInternal::Section sep;
if (checkFilePosition(fcSep + 1))
{
input->seek(long(fcSep), librevenge::RVNG_SEEK_SET);
uint8_t headerSize = libwps::readU8(input);
if (headerSize<1 || !checkFilePosition(fcSep+1+headerSize))
{
WPS_DEBUG_MSG(("DosWordParser::readSECT: can not read the structure, using default\n"));
}
else
{
do
{
if (headerSize < 2) break;
input->seek(1, librevenge::RVNG_SEEK_CUR); // skip style
sep.m_bkc = libwps::readU8(input) & 7;
// read section
if (headerSize < 4) break;
sep.m_yaMac=double(libwps::readU16(input))/1440.;
if (headerSize < 6) break;
sep.m_xaMac=double(libwps::readU16(input))/1440.;
if (headerSize < 8) break;
sep.m_startPageNumber=libwps::readU16(input);
if (headerSize < 10) break;
sep.m_yaTop=double(libwps::readU16(input))/1440.;
if (headerSize < 12) break;
sep.m_dyaText=double(libwps::readU16(input))/1440.;
if (headerSize < 14) break;
sep.m_xaLeft=double(libwps::readU16(input))/1440.;
if (headerSize < 16) break;
sep.m_dxaText=double(libwps::readU16(input))/1440.;
if (headerSize < 17) break;
sep.m_endFtns = (libwps::readU8(input) & 0x80) != 0;
if (headerSize < 18) break;
sep.m_columns = libwps::readU8(input);
if (headerSize < 20) break;
sep.m_yaHeader=double(libwps::readU16(input))/1440.;
if (headerSize < 22) break;
sep.m_yaFooter=double(libwps::readU16(input))/1440.;
if (headerSize < 24) break;
sep.m_dxaColumns=double(libwps::readU16(input))/1440.;
if (headerSize < 26) break;
sep.m_dxaGutter=double(libwps::readU16(input))/1440.;
}
while (0);
}
}
sep.m_fcLim = fcLim;
m_sections.push_back(sep);
}
/* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */