You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/filters/kword/mswrite/structures_private.cpp

1623 lines
41 KiB

/* This file is part of the LibMSWrite Library
Copyright (C) 2001-2003 Clarence Dang <clarencedang@users.sourceforge.net>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License Version 2 as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License Version 2 for more details.
You should have received a copy of the GNU Library General Public License
Version 2 along with this library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
LibMSWrite Project Website:
http://sourceforge.net/projects/libmswrite/
*/
/*
* structures_private.cpp - Process Internal Microsoft(r) Write file structures
* - that are hidden/abstracted away from the user
* This file has ugly reading/writing code that couldn't be generated.
* It performs some higher-level sanity checks.
*
* Don't use any of these classes as it would defeat the purpose of LibMSWrite.
*/
#include "structures_private.h"
#include "structures.h"
namespace MSWrite
{
Header::Header ()
{
}
Header::~Header ()
{
}
Header &Header::operator= (const Header &rhs)
{
if (this == &rhs)
return *this;
HeaderGenerated::operator= (rhs);
m_numCharBytes = rhs.m_numCharBytes;
m_pageCharInfo = rhs.m_pageCharInfo;
return *this;
}
bool Header::readFromDevice (void)
{
CHECK_DEVICE;
#ifdef DEBUG_HEADER
m_device->debug ("\n<<<< Header::readFromDevice >>>>\n");
#endif
if (!m_device->seekInternal (0, SEEK_SET)) return false;
if (!HeaderGenerated::readFromDevice ()) return false;
#ifdef DEBUG_HEADER
switch (m_magic)
{
case 0xBE31: m_device->debug ("normal write file\n"); break;
case 0xBE32: m_device->debug ("write file with OLE\n"); break;
default: ErrorAndQuit (Error::InternalError, "magic test passed but failed later?");
}
#endif
m_numCharBytes = m_numCharBytesPlus128 - 128;
#ifdef DEBUG_HEADER
m_device->debug ("num bytes of data (text+images+OLE): ", m_numCharBytes);
m_device->debug ("page # start of parainfo: ", m_pageParaInfo);
m_device->debug ("page # footnote table: ", m_pageFootnoteTable);
m_device->debug ("page # pageLayout: ", m_pageSectionProperty);
m_device->debug ("page # sectionTable: ", m_pageSectionTable);
m_device->debug ("page # pageTable: ", m_pagePageTable);
m_device->debug ("page # fontTable: ", m_pageFontTable);
m_device->debug ("num pages in file: ", m_numPages);
#endif
/*
* more checks
*/
// footnoteTables simply do not exist...
if (m_pageFootnoteTable != m_pageSectionProperty)
ErrorAndQuit (Error::InvalidFormat, "document should not have a footnoteTable\n");
// cannot have a sectionProperty without a sectionTable or vice-versa
// no sectionProperty?
if (m_pageSectionProperty == m_pagePageTable)
{
// must not have a sectionTable then
if (m_pageSectionTable != m_pagePageTable)
ErrorAndQuit (Error::InvalidFormat, "sectionTable without sectionProperty\n");
}
// have sectionProperty...
else
{
if (m_pageSectionTable != m_pageSectionProperty + 1)
ErrorAndQuit (Error::InvalidFormat, "sectionTable not immediately after sectionProperty\n");
if (m_pageSectionTable == m_pagePageTable)
ErrorAndQuit (Error::InvalidFormat, "sectionProperty without sectionTable\n");
}
// charInfo page comes immediately after the header and text
m_pageCharInfo = (m_numCharBytesPlus128 + 127) / 128;
#ifdef DEBUG_HEADER
m_device->debug ("page # start of charinfo: ", m_pageCharInfo);
#endif
// catches a lot of corrupted files
if (m_pageCharInfo > m_pageParaInfo)
ErrorAndQuit (Error::InvalidFormat, "charInfo page after paraInfo page\n");
return true;
}
bool Header::writeToDevice (void)
{
CHECK_DEVICE;
#ifdef DEBUG_HEADER
m_device->debug ("\n<<<< Header::writeToDevice >>>>\n");
#endif
m_numCharBytesPlus128 = m_numCharBytes + 128;
if (!m_device->seekInternal (0, SEEK_SET)) return false;
if (!HeaderGenerated::writeToDevice ()) return false;
return true;
}
SectionDescriptor::SectionDescriptor ()
{
}
SectionDescriptor::~SectionDescriptor ()
{
}
SectionDescriptor &SectionDescriptor::operator= (const SectionDescriptor &rhs)
{
if (this == &rhs)
return *this;
SectionDescriptorGenerated::operator= (rhs);
return *this;
}
SectionTable::SectionTable ()
{
}
SectionTable::~SectionTable ()
{
}
SectionTable &SectionTable::operator= (const SectionTable &rhs)
{
if (this == &rhs)
return *this;
SectionTableGenerated::operator= (rhs);
NeedsHeader::operator= (rhs);
return *this;
}
// this function really only does some sanity checking
// in fact, a SectionTable is quite useless in Write...
// ...so you actually don't have to call it :)
bool SectionTable::readFromDevice (void)
{
CHECK_DEVICE;
#ifdef DEBUG_PAGELAYOUT
m_device->debug ("\n<<<< SectionTable::readFromDevice >>>>\n");
#endif
int numSectionTablePages = m_header->getNumPageSectionTable ();
#ifdef DEBUG_PAGELAYOUT
m_device->debug ("num sectionTablePages=", numSectionTablePages);
#endif
// no SectionTable
if (numSectionTablePages == 0)
return true;
else if (numSectionTablePages > 1)
ErrorAndQuit (Error::InvalidFormat, "invalid #sectionTablePages\n");
// seek to the SectionTable in the file
if (!m_device->seekInternal (m_header->getPageSectionTable () * 128, SEEK_SET))
return false;
if (!SectionTableGenerated::readFromDevice ()) return false;
#ifdef DEBUG_PAGELAYOUT
m_device->debug ("num sectionDescriptors=", m_numSectionDescriptors);
for (int i = 0; i < 2; i++)
{
m_device->debug ("Dumping SED #", i);
m_device->debug ("\tbyte after section=", m_sed [i]->getAfterEndCharByte ());
m_device->debug ("\tsectionProperty location=", m_sed [i]->getSectionPropertyLocation ());
}
#endif
if (m_numSectionDescriptors != 2)
m_device->error (Error::Warn, "#sectionDescriptors != 2, ignoring");
// check that 1st SectionDescriptor covers all characters
if (m_sed [0]->getAfterEndCharByte () != m_header->getNumCharBytes ())
m_device->error (Error::Warn, "sectionDescriptor #1 does not cover entire document\n");
// check that 1st SectionDescriptor points to the SectionProperty
if (m_sed [0]->getSectionPropertyLocation () != m_header->getPageSectionProperty () * DWord (128))
m_device->error (Error::Warn, "sectionDescriptor #1 does not refer to correct sectionProperty, ignoring\n");
// check that 2nd SectionDescriptor covers after the end of the document
if (m_sed [1]->getAfterEndCharByte () != m_header->getNumCharBytes () + 1)
m_device->error (Error::Warn, "sectionDescriptor #2 does not cover post-document\n");
// check that 2nd SectionDescriptor is indeed a dummy
if (m_sed [1]->getSectionPropertyLocation () != (DWord) 0xFFFFFFFF)
m_device->error (Error::Warn, "sectionDescriptor #2 is not a dummy\n");
return true;
}
bool SectionTable::writeToDevice (const bool needed)
{
CHECK_DEVICE;
#ifdef DEBUG_PAGELAYOUT
m_device->debug ("\n>>>> SectionTable::writeToDevice <<<<\n");
#endif
m_header->setPageSectionTable (m_device->tellInternal () / 128);
// if no sectionProperty, no sectionTable
if (!needed)
return true;
// set that 1st SectionDescriptor covers all characters
m_sed [0]->setAfterEndCharByte (m_header->getNumCharBytes ());
// set that 1st SectionDescriptor points to the SectionProperty
m_sed [0]->setSectionPropertyLocation (m_header->getPageSectionProperty () * 128);
// set that 2nd SectionDescriptor covers after the end of the document
m_sed [1]->setAfterEndCharByte (m_header->getNumCharBytes () + 1);
// set that 2nd SectionDescriptor is indeed a dummy
m_sed [1]->setSectionPropertyLocation ((DWord) 0xFFFFFFFF);
if (!SectionTableGenerated::writeToDevice ())
return false;
return true;
}
FontTable::FontTable ()
{
}
FontTable::~FontTable ()
{
}
FontTable &FontTable::operator= (const FontTable &rhs)
{
if (this == &rhs)
return *this;
FontTableGenerated::operator= (rhs);
NeedsHeader::operator= (rhs);
m_fontList = rhs.m_fontList;
return *this;
}
bool FontTable::readFromDevice (void)
{
CHECK_DEVICE;
#ifdef DEBUG_FONT
m_device->debug ("\n<<<< FontTable::readFromDevice >>>>\n");
#endif
int numFontTablePages = m_header->getNumPageFontTable ();
// no FontTable
if (numFontTablePages == 0)
return true;
// seek to the fontTable in the file
if (!m_device->seekInternal (m_header->getPageFontTable () * 128, SEEK_SET))
return false;
if (!FontTableGenerated::readFromDevice ()) return false;
#ifdef DEBUG_FONT
m_device->debug ("num Fonts: ", m_numFonts);
#endif
bool dontAddToBack = false;
for (int i = 0; i < FontTableGenerated::m_numFonts; i++)
{
#ifdef DEBUG_FONT
m_device->debug ("Font: ", i);
#endif
if (!dontAddToBack)
{
if (!m_fontList.addToBack ())
ErrorAndQuit (Error::OutOfMemory, "could not add Font to fontList\n");
}
else
dontAddToBack = false;
List <Font>::Iterator it = m_fontList.begin (false);
Font &font = *it;
// read font
font.setDevice (m_device);
if (!font.readFromDevice ())
{
// a real error...
if (m_device->bad ())
return false;
//
// ... or Font::readFromDevice() signalled something
//
// font is on next page?
if (font.getNumDataBytes () == 0xFFFF)
{
#ifdef DEBUG_FONT
m_device->debug ("\tcurrent offset=", m_device->tellInternal ());
m_device->debug ("\tnext page offset=", (m_device->tellInternal () + 127) / 128 * 128);
#endif
// seek to next page
if (!m_device->seekInternal ((m_device->tellInternal () + 127) / 128 * 128, SEEK_SET))
return false;
--i; // still reading the same font
dontAddToBack = true; // don't need to add another font, just re-use this sentinel
continue;
}
// no more entries (should _not_ get in here)?
if (font.getNumDataBytes () == 0)
{
if (i != m_numFonts - 1) // actually, this check isn't required
m_device->error (Error::Warn, "font marked as last but is not\n");
// let's not cause problems later with uninitialised Font::m_name's
m_fontList.erase (it);
// better quit just in case (it is better to have fewer fonts than risk errors)
break;
}
}
} // for (int i = 0; i < m_numFonts; i++) {
return true;
}
bool FontTable::writeToDevice (void)
{
CHECK_DEVICE;
#ifdef DEBUG_FONT
m_device->debug ("\n>>>> FontTable::writeToDevice <<<<\n");
#endif
// indicate fontTable page in header
m_header->setPageFontTable (m_device->tellInternal () / 128);
FontTableGenerated::m_numFonts = m_fontList.getNumElements ();
// no fontTable
if (FontTableGenerated::m_numFonts == 0)
{
m_device->error (Error::Warn, "not writing fontTable\n");
return true;
}
// write numFonts
if (!FontTableGenerated::writeToDevice ()) return false;
int i = 0;
for (List <Font>::Iterator it = m_fontList.begin ();
it != m_fontList.end ();
/* don't iterate here since we might "continue" with the same font */)
{
#ifdef DEBUG_FONT
m_device->debug ("\twriting font #", i);
#endif
Font &font = *it;
// write font
font.setDevice (m_device);
if (!font.writeToDevice ())
{
// a real error...
if (m_device->bad ())
return false;
//
// ... or Font::readFromDevice() signalled something
//
// font is on next page then
#ifdef DEBUG_FONT
m_device->debug ("\tcurrent offset=", m_device->tellInternal ());
m_device->debug ("\tnext page offset=", (m_device->tellInternal () + 127) / 128 * 128);
#endif
// seek to next page
if (!m_device->seekInternal ((m_device->tellInternal () + 127) / 128 * 128, SEEK_SET))
return false;
// still writing the same font
continue;
}
// get next font to write
it++;
i++;
}
return true;
}
Font *FontTable::getFont (const DWord fontCode) const
{
// OPT: inefficient, maybe an array of pointers because we can't delete fonts anyway
List <Font>::Iterator it = m_fontList.begin ();
for (int i = 0; i < int (fontCode) && it != m_fontList.end (); i++, ++it)
;
if (it == m_fontList.end ()) return NULL;
return &(*it);
}
DWord FontTable::findFont (const Font *want) const
{
DWord code = 0;
List <Font>::Iterator it;
for (it = m_fontList.begin (); it != m_fontList.end (); ++it)
{
if ((*it) == *want)
return code;
code++;
}
// couldn't find
return 0xFFFFFFFF;
}
DWord FontTable::addFont (const Font *input)
{
CHECK_DEVICE;
#ifdef DEBUG_FONT
m_device->debug ("\t\t\tTrying to add Font ", input->getName ());
#endif
DWord e = findFont (input);
// already in list
if (e != 0xFFFFFFFF)
{
#ifdef DEBUG_FONT
m_device->debug ("\t\t\t\tAlready in list, fontCode=", e);
#endif
// return fontCode
return e;
}
// new font
else
{
#ifdef DEBUG_FONT
m_device->debug ("\t\t\t\tNew font, adding to list\n");
#endif
if (!m_fontList.addToBack (*input))
ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for next font element\n");
return m_fontList.getNumElements () - 1;
}
}
PagePointer::PagePointer ()
{
}
PagePointer::~PagePointer ()
{
}
PagePointer &PagePointer::operator= (const PagePointer &rhs)
{
if (this == &rhs)
return *this;
PagePointerGenerated::operator= (rhs);
return *this;
}
bool PagePointer::readFromDevice (void)
{
CHECK_DEVICE;
if (!PagePointerGenerated::readFromDevice ())
return false;
#ifdef DEBUG_PAGETABLE
m_device->debug ("\t\tpage number: ", m_pageNumber);
m_device->debug ("\t\tfirst char: ", m_firstCharByte);
#endif
return true;
}
bool PagePointer::writeToDevice (void)
{
CHECK_DEVICE;
if (!PagePointerGenerated::writeToDevice ())
return false;
return true;
}
PageTable::PageTable () : m_pageNumberStart (0xFFFF)
{
}
PageTable::~PageTable ()
{
}
PageTable &PageTable::operator= (const PageTable &rhs)
{
if (this == &rhs)
return *this;
PageTableGenerated::operator= (rhs);
NeedsHeader::operator= (rhs);
m_pagePointerList = rhs.m_pagePointerList;
m_pageNumberStart = rhs.m_pageNumberStart;
m_pageTableIterator = rhs.m_pageTableIterator;
return *this;
}
bool PageTable::readFromDevice (void)
{
CHECK_DEVICE;
#ifdef DEBUG_PAGETABLE
m_device->debug ("\n<<<< PageTable::readFromDevice >>>>\n");
#endif
#ifdef CHECK_INTERNAL
if (m_pageNumberStart == (Word) 0xFFFF || NeedsHeader::m_header == NULL)
ErrorAndQuit (Error::InternalError, "PageTable call not setup\n");
#endif
// no pageTable
if (m_header->getNumPagePageTable () == 0)
return true;
// seek to the pageTable in the file
if (!m_device->seekInternal (m_header->getPagePageTable () * 128, SEEK_SET))
return false;
if (!PageTableGenerated::readFromDevice ())
return false;
#ifdef DEBUG_PAGETABLE
Dump (numPagePointers);
Dump (zero);
#endif
DWord lastCharByte = (DWord) 0xFFFFFFFF;
Word lastPage = (Word) 0xFFFF; // do not have to init
for (int i = 0; i < m_numPagePointers; i++)
{
if (!m_pagePointerList.addToBack ())
ErrorAndQuit (Error::OutOfMemory, "could not add pagePointer to list\n");
PagePointer &pp = *m_pagePointerList.begin (false);
#ifdef DEBUG_PAGETABLE
m_device->debug ("\tPagePointer: ", i);
#endif
// read pointer
pp.setDevice (m_device);
if (!pp.readFromDevice ()) return false;
// first pointer?
if (i == 0)
{
if (pp.getPageNumber () != m_pageNumberStart)
ErrorAndQuit (Error::InvalidFormat, "pageTable & sectionProperty disagree on pageNumberStart\n");
}
else
{
// according to KOffice 1.2:
//
// "the pageTable can get really out of sync with reality
// if the user doesn't repaginate after deleting a few pages
// -- so this is just a warning, not an error"
//
if (pp.getPageNumber () != lastPage + 1)
m_device->error (Error::Warn, "pages don't follow each other\n");
if (pp.getFirstCharByte () <= lastCharByte)
ErrorAndQuit (Error::InvalidFormat, "pageTable is not going forward?\n");
}
// for checking, on next iteration
lastPage = pp.getPageNumber ();
lastCharByte = pp.getFirstCharByte ();
}
return true;
}
bool PageTable::writeToDevice (void)
{
CHECK_DEVICE;
#ifdef DEBUG_PAGETABLE
m_device->debug ("\n>>>> PageTable::writeToDevice <<<<\n");
#endif
m_header->setPagePageTable (m_device->tellInternal () / 128);
// LibMSWrite directly (!) adds to the list so m_numPagePointers may be out of date
PageTableGenerated::m_numPagePointers = m_pagePointerList.getNumElements ();
// no pageTable
if (m_numPagePointers == 0)
return true;
// write numPagePointers, zero
if (!PageTableGenerated::writeToDevice ())
return false;
int i = 0;
List <PagePointer>::Iterator it;
for (it = m_pagePointerList.begin (); it != m_pagePointerList.end (); ++it, i++)
{
PagePointer &pp = (*it);
#ifdef DEBUG_PAGETABLE
m_device->debug ("\tPagePointer: ", i);
#endif
// read page pointer
pp.setDevice (m_device);
if (!pp.writeToDevice ())
return false;
}
return true;
}
FormatPointer::FormatPointer () : m_afterEndCharByte (0)
{
}
FormatPointer::~FormatPointer ()
{
}
FormatPointer &FormatPointer::operator= (const FormatPointer &rhs)
{
if (this == &rhs)
return *this;
FormatPointerGenerated::operator= (rhs);
m_afterEndCharByte = rhs.m_afterEndCharByte;
m_formatProperty = rhs.m_formatProperty;
return *this;
}
bool FormatPointer::readFromDevice (void)
{
CHECK_DEVICE;
if (!FormatPointerGenerated::readFromDevice ())
return false;
m_afterEndCharByte = m_afterEndCharBytePlus128 - 128;
#ifdef DEBUG_FORMATINFO
m_device->debug ("\t\tafterEndCharByte: ", m_afterEndCharByte);
m_device->debug ("\t\tformatPropertyOffset: ", m_formatPropertyOffset);
#endif
return true;
}
bool FormatPointer::writeToDevice (void)
{
CHECK_DEVICE;
#ifdef DEBUG_FORMATINFO
m_device->debug ("\t\t\t\tafterEndCharByte: ", m_afterEndCharByte);
m_device->debug ("\t\t\t\tformatPropertyOffset: ", m_formatPropertyOffset);
#endif
m_afterEndCharBytePlus128 = m_afterEndCharByte + 128;
if (!FormatPointerGenerated::writeToDevice ())
return false;
return true;
}
FormatInfoPage::FormatInfoPage () : m_firstCharByte (0),
m_formatPointer (NULL),
m_formatCharProperty (NULL),
m_fontTable (NULL),
m_formatParaProperty (NULL),
m_leftMargin (0xFFFF), m_rightMargin (0xFFFF),
m_formatPointerUpto (0),
m_nextCharByte (0),
m_formatPointerPos (0), m_formatPropertyPos (123)
{
// m_type=
// m_lastPropertyOffset=
// m_numProperty=
}
FormatInfoPage::~FormatInfoPage ()
{
delete [] m_formatParaProperty;
delete [] m_formatCharProperty;
delete [] m_formatPointer;
}
bool FormatInfoPage::readFromDevice (void)
{
CHECK_DEVICE;
#ifdef DEBUG_FORMATINFO
if (m_type == ParaType)
m_device->debug ("FormatInfoPage::readFromDevice (ParaType)\n");
else // if (m_type == CharType)
m_device->debug ("FormatInfoPage::readFromDevice (CharType)\n");
#endif
if (!FormatInfoPageGenerated::readFromDevice ())
return false;
m_firstCharByte = FormatInfoPageGenerated::m_firstCharBytePlus128 - 128;
#ifdef DEBUG_FORMATINFO
m_device->debug ("number of FormatPointers on this page: ", FormatInfoPageGenerated::m_numFormatPointers);
m_device->debug ("byte number of first character covered by this page: ", m_firstCharByte);
#endif
return true;
}
bool FormatInfoPage::writeToDevice (void)
{
CHECK_DEVICE;
#ifdef DEBUG_FORMATINFO
if (m_type == ParaType)
m_device->debug ("FormatInfoPage::writeToDevice (ParaType)\n");
else // if (m_type == CharType)
m_device->debug ("FormatInfoPage::writeToDevice (CharType)\n");
#endif
FormatInfoPageGenerated::m_firstCharBytePlus128 = m_firstCharByte + 128;
#ifdef DEBUG_FORMATINFO
m_device->debug ("\tnumber of FormatPointers on this page: ", FormatInfoPageGenerated::m_numFormatPointers);
m_device->debug ("\tbyte number of first character covered by this page: ", m_firstCharByte);
#endif
// will call FormatInfoPageGenerated::writeToArray()...
// ...which will resolve to FormatInfoPage::writeToArray()...
// which will then call the base FormatInfoPageGenerated::writeToArray()
return FormatInfoPageGenerated::writeToDevice ();
}
bool FormatInfoPage::writeToArray (void)
{
CHECK_DEVICE;
#ifdef DEBUG_FORMATINFO
if (m_type == ParaType)
m_device->debug ("\tFormatInfoPage::writeToArray (ParaType)\n");
else // if (m_type == CharType)
m_device->debug ("\tFormatInfoPage::writeToArray (CharType)\n");
#endif
MemoryDevice memdev;
m_formatPointerPos = 0;
m_formatPropertyPos = 123;
#ifdef DEBUG_FORMATINFO
m_device->debug ("\t\tWriting FormatPointer[], num=", m_numFormatPointers);
#endif
for (int i = 0; i < m_numFormatPointers; i++)
{
#ifdef DEBUG_FORMATINFO
m_device->debug ("\t\t\tOffset=", m_formatPointerPos);
#endif
// write FormatPointer
memdev.setCache (m_packedStructs + m_formatPointerPos);
m_formatPointer [i].setDevice (&memdev);
if (!m_formatPointer [i].writeToDevice ()) return false;
memdev.setCache (NULL);
m_formatPointerPos += FormatPointer::s_size;
}
#ifdef DEBUG_FORMATINFO
m_device->debug ("\t\tWriting FormatProperty[], num=", m_numProperty);
#endif
for (int i = 0; i < m_numProperty; i++)
{
// write FormatProperty
if (m_type == ParaType)
{
FormatParaProperty *prop = &m_formatParaProperty [i];
m_formatPropertyPos -= (sizeof (Byte) + prop->getNumDataBytes ());
memdev.setCache (m_packedStructs + m_formatPropertyPos);
prop->setDevice (&memdev); // device was set to m_device to keep operator== happy in FormatInfoPage::add
if (!prop->writeToDevice ()) return false;
memdev.setCache (NULL);
}
else // if (m_type == CharType)
{
FormatCharProperty *prop = &m_formatCharProperty [i];
m_formatPropertyPos -= (sizeof (Byte) + prop->getNumDataBytes ());
memdev.setCache (m_packedStructs + m_formatPropertyPos);
prop->setDevice (&memdev); // device was set to m_device to keep operator== happy in FormatInfoPage::add
if (!prop->writeToDevice ()) return false;
memdev.setCache (NULL);
}
#ifdef DEBUG_FORMATINFO
m_device->debug ("\t\t\tWrote at Offset=", m_formatPropertyPos);
#endif
}
if (!FormatInfoPageGenerated::writeToArray ())
return false;
return true;
}
void *FormatInfoPage::begin (void)
{
CHECK_DEVICE;
#ifdef DEBUG_FORMATINFO
if (m_type == ParaType)
m_device->debug ("\nFormatInfoPage::begin (ParaType)\n");
else // if (m_type == CharType)
m_device->debug ("\nFormatInfoPage::begin (CharType)\n");
#endif
m_formatPointerUpto = 0;
m_nextCharByte = 0; // for consistency checking
m_lastPropertyOffset = -1;
if (!m_formatPointer)
{
m_formatPointer = new FormatPointer [1];
if (!m_formatPointer)
{
m_device->error (Error::OutOfMemory, "could not allocate memory for FormatPointer\n");
return NULL;
}
m_formatPointer->setDevice (m_device);
}
return this->next ();
}
void *FormatInfoPage::next (void)
{
void *ret;
#ifdef DEBUG_FORMATINFO
if (m_type == ParaType)
m_device->debug ("\tPara FormatPointer #", m_formatPointerUpto);
else // if (m_type == CharType)
m_device->debug ("\tChar FormatPointer #", m_formatPointerUpto);
#endif
//
// read Format Pointer
//
// check Format Pointer allocated
if (!m_formatPointer)
{
m_device->error (Error::InternalError, "formatPointer not initialised - call FormatInfoPage::begin() before next()\n");
return NULL;
}
// read next Format Pointer (fixed length)
m_device->setCache (m_packedStructs + m_formatPointerUpto * FormatPointer::s_size);
if (!m_formatPointer->readFromDevice ()) return NULL;
m_device->setCache (NULL);
DWord formatPointerAfterEndCharByte = m_formatPointer->getAfterEndCharByte ();
// check that it continues on from the last
if (formatPointerAfterEndCharByte <= m_nextCharByte)
m_device->error (Error::Warn, "FormatPointer afterEndCharByte does not go forward\n");
m_nextCharByte = formatPointerAfterEndCharByte;
// check whether it is the last one (EOF-wise)
if (formatPointerAfterEndCharByte >= m_header->getNumCharBytes ())
{
#ifdef DEBUG_FORMATINFO
m_device->debug ("\t\tThis is the last FormatPointer!\n");
#endif
// past EOF?
if (formatPointerAfterEndCharByte > m_header->getNumCharBytes ())
{
m_device->error (Error::Warn, "FormatPointer ends after EOF, forcing it to end at EOF\n");
m_formatPointer->setAfterEndCharByte (m_header->getNumCharBytes ());
m_nextCharByte = m_header->getNumCharBytes ();
}
// but there are still more FormatPointers left?
if (m_formatPointerUpto != m_numFormatPointers - 1)
{
m_device->error (Error::Warn, "FormatPointer ends at EOF but is not the last, forcing it to be the last\n");
m_formatPointerUpto = m_numFormatPointers - 1; // m_formatPointerUpto will get incremented at the end of this function
}
}
//
// read in corresponding Format Property
//
int currentPropertyOffset = m_formatPointer->getFormatPropertyOffset ();
bool up2date = (currentPropertyOffset == m_lastPropertyOffset);
if (!up2date) m_device->setCache (m_packedStructs + currentPropertyOffset);
if (m_type == CharType)
{
if (!up2date)
{
// reset to defaults
delete [] m_formatCharProperty;
m_formatCharProperty = new FormatCharProperty [1];
if (!m_formatCharProperty)
{
m_device->error (Error::OutOfMemory, "could not allocate memory for FormatCharProperty\n");
m_device->setCache (NULL);
return NULL;
}
m_formatCharProperty->setDevice (m_device);
m_formatCharProperty->setFontTable (m_fontTable);
if (!m_formatCharProperty->updateFont ())
{
m_device->setCache (NULL);
return NULL;
}
// corresponding charProperty structure exists?
if (currentPropertyOffset != 0xFFFF)
{
if (!m_formatCharProperty->readFromDevice ())
{
m_device->setCache (NULL);
return NULL;
}
}
}
assert (m_formatCharProperty);
m_formatCharProperty->setAfterEndCharByte (m_formatPointer->getAfterEndCharByte ());
ret = m_formatCharProperty;
}
else // if (m_type == ParaType)
{
if (!up2date)
{
// reset to defaults
delete [] m_formatParaProperty;
m_formatParaProperty = new FormatParaProperty [1];
if (!m_formatParaProperty)
{
m_device->error (Error::OutOfMemory, "could not allocate memory for FormatParaProperty\n");
m_device->setCache (NULL);
return NULL;
}
m_formatParaProperty->setDevice (m_device);
m_formatParaProperty->setMargins (m_leftMargin, m_rightMargin);
// corresponding paraProperty structure exists?
if (currentPropertyOffset != 0xFFFF)
{
if (!m_formatParaProperty->readFromDevice ())
{
m_device->setCache (NULL);
return NULL;
}
}
}
assert (m_formatParaProperty);
m_formatParaProperty->setAfterEndCharByte (m_formatPointer->getAfterEndCharByte ());
ret = m_formatParaProperty;
}
if (!up2date) m_device->setCache (NULL);
m_lastPropertyOffset = currentPropertyOffset;
m_formatPointerUpto++;
assert (m_formatPointer);
return ret;
}
bool FormatInfoPage::end (void) const
{
assert (m_formatPointerUpto <= FormatInfoPageGenerated::m_numFormatPointers);
return m_formatPointerUpto >= FormatInfoPageGenerated::m_numFormatPointers;
}
bool FormatInfoPage::add (const void *property)
{
CHECK_DEVICE;
// MaxElements is true for FormatPointers since you can't have partial FormatPointers
// This is also true for FormatProperties because m_numFormatPointer >= m_numProperty
// so MaxElements is also the upper limit on the number of properties
const int MaxElements = 123 / FormatPointer::s_size;
#ifdef DEBUG_FORMATINFO
if (m_type == ParaType)
m_device->debug (">>>> FormatInfoPage::add (ParaType) <<<<\n");
else // if (m_type == CharType)
m_device->debug (">>>> FormatInfoPage::add (CharType) <<<<\n");
Dump (formatPointerPos);
Dump (formatPropertyPos);
#endif
//
// Allocated memory for FormatPointers yet?
//
if (!m_formatPointer)
{
#ifdef DEBUG_FORMATINFO
m_device->debug ("\tFIRST CALL! Allocating memory for FormatPointer[] and FormatProperty[]\n");
#endif
// allocate memory for FormatPointers
m_formatPointer = new FormatPointer [MaxElements + 1]; // lazy memory allocation (+1 in case we can merge the last one)
if (!m_formatPointer)
ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for formatPointer[]\n");
// don't need to use m_formatPointerUpto here
FormatInfoPageGenerated::m_numFormatPointers = 0;
// ok, better allocate memory for relevant FormatProperties
if (m_type == ParaType)
{
assert (!m_formatParaProperty);
m_formatParaProperty = new FormatParaProperty [MaxElements + 1]; // lazy memory allocation (+1 for default prop)
m_formatParaProperty [MaxElements].setDevice (m_device); // we will be == this default which has to writeToArray which NeedsDevice
if (!m_formatParaProperty)
ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for formatParaProperty[]\n");
}
else // if (m_type == CharType)
{
assert (!m_formatCharProperty);
m_formatCharProperty = new FormatCharProperty [MaxElements + 1]; // lazy memory allocation (+1 for default prop)
m_formatCharProperty [MaxElements].setDevice (m_device); // we will be == this default which has to writeToArray which NeedsDevice
if (!m_formatCharProperty)
ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for formatCharProperty[]\n");
}
m_numProperty = 0;
}
//
// Setup pointers
//
FormatParaProperty inpp;
FormatCharProperty incp;
if (m_type == ParaType)
{
#ifdef DEBUG_FORMATINFO
m_device->debug ("\tTrying to add ParaProperty, #numDataBytes=", ((FormatParaProperty *) property)->getNumDataBytes ());
#endif
inpp = *((FormatParaProperty *) property);
inpp.setDevice (m_device);
inpp.setAfterEndCharByte (m_device->tellInternal () - 128);
inpp.setMargins (m_leftMargin, m_rightMargin);
if (!inpp.updateIndents ()) return false;
}
else // if (m_type == CharType)
{
#ifdef DEBUG_FORMATINFO
m_device->debug ("\tTrying to add CharProperty, #numDataBytes=", ((FormatCharProperty *) property)->getNumDataBytes ());
#endif
incp = *((FormatCharProperty *) property);
incp.setDevice (m_device);
incp.setAfterEndCharByte (m_device->tellInternal () - 128);
incp.setFontTable (m_fontTable);
if (!incp.updateFontCode ()) return false;
}
//
// Attempt to add Property to current page:
//
// Since MS programmers tried so hard to save space, we will do the same :)
// This results in having to store variable-length structures and the use of other nasty
// tricks such as having multiple FormatPointers pointing to the same FormatProperty.
// Details follow in code :)
//
// In Write, character formatting blocks can extend across paragraphs
// In LibMSWrite they don't (for convenience?) so here we merge FormatPointers that have been split up
// This applies _only_ to _character formatting_ and is not MS' fault but rather the design of LibMSWrite.
// It should _not_ be done to paragraph formatting because I don't think the user would appreciate
// several paragraphs being merged into one multi-line paragraph (changing paragraph properties would
// become rather difficult...)
bool checkedLastFormatPointer = false;
if (m_type == CharType && m_numProperty > 0 /* && m_numFormatPointers > 0 */)
{
#ifdef DEBUG_FORMATINFO
m_device->debug ("\tIs it the same property as last? ");
#endif
// simply extend last FormatPointer
FormatCharProperty *lastProp = (FormatCharProperty *) m_formatPointer [m_numFormatPointers - 1].getFormatProperty ();
if (incp == *lastProp)
{
#ifdef DEBUG_FORMATINFO
m_device->debug ("Yes, extending FormatPointer #", m_numFormatPointers - 1);
m_device->debug ("\t\tFrom ", m_formatPointer [m_numFormatPointers - 1].getAfterEndCharByte ());
#endif
m_formatPointer [m_numFormatPointers - 1].setAfterEndCharByte (incp.getAfterEndCharByte ());
#ifdef DEBUG_FORMATINFO
m_device->debug ("\t\tTo: ", incp.getAfterEndCharByte ());
#endif
return true;
}
checkedLastFormatPointer = true;
#ifdef DEBUG_FORMATINFO
m_device->debug ("No\n");
#endif
}
#ifdef DEBUG_FORMATINFO
m_device->debug ("\tSame as earlier FormatPointer? ");
#endif
// points to same property as an earlier formatPointer?
for (int i = 0; i < m_numFormatPointers - (checkedLastFormatPointer ? 1 : 0); i++)
{
#ifdef DEBUG_FORMATINFO
m_device->debug (i);
m_device->debug ("? ");
#endif
if (m_type == ParaType)
{
FormatParaProperty *prop = (FormatParaProperty *) m_formatPointer [i].getFormatProperty ();
if (inpp == *prop)
{
// try to add new formatPointer
if (m_formatPointerPos + FormatPointer::s_size > m_formatPropertyPos)
{
#ifdef DEBUG_FORMATINFO
m_device->debug ("Yes, but out of room on this page\n");
#endif
return false; // not enough room
}
#ifdef DEBUG_FORMATINFO
m_device->debug ("Yes, same property as ", i);
#endif
m_formatPointer [m_numFormatPointers].setAfterEndCharByte (inpp.getAfterEndCharByte ());
m_formatPointer [m_numFormatPointers].setFormatPropertyOffset (m_formatPointer [i].getFormatPropertyOffset ());
m_formatPointer [m_numFormatPointers].setFormatProperty (prop);
m_formatPointerPos += FormatPointer::s_size;
m_numFormatPointers++;
return true;
}
}
else // if (m_type == CharType)
{
FormatCharProperty *prop = (FormatCharProperty *) m_formatPointer [i].getFormatProperty ();
if (incp == *prop)
{
// try to add new formatPointer
if (m_formatPointerPos + FormatPointer::s_size > m_formatPropertyPos)
{
#ifdef DEBUG_FORMATINFO
m_device->debug ("Yes, but out of room on this page\n");
#endif
return false; // not enough room
}
#ifdef DEBUG_FORMATINFO
m_device->debug ("Yes, same property as ", i);
#endif
m_formatPointer [m_numFormatPointers].setAfterEndCharByte (incp.getAfterEndCharByte ());
m_formatPointer [m_numFormatPointers].setFormatPropertyOffset (m_formatPointer [i].getFormatPropertyOffset ());
m_formatPointer [m_numFormatPointers].setFormatProperty (prop);
m_formatPointerPos += FormatPointer::s_size;
m_numFormatPointers++;
return true;
}
}
}
#ifdef DEBUG_FORMATINFO
m_device->debug ("No, outputting full FormatPointer & Property\n");
#endif
// ok we can't compress, must output a full FormatPointer & FormatProperty
if (m_type == ParaType)
{
int nextPropertyPos = m_formatPropertyPos;
if (inpp.getNumDataBytes ())
nextPropertyPos -= (sizeof (Byte) + inpp.getNumDataBytes ());
if (m_formatPointerPos + FormatPointer::s_size > nextPropertyPos)
{
#ifdef DEBUG_FORMATINFO
m_device->debug ("\tOut of room on this page!\n");
#endif
return false; // not enough room
}
m_formatPropertyPos = nextPropertyPos;
if (inpp.getNumDataBytes ())
m_formatParaProperty [m_numProperty] = inpp;
m_formatPointer [m_numFormatPointers].setAfterEndCharByte (inpp.getAfterEndCharByte ());
if (inpp.getNumDataBytes ())
{
m_formatPointer [m_numFormatPointers].setFormatPropertyOffset (m_formatPropertyPos);
m_formatPointer [m_numFormatPointers].setFormatProperty (&m_formatParaProperty [m_numProperty]);
}
else
{
m_formatPointer [m_numFormatPointers].setFormatPropertyOffset (0xFFFF/*nowhere*/);
m_formatPointer [m_numFormatPointers].setFormatProperty (&m_formatParaProperty [MaxElements]/*default*/);
}
m_formatPointerPos += FormatPointer::s_size;
if (inpp.getNumDataBytes ()) m_numProperty++;
m_numFormatPointers++;
return true;
}
else // if (m_type == CharType)
{
int nextPropertyPos = m_formatPropertyPos;
if (incp.getNumDataBytes ())
nextPropertyPos -= (sizeof (Byte) + incp.getNumDataBytes ());
if (m_formatPointerPos + FormatPointer::s_size > nextPropertyPos)
{
#ifdef DEBUG_FORMATINFO
m_device->debug ("\tOut of room on this page!\n");
#endif
return false; // not enough room
}
m_formatPropertyPos = nextPropertyPos;
if (incp.getNumDataBytes ())
m_formatCharProperty [m_numProperty] = incp;
m_formatPointer [m_numFormatPointers].setAfterEndCharByte (incp.getAfterEndCharByte ());
if (incp.getNumDataBytes ())
{
m_formatPointer [m_numFormatPointers].setFormatPropertyOffset (m_formatPropertyPos);
m_formatPointer [m_numFormatPointers].setFormatProperty (&m_formatCharProperty [m_numProperty]);
}
else
{
m_formatPointer [m_numFormatPointers].setFormatPropertyOffset (0xFFFF/*nowhere*/);
m_formatPointer [m_numFormatPointers].setFormatProperty (&m_formatCharProperty [MaxElements]/*default*/);
}
m_formatPointerPos += FormatPointer::s_size;
if (incp.getNumDataBytes ()) m_numProperty++;
m_numFormatPointers++;
return true;
}
}
BMP_BitmapFileHeader::BMP_BitmapFileHeader ()
{
}
BMP_BitmapFileHeader::~BMP_BitmapFileHeader ()
{
}
BMP_BitmapFileHeader &BMP_BitmapFileHeader::operator= (const BMP_BitmapFileHeader &rhs)
{
if (this == &rhs)
return *this;
BMP_BitmapFileHeaderGenerated::operator= (rhs);
return *this;
}
bool BMP_BitmapFileHeader::readFromDevice (void)
{
CHECK_DEVICE;
#ifdef DEBUG_IMAGE
m_device->debug ("\n<<<< BMP_BitmapFileHeader::readFromDevice >>>>\n");
#endif
if (!BMP_BitmapFileHeaderGenerated::readFromDevice ())
return false;
#ifdef DEBUG_IMAGE
Dump (magic);
Dump (totalBytes);
Dump (zero [0]);
Dump (zero [1]);
Dump (actualImageOffset);
#endif
return true;
}
bool BMP_BitmapFileHeader::writeToDevice (void)
{
CHECK_DEVICE;
#ifdef DEBUG_IMAGE
m_device->debug ("\n<<<< BMP_BitmapFileHeader::writeToDevice >>>>\n");
#endif
if (!BMP_BitmapFileHeaderGenerated::writeToDevice ())
return false;
return true;
}
BMP_BitmapInfoHeader::BMP_BitmapInfoHeader ()
{
}
BMP_BitmapInfoHeader::~BMP_BitmapInfoHeader ()
{
}
BMP_BitmapInfoHeader &BMP_BitmapInfoHeader::operator= (const BMP_BitmapInfoHeader &rhs)
{
if (this == &rhs)
return *this;
BMP_BitmapInfoHeaderGenerated::operator= (rhs);
return *this;
}
bool BMP_BitmapInfoHeader::readFromDevice (void)
{
CHECK_DEVICE;
#ifdef DEBUG_IMAGE
m_device->debug ("\n<<<< BMP_BitmapInfoHeader::readFromDevice >>>>\n");
#endif
if (!BMP_BitmapInfoHeaderGenerated::readFromDevice ())
return false;
#ifdef DEBUG_IMAGE
Dump (numHeaderBytes);
Dump (width);
Dump (height);
Dump (numPlanes);
Dump (bitsPerPixel);
Dump (compression);
Dump (sizeImage);
Dump (xPixelsPerMeter);
Dump (yPixelsPerMeter);
Dump (coloursUsed);
Dump (coloursImportant);
#endif
return true;
}
bool BMP_BitmapInfoHeader::writeToDevice (void)
{
CHECK_DEVICE;
#ifdef DEBUG_IMAGE
m_device->debug ("\n<<<< BMP_BitmapInfoHeader::writeToDevice >>>>\n");
#endif
if (!BMP_BitmapInfoHeaderGenerated::writeToDevice ())
return false;
return true;
}
BMP_BitmapColourIndex::BMP_BitmapColourIndex ()
{
}
BMP_BitmapColourIndex::~BMP_BitmapColourIndex ()
{
}
BMP_BitmapColourIndex &BMP_BitmapColourIndex::operator= (const BMP_BitmapColourIndex &rhs)
{
if (this == &rhs)
return *this;
BMP_BitmapColourIndexGenerated::operator= (rhs);
return *this;
}
BitmapHeader::BitmapHeader ()
{
}
BitmapHeader::~BitmapHeader ()
{
}
BitmapHeader &BitmapHeader::operator= (const BitmapHeader &rhs)
{
if (this == &rhs)
return *this;
BitmapHeaderGenerated::operator= (rhs);
return *this;
}
bool BitmapHeader::readFromDevice (void)
{
CHECK_DEVICE;
#ifdef DEBUG_IMAGE
m_device->debug ("\n<<<< BitmapHeader::readFromDevice >>>>\n");
#endif
if (!BitmapHeaderGenerated::readFromDevice ())
return false;
#ifdef DEBUG_IMAGE
Dump (zero);
Dump (width);
Dump (height);
Dump (widthBytes);
Dump (numPlanes);
Dump (bitsPerPixel);
Dump (zero2);
#endif
return true;
}
bool BitmapHeader::writeToDevice (void)
{
CHECK_DEVICE;
#ifdef DEBUG_IMAGE
m_device->debug ("\n>>>> BitmapHeader::writeToDevice <<<<\n");
#endif
if (!BitmapHeaderGenerated::writeToDevice ())
return false;
return true;
}
WMFHeader::WMFHeader ()
{
}
WMFHeader::~WMFHeader ()
{
}
WMFHeader &WMFHeader::operator= (const WMFHeader &rhs)
{
if (this == &rhs)
return *this;
WMFHeaderGenerated::operator= (rhs);
return *this;
}
bool WMFHeader::readFromDevice (void)
{
CHECK_DEVICE;
#ifdef DEBUG_IMAGE
m_device->debug ("\n<<<< WMFHeader::readFromDevice >>>>\n");
#endif
if (!WMFHeaderGenerated::readFromDevice ())
return false;
#ifdef DEBUG_IMAGE
Dump (fieldType);
Dump (headerSize);
Dump (winVersion);
Dump (fileSize);
Dump (numObjects);
Dump (maxRecordSize);
Dump (zero);
#endif
return true;
}
bool WMFHeader::writeToDevice (void)
{
CHECK_DEVICE;
#ifdef DEBUG_IMAGE
m_device->debug ("\n>>>> WMFHeader::writeToDevice <<<<\n");
#endif
#ifdef DEBUG_IMAGE
Dump (fieldType);
Dump (headerSize);
Dump (winVersion);
Dump (fileSize);
Dump (numObjects);
Dump (maxRecordSize);
Dump (zero);
#endif
if (!WMFHeaderGenerated::writeToDevice ())
return false;
return true;
}
} // namespace MSWrite {
// end of structures_private.cpp