Exemplo n.º 1
0
	bool InternalGenerator::writeParaInfoBegin (const FormatParaProperty * /*paraProperty*/,
																const OLE *ole,
																const Image *image)
	{
	#ifdef DEBUG_INTERNALGENERATOR
		m_device->debug ("!!!! InternalGenerator: writeParaInfoBegin\n");
	#endif

		if (ole)
		{
			m_ole = new OLE;
			if (!m_ole)
				ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for OLE\n");
			*m_ole = *ole;

			m_ole->setDevice (m_device);
			m_ole->setExternalObjectSize (ole->getExternalObjectSize ());
		}

		if (image)
		{
			m_image = new Image;
			if (!m_image)
				ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for image\n");
			*m_image = *image;

			m_image->setDevice (m_device);
			m_image->setExternalImageSize (image->getExternalImageSize ());
		}

		return true;
	}
Exemplo n.º 2
0
	bool FormatParaProperty::writeToDevice (void)
	{
	CHECK_DEVICE;

	#ifdef CHECK_INTERNAL
		if (m_leftMargin == 0xFFFF && m_rightMargin == 0xFFFF)
			ErrorAndQuit (Error::InternalError, "FormatParaProperty::writeToDevice call not setup\n");
	#endif

	#ifdef DEBUG_PARA
		m_device->debug ("\nFormatParaProperty::writeToDevice, #bytes=", getNumDataBytes ());
	#endif

		if (m_addedTooManyTabs)
			ErrorAndQuit (Error::InternalError, "cannot have more than 14 tabulators; shouldn't even have more than 12\n");

		if (m_numTabulators > 12)
			m_device->error (Error::Warn, "should not have more than 12 tabulators since you can only access 12 tabs via the GUI\n");

		// --- indents adjusted in updateIndents() called by FormatInfoPage::add() ---

		if (!FormatParaPropertyGenerated::writeToDevice ())
			return false;

		return true;
	}
Exemplo n.º 3
0
	bool Font::writeToDevice (void)
	{
	CHECK_DEVICE;

		// should I be on the next page? (TODO: this check is stupid if it's the last font)
		Word offset = m_device->tellInternal () % 128;	// from start of current page
		if (offset + sizeof (m_numDataBytes) + m_numDataBytes + sizeof (m_numDataBytes)/*for next Font's 0xFFFF*/ > 128)
		{
			// signal that font is on next page
			Byte scratch [2] = {0xFF, 0xFF};
			if (!m_device->writeInternal (scratch, 2))
				ErrorAndQuit (Error::FileError, "could not write Font 0xFFFF\n");
			return false;	// Device::m_error will be clear so this is ok
		}

		// --- we don't have to write 0 to indicate last font (since we write the right number of elements) ---

		// write numDataBytes, family
		if (!FontGenerated::writeToDevice ())
			return false;

		if (!m_device->writeInternal (m_name, m_numDataBytes - sizeof (m_family)))
			ErrorAndQuit (Error::FileError, "could not write fontName\n");

		return true;
	}
Exemplo n.º 4
0
	bool Font::readFromDevice (void)
	{
	CHECK_DEVICE;

		if (!FontGenerated::readFromDevice ())
			return false;

	#ifdef DEBUG_FONT
		Dump (numDataBytes);
		Dump (family);
	#endif

		// is this font on the next page?
		if (m_numDataBytes == 0xFFFF)
			return false;	// Device::m_error will be clear so this is ok

		// is this the last font _ever_?
		if (m_numDataBytes == 0)
			return false;	// Device::m_error will be clear so this is ok

		// Font structure size can't exceed a page anyway
		if (m_numDataBytes > 128 - sizeof (m_numDataBytes))
			ErrorAndQuit (MSWrite::Error::InvalidFormat, "Font nameLen is too big\n");

		// calculate length of name
		int nameLen = m_numDataBytes - sizeof (m_family) - 1	/* NUL */;

		// we should really call this->setName()...
		m_name = new Byte [nameLen + 1];
		if (!m_name)
			ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for fontName\n");

		// read fontName
		if (!m_device->readInternal (m_name, nameLen + 1))
			ErrorAndQuit (Error::FileError, "could not read fontName\n");

		// check name is valid
		if (m_name [nameLen] != '\0')
			ErrorAndQuit (Error::InvalidFormat, "fontName not NUL-terminated\n");

	#ifdef DEBUG_FONT
		m_device->debug ("\tfontName=", (const char *) m_name);
	#endif
		return true;
	}
Exemplo n.º 5
0
	bool FormatCharProperty::updateFont (void)
	{
		Font *fontPtr = m_fontTable->getFont (getFontCode ());
		if (!fontPtr)
			ErrorAndQuit (Error::InvalidFormat, "fontCode out of range\n");

		m_font = *fontPtr;
		return true;
	}
Exemplo n.º 6
0
	bool OLE::readFromDevice (void)
	{
	CHECK_DEVICE;

	#ifdef DEBUG_OBJECT
		m_device->debug ("\n<<<< OLE::readFromDevice >>>>\n");
	#endif

		if (!OLEGenerated::readFromDevice ())
			return false;

	#ifdef DEBUG_OBJECT
		Dump (zero);

		switch (m_objectType)
		{
		case OLEType::Static:
			m_device->debug ("\tobjectType: 1 - static\n");
			break;
		case OLEType::Embedded:
			m_device->debug ("\tobjectType: 2 - embedded\n");
			break;
		case OLEType::Link:
			m_device->debug ("\tobjectType: 3 - link\n");
			break;
		}

		Dump (indent);
		Dump (width);
		Dump (height);
		Dump (zero2);
		Dump (numDataBytes);
		Dump (zero3);
		Dump (objectName);
		Dump (zero4);
		Dump (numHeaderBytes);
		Dump (zero5);
		Dump (widthScaledRel1000);
		Dump (heightScaledRel1000);
	#endif

		// OPT: TODO: this is dumb, we read it only to give it back to the parser who tells the generator to write it
		m_externalObject = new Byte [m_externalObjectSize = getNumDataBytes ()];
		if (!m_externalObject)
			ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for external OLE object\n");

		if (!m_device->readInternal (m_externalObject, m_externalObjectSize))
			return false;

		return true;
	}
Exemplo n.º 7
0
	bool FormatParaProperty::readFromDevice (void)
	{
	CHECK_DEVICE;

	#ifdef DEBUG_PARA
		m_device->debug ("\nFormatParaProperty::readFromDevice\n");
	#endif

	#ifdef CHECK_INTERNAL
		if (m_leftMargin == 0xFFFF && m_rightMargin == 0xFFFF)
			ErrorAndQuit (Error::InternalError, "FormatParaProperty::readFromDevice call not setup\n");
	#endif

		if (!FormatParaPropertyGenerated::readFromDevice ())
			return false;

		// Correct indentation in Header and Footer:
		//
		// For unknown reasons, Write adds the leftMargin to the leftIndent
		// and rightMargin to rightIndent in the Header and Footer only but
		// does not touch the leftIndentFirstLine
		//
		// TODO: what if it's an image in the header/footer?
		if (getIsNotNormalParagraph ())
		{
			// adjust leftIndent
			if (m_leftMargin < m_leftIndent)
				m_leftIndent -= m_leftMargin;
			else
				m_leftIndent = 0;

			// adjust rightIndent
			if (m_rightMargin < m_rightIndent)
				m_rightIndent -= m_rightMargin;
			else
				m_rightIndent = 0;
		}

		if (m_numDataBytes > 22)
			m_numTabulators = (m_numDataBytes - 22) / FormatParaPropertyTabulator::s_size;
		else
			m_numTabulators = 0;

		// for impexp
		if (getNumDataBytes () != m_numDataBytes && !m_numTabulators)
			m_device->error (Error::Warn, "m_numDataBytes != getNumDataBytes ()\n");
		UseThisMuch::signalHaveSetData (false, m_numDataBytes * 8);

		return true;
	}
Exemplo n.º 8
0
	bool InternalGenerator::writeDocumentBegin (const Word, const PageLayout *pageLayout)
	{
		if (!m_device)
		{
			fprintf (stderr, "INTERNAL ERROR: InternalGenerator::writeDocumentBegin() called without a device\n");
			return false;	// cannot use ErrorAndQuit() because that calls m_device->error()
		}

		m_header = new Header;
		if (!m_header)
			ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for header\n");
		m_header->setDevice (m_device);

		m_pageLayout = new PageLayout;
		if (!m_pageLayout)
			ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for pageLayout\n");
		m_pageLayout->setDevice (m_device);

		m_sectionTable = new SectionTable;
		if (!m_sectionTable)
			ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for sectionTable\n");
		m_sectionTable->setDevice (m_device);

		m_pageTable = new PageTable;
		if (!m_pageTable)
			ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for pageTable\n");
		m_pageTable->setDevice (m_device);

		m_fontTable = new FontTable;
		if (!m_fontTable)
			ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for fontTable\n");
		m_fontTable->setDevice (m_device);

		m_paragraphInfo = new FormatInfo;
		if (!m_paragraphInfo)
			ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for paragraphInfo\n");
		m_paragraphInfo->setType (ParaType);
		m_paragraphInfo->setDevice (m_device);

		m_characterInfo = new FormatInfo;
		if (!m_characterInfo)
			ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for characterInfo\n");
		m_characterInfo->setType (CharType);
		m_characterInfo->setDevice (m_device);
		
		*m_pageLayout = *pageLayout;
		
		// get ready to output text
		if (!m_device->seekInternal (1 * 128, SEEK_SET)) return false;

		return true;
	}
Exemplo n.º 9
0
	bool InternalGenerator::writeBinary (const Byte *buffer, const DWord length)
	{
		if (m_ole)
		{
			if (!m_ole->setExternalObject (buffer, length))
				return false;
		}
		else if (m_image)
		{
			if (!m_image->setExternalImage (buffer, length))
				return false;
		}
		else
			ErrorAndQuit (Error::InternalError, "attempt to write unknown type of binary data\n");

		return true;
	}
Exemplo n.º 10
0
	bool FormatCharProperty::readFromDevice (void)
	{
	CHECK_DEVICE;

	#ifdef DEBUG_CHAR
		m_device->debug ("\nFormatCharProperty::readFromDevice\n");
	#endif

		if (!FormatCharPropertyGenerated::readFromDevice ())
			return false;

		if (!m_fontTable)
			ErrorAndQuit (Error::InternalError, "m_fontTable not setup for FormatCharProperty::readFromDevice\n");

		// note: the converse is done in FormatInfoPage::add(), not FormatCharProperty::writeToDevice
		if (!updateFont ()) return false;

		return true;
	}
Exemplo n.º 11
0
	bool Image::writeToDevice (void)
	{
	CHECK_DEVICE;

	#ifdef DEBUG_IMAGE
		m_device->debug ("\n>>>> Image::writeToDevice <<<<\n");
	#endif

	#ifdef DEBUG_IMAGE
		Dump (mappingMode);
		//Dump (MFP_width);	// will change below
		//Dump (MFP_height);
		Dump (MFP_unknown);

		Dump (indent);
		//Dump (width);
		//Dump (height);
		Dump (zero);

		Dump (numHeaderBytes);
		//Dump (numDataBytes);
		//Dump (horizontalScalingRel1000);
		//Dump (verticalScalingRel1000);
	#endif

		// sanity checking
		if (!m_externalImage || m_externalImageSize <= 0 ||
				m_originalWidth <= 0 || m_originalHeight <= 0 ||
				m_displayedWidth <= 0 || m_displayedHeight <= 0)
		{
			ErrorAndQuit (Error::InternalError, "uninitialised or invalid Image\n");
		}

		//
		// write data
		//
		//
		if (getIsWMF ())
		{
			// Header check
			WMFHeader wmfHeader;
			m_device->setCache (m_externalImage);
				wmfHeader.setDevice (m_device);
				if (!wmfHeader.readFromDevice ()) return false;

				// TODO: fix this incorrect check (see wmf.cpp)
				//if (wmfHeader.getFileSize () * sizeof (Word) != m_externalImageSize)
				//	m_device->error (Error::Warn, "wmfHeader.fileSize != externalImageSize\n");
			m_device->setCache (NULL);


			//
			// set image dimensions
			//

			// entire BitmapHeader is unused with WMFs
			m_bmh->setWidth (0);
			m_bmh->setHeight (0);
			m_bmh->setWidthBytes (0);
			m_bmh->setNumPlanes (0);
			m_bmh->setBitsPerPixel (0);

			m_MFP_width = Word (Twip2Milli (m_originalWidth * 0.75) * 100.0);
			m_MFP_height = Word (Twip2Milli (m_originalHeight * 0.75) * 100.0);

			m_width = Word (m_displayedWidth);
			m_height = Word (m_displayedHeight);

			// not used by WMFs
			m_horizontalScalingRel1000 = m_verticalScalingRel1000 = 1000;


			// write header
			setNumDataBytes (m_externalImageSize);
			if (!ImageGenerated::writeToDevice ())
				return false;

			// external=internal with WMF (i.e. we really do write a WMF)
			if (!m_device->writeInternal (m_externalImage, m_externalImageSize)) return false;
		}
		else	//	if (getIsBMP ())
		{
			m_device->setCache (m_externalImage);

			BMP_BitmapFileHeader fileHeader;
			fileHeader.setDevice (m_device);
			if (!fileHeader.readFromDevice ()) return false;


			/*Word colorTableSize = (1 << m_bmh->getNumPlanes ()) * BMP_BitmapColorIndex::s_size;

			// fileHeader
			DWord fileSize = BMP_BitmapFileHeader::s_size + BMP_BitmapInfoHeader::s_size
												+ colorTableSize
												+ (m_bmh->getHeight ()
													* getBytesPerScanLine (m_bmh->getWidth (), m_bmh->getBitsPerPixel (), 4));

			fileHeader.setTotalBytes (fileSize);
			fileHeader.setActualImageOffset (BMP_BitmapFileHeader::s_size + BMP_BitmapInfoHeader::s_size
														+ colorTableSize);*/

			// infoHeader
			BMP_BitmapInfoHeader infoHeader;
			infoHeader.setDevice (m_device);
			if (!infoHeader.readFromDevice ()) return false;

			// write out each scanline
			// to .WRI (padded to 2) vs input BMP (padded to 4
			Word scanLineWRILength = getBytesPerScanLine (infoHeader.getWidth (), infoHeader.getBitsPerPixel (), 2);
			Word scanLineBMPLength = getBytesPerScanLine (infoHeader.getWidth (), infoHeader.getBitsPerPixel (), 4);

			if (infoHeader.getWidth () <= 0 || infoHeader.getHeight () <= 0)
				ErrorAndQuit (Error::InvalidFormat, "infoHeader invalid dimensions\n");

			// did the user lie about the dimensions of the BMP?
			if (infoHeader.getWidth () != Word (Twip2Point (m_originalWidth)))
				m_device->error (Error::Warn, "infoHeader width != m_originalWidth\n");
			if (infoHeader.getHeight () != Word (Twip2Point (m_originalHeight)))
				m_device->error (Error::Warn, "infoHeader.height != m_originalHeight\n");

			m_bmh->setWidth (infoHeader.getWidth ());
			m_bmh->setHeight (infoHeader.getHeight ());
			m_bmh->setWidthBytes (scanLineWRILength);
			if (infoHeader.getNumPlanes () != 1)
				ErrorAndQuit (Error::InvalidFormat, "infoHeader.getNumPlanes() != 1\n");
			m_bmh->setNumPlanes (infoHeader.getNumPlanes ());
			m_bmh->setBitsPerPixel (infoHeader.getBitsPerPixel ());
			if (infoHeader.getCompression () != 0)	// BI_RGB (uncompressed)
				ErrorAndQuit (Error::Unsupported, "compressed bitmaps unsupported\n");
			//infoHeader.setSizeImage (0);		// lazy
			//infoHeader.setXPixelsPerMeter (0), infoHeader.setYPixelsPerMeter (0);
			infoHeader.setColorsUsed (1 << infoHeader.getBitsPerPixel ());	// make life easier
			//infoHeader.setColorsImportant (infoHeader.getColorsUsed ());

			if (infoHeader.getColorsUsed () != 2)
				ErrorAndQuit (Error::Unsupported, "can't save color BMPs, use WMFs for that purpose\n");

			// colorTable
			BMP_BitmapColorIndex *colorIndex = new BMP_BitmapColorIndex [infoHeader.getColorsUsed ()];
			if (!colorIndex)
				ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for colorIndex[]\n");
			colorIndex [0].setDevice (m_device);
			if (!colorIndex [0].readFromDevice ()) return false;
			if (colorIndex [0].getRed () != 0 || colorIndex [0].getGreen () != 0 || colorIndex [0].getBlue () != 0)
				m_device->error (Error::Warn, "black not black\n");
			colorIndex [1].setDevice (m_device);
			if (!colorIndex [1].readFromDevice ()) return false;
			if (colorIndex [1].getRed () != 0xFF || colorIndex [1].getGreen () != 0xFF || colorIndex [1].getBlue () != 0xFF)
				m_device->error (Error::Warn, "white not white\n");

			// finish reading from m_externalImage
			m_device->setCache (NULL);


			//
			// set image dimensions
			//

			m_MFP_width = Word (Twip2Point (m_originalWidth) * 2.64);
			m_MFP_height = Word (Twip2Point (m_originalHeight) * 2.64);

			// BMPs don't use
			m_width = 0, m_height = 0;

			m_horizontalScalingRel1000 = Word (m_displayedWidth * 1.38889 * 1000.0 / m_originalWidth);
			m_verticalScalingRel1000 = Word (m_displayedHeight * 1.38889 * 1000.0 / m_originalHeight);


			// write header
			setNumDataBytes (infoHeader.getHeight () * scanLineWRILength);
			if (!ImageGenerated::writeToDevice ())
				return false;

			// sanity check
			DWord expectedSize = DWord (infoHeader.getHeight ()) * DWord (scanLineBMPLength);
			DWord imageSize = m_externalImageSize - fileHeader.getActualImageOffset ();
			if (expectedSize != imageSize)
			{
				if (expectedSize > imageSize)
				{
					// better quit instead of reading past end of m_externalImage[]
					ErrorAndQuit (Error::InvalidFormat, "infoHeader.getHeight () * scanLineBMPLength > imageSize\n");
				}
				else
					m_device->error (Error::Warn, "infoHeader.getHeight () * scanLineBMPLength != imageSize\n");
			}

			// the DIB is upside-down...
			Byte *bmpData = m_externalImage + fileHeader.getActualImageOffset () + (infoHeader.getHeight () - 1) * scanLineBMPLength;
			for (int i = (int) infoHeader.getHeight () - 1; i >= 0; i--)
			{
				// write bitmap scanline (padded to 2)
				//if (!m_device->writeInternal (m_externalImage + fileHeader.getActualImageOffset () + i * scanLineBMPLength, scanLineWRILength))
				if (!m_device->writeInternal (bmpData, scanLineWRILength))
					return false;

				bmpData -= scanLineBMPLength;
			}

			delete [] colorIndex;
		}

		return true;
	}
Exemplo n.º 12
0
	bool PageLayout::readFromDevice (void)
	{
	CHECK_DEVICE;

	#ifdef DEBUG_PAGELAYOUT
		m_device->debug ("\n<<<< PageLayout::readFromDevice >>>>\n");
	#endif

		int numPageLayoutPages = m_header->getNumPageSectionProperty ();

	#ifdef DEBUG_PAGELAYOUT
		m_device->debug ("num pageLayoutPages: ", numPageLayoutPages);
	#endif

		// no PageLayout
		if (numPageLayoutPages == 0)
			return true;
		else if (numPageLayoutPages > 1)
			ErrorAndQuit (Error::InvalidFormat, "invalid #pageLayoutPages\n");

		// seek to the PageLayout in the file
		if (!m_device->seekInternal (m_header->getPageSectionProperty () * 128, SEEK_SET))
			ErrorAndQuit (Error::FileError, "could not seek to pageLayout\n");

		if (!PageLayoutGenerated::readFromDevice ())
			return false;

	#ifdef DEBUG_PAGELAYOUT
		Dump (magic102);
		Dump (magic512);

		Dump (pageHeight);
		Dump (pageWidth);
		Dump (pageNumberStart);
		Dump (topMargin);
		Dump (textHeight);
		Dump (leftMargin);
		Dump (textWidth);

		Dump (magic256);

		Dump (headerFromTop);
		Dump (footerFromTop);

		Dump (magic720);
		Dump (zero);
		Dump (magic1080);
		Dump (unknown);
		Dump (zero2);
	#endif

		#define UpdateModifiedCount(variable) if (m_##variable != variable##Default) m_numModified++
		UpdateModifiedCount (magic102);
		UpdateModifiedCount (magic512);
		UpdateModifiedCount (pageHeight);
		UpdateModifiedCount (pageWidth);
		UpdateModifiedCount (pageNumberStart);
		UpdateModifiedCount (topMargin);
		UpdateModifiedCount (textHeight);
		UpdateModifiedCount (leftMargin);
		UpdateModifiedCount (textWidth);
		UpdateModifiedCount (magic256);
		UpdateModifiedCount (headerFromTop);
		UpdateModifiedCount (footerFromTop);
		UpdateModifiedCount (magic720);
		UpdateModifiedCount (zero);
		UpdateModifiedCount (magic1080);
		//UpdateModifiedCount (unknown);	// no reliable default for unknown
		UpdateModifiedCount (zero2);
		#undef UpdateModifiedCount

		return true;
	}
Exemplo n.º 13
0
	bool Image::readFromDevice (void)
	{
	CHECK_DEVICE;

	#ifdef DEBUG_IMAGE
		m_device->debug ("\n<<<< Image::readFromDevice >>>>\n");
	#endif

		if (!ImageGenerated::readFromDevice ())
			return false;

	#ifdef DEBUG_IMAGE
		Dump (mappingMode);
		Dump (MFP_width);
		Dump (MFP_height);
		Dump (MFP_unknown);

		Dump (indent);
		Dump (width);
		Dump (height);
		Dump (zero);

		Dump (numHeaderBytes);
		Dump (numDataBytes);
		Dump (horizontalScalingRel1000);
		Dump (verticalScalingRel1000);
	#endif

		if (getIsWMF ())
		{
			//
			// get image dimensions
			//

			if (m_bmh->getWidth () || m_bmh->getHeight ())
				m_device->error (Error::Warn, "m_bmh structure should be 0 for WMFs\n");

			m_originalWidth = Milli2Twip (double (m_MFP_width) / 100.0) * 4.0/3.0;
			m_originalHeight = Milli2Twip (double (m_MFP_height) / 100.0) * 4.0/3.0;

			m_displayedWidth = double (m_width);
			m_displayedHeight = double (m_height);

			if (m_horizontalScalingRel1000 != 1000)
				m_device->error (Error::Warn, "horizontal scaling should not be set for WMFs\n");
			if (m_verticalScalingRel1000 != 1000)
				m_device->error (Error::Warn, "vertical scaling should not be set for WMFs\n");


			//
			// read image
			//

			m_externalImage = new Byte [m_externalImageSize = getNumDataBytes ()];
			if (!m_externalImage)
				ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for external WMF image\n");

			if (!m_device->readInternal (m_externalImage, m_externalImageSize))
				ErrorAndQuit (Error::FileError, "could not read internal WMF\n");

			// Header check
			WMFHeader wmfHeader;
			m_device->setCache (m_externalImage);
				wmfHeader.setDevice (m_device);
				if (!wmfHeader.readFromDevice ())
					return false;

				// TODO: fix this incorrect check (see wmf.cpp)
				//if (wmfHeader.getFileSize () * sizeof (Word) != m_numDataBytes)
				//	m_device->error (Error::Warn, "wmfHeader.fileSize != numDataBytes\n");
			m_device->setCache (NULL);
		}
		else	//	if (getIsBMP ())
		{
			//
			// get image dimensions
			//

			m_originalWidth = Point2Twip (DWord (m_bmh->getWidth ()));
			m_originalHeight = Point2Twip (DWord (m_bmh->getHeight ()));

			m_displayedWidth = m_originalWidth / 1.38889 * m_horizontalScalingRel1000 / 1000;
			m_displayedHeight = m_originalHeight / 1.38889 * m_verticalScalingRel1000 / 1000;

#define MSWrite_fabs(val) (((val)>=0)?(val):(-(val)))

			if (MSWrite_fabs (m_MFP_width / double (m_bmh->getWidth ()) - 2.64) > .3)
				m_device->error (Error::Warn, "m_MFP_width != m_bmh->getWidth() * 2.64\n");
			if (MSWrite_fabs (m_MFP_height / double (m_bmh->getHeight ()) - 2.64) > .3)
				m_device->error (Error::Warn, "m_MFP_height != m_bmh->getHeight() * 2.64\n");

#undef MSWrite_fabs

			if (m_width)
				m_device->error (Error::Warn, "m_width should not be set for BMPs\n");

			if (m_height)
				m_device->error (Error::Warn, "m_height should not be set for BMPs\n");


			//
			// read image
			//

			Byte *internalData = new Byte [getNumDataBytes ()];
			if (!internalData)
				ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for internal BMP image\n");
			if (!m_device->readInternal (internalData, getNumDataBytes ()))
				ErrorAndQuit (Error::FileError, "could not read internal BMP\n");

			// infoHeader
			BMP_BitmapInfoHeader infoHeader;
			infoHeader.setWidth (m_bmh->getWidth ());
			infoHeader.setHeight (m_bmh->getHeight ());
			if (m_bmh->getNumPlanes () != 1)
				ErrorAndQuit (Error::InvalidFormat, "bmh.m_numPlanes != 1\n");
			infoHeader.setNumPlanes (m_bmh->getNumPlanes ());
			infoHeader.setBitsPerPixel (m_bmh->getBitsPerPixel ());
			infoHeader.setCompression (0);	// BI_RGB (uncompressed)
			infoHeader.setSizeImage (0);		// lazy
			infoHeader.setXPixelsPerMeter (0), infoHeader.setYPixelsPerMeter (0);
			infoHeader.setColorsUsed (1 << infoHeader.getBitsPerPixel ());
			infoHeader.setColorsImportant (infoHeader.getColorsUsed ());

			if (infoHeader.getColorsUsed () != 2)
				ErrorAndQuit (Error::InternalError, "color bitmap???  Please email this file to <*****@*****.**>\n");

			Word colorTableSize = infoHeader.getColorsUsed () * BMP_BitmapColorIndex::s_size;

			// fileHeader
			BMP_BitmapFileHeader fileHeader;
			DWord fileSize = BMP_BitmapFileHeader::s_size + BMP_BitmapInfoHeader::s_size
										+ colorTableSize
										+ (m_bmh->getHeight ()
											* getBytesPerScanLine (m_bmh->getWidth (), m_bmh->getBitsPerPixel (), 4));

			fileHeader.setTotalBytes (fileSize);
			fileHeader.setActualImageOffset (BMP_BitmapFileHeader::s_size + BMP_BitmapInfoHeader::s_size
														+ colorTableSize);

			// colorTable
			BMP_BitmapColorIndex *colorIndex = new BMP_BitmapColorIndex [infoHeader.getColorsUsed ()];
			if (!colorIndex)
				ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for colorIndex[]\n");


			// black and white...
			colorIndex [0].setRed (0), colorIndex [0].setGreen (0), colorIndex [0].setBlue (0);
			colorIndex [1].setRed (0xFF), colorIndex [1].setGreen (0xFF), colorIndex [1].setBlue (0xFF);

			m_externalImage = new Byte [m_externalImageSize = fileSize];
			if (!m_externalImage)
				ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for external BMP image\n");

			MemoryDevice device;
			device.setCache (m_externalImage);
			fileHeader.setDevice (&device);
			fileHeader.writeToDevice ();
			infoHeader.setDevice (&device);
			infoHeader.writeToDevice ();
			for (int i = 0; i < 2; i++)
			{
				colorIndex [i].setDevice (&device);
				colorIndex [i].writeToDevice ();
			}

			// (BMP padded to 4 bytes vs WRI input bitmap which is actually padded to 2)
			Word scanLineWRILength = getBytesPerScanLine (infoHeader.getWidth (), infoHeader.getBitsPerPixel (), 2);
			if (scanLineWRILength != m_bmh->getWidthBytes ())
				ErrorAndQuit (Error::InvalidFormat, "scanLineWRILength != m_bmh->getWidthBytes()\n");
			Word scanLineBMPLength = getBytesPerScanLine (infoHeader.getWidth (), infoHeader.getBitsPerPixel (), 4);

		#ifdef DEBUG_IMAGE
			m_device->debug ("in: scanLineWRILength: ", scanLineWRILength);
			m_device->debug ("out: scanLineBMPLength: ", scanLineBMPLength);
		#endif

			// sanity check
			DWord expectedSize = DWord (infoHeader.getHeight ()) * DWord (scanLineWRILength);
			if (expectedSize != getNumDataBytes ())
			{
				if (expectedSize > getNumDataBytes ())
				{
					// better quit instead of reading past end of internalData[]
					ErrorAndQuit (Error::InvalidFormat, "infoHeader.getHeight () * scanLineWRILength > numDataBytes\n");
				}
				else
					m_device->error (Error::Warn, "infoHeader.getHeight () * scanLineWRILength != numDataBytes\n");
			}

			Byte *padding = new Byte [scanLineBMPLength - scanLineWRILength];
			if (!padding)
				ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for scanline\n");
			memset (padding, 0, scanLineBMPLength - scanLineWRILength);

			// the DIB is upside-down...
			for (int i = (int) infoHeader.getHeight () - 1; i >= 0; i--)
			{
				// write bitmap scanline
				device.writeInternal (internalData + i * scanLineWRILength, scanLineWRILength * sizeof (Byte));

				// write padding for scanline
				device.writeInternal (padding, (scanLineBMPLength - scanLineWRILength) * sizeof (Byte));
			}

			delete [] padding;

			device.setCache (NULL);

			delete [] colorIndex;
			delete [] internalData;
		}

		return true;
	}
Exemplo n.º 14
0
	// use this parser for "import" filters
	bool InternalParser::parse (void)
	{
		if (!m_device)
		{
			fprintf (stderr, "INTERNAL ERROR: InternalParser::parse() called without a device\n");
			return false;	// cannot use ErrorAndQuit() because that calls m_device->error()
		}

		if (!m_generator)
			ErrorAndQuit (Error::InternalError, "generator not passed to parser\n");

		//
		// allocate memory
		//

		m_header = new Header;
		if (!m_header)
			ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for header\n");

		m_sectionTable = new SectionTable;
		if (!m_sectionTable)
			ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for sectionTable\n");

		m_pageLayout = new PageLayout;
		if (!m_pageLayout)
			ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for pageLayout\n");

		m_pageTable = new PageTable;
		if (!m_pageTable)
			ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for pageTable\n");

		m_fontTable = new FontTable;
		if (!m_fontTable)
			ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for fontTable\n");

		m_paragraphInfo = new FormatInfo;
		if (!m_paragraphInfo)
			ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for paragraphInfo\n");

		m_characterInfo = new FormatInfo;
		if (!m_characterInfo)
			ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for charInfo\n");

		//
		// Read everything from .WRI file
		//

		m_header->setDevice (m_device);
		if (!m_header->readFromDevice ()) return false;
		DWord numCharBytes = m_header->getNumCharBytes ();

		m_sectionTable->setHeader (m_header);
		m_sectionTable->setDevice (m_device);
		if (!m_sectionTable->readFromDevice ())
			return false;

		m_pageLayout->setHeader (m_header);
		m_pageLayout->setDevice (m_device);
		if (!m_pageLayout->readFromDevice ())
			return false;

		m_pageTable->setPageNumberStart (m_pageLayout->getPageNumberStart ());
		m_pageTable->setHeader (m_header);
		m_pageTable->setDevice (m_device);
		if (!m_pageTable->readFromDevice ())
			return false;

		m_fontTable->setHeader (m_header);
		m_fontTable->setDevice (m_device);
		if (!m_fontTable->readFromDevice ())
			return false;

		m_paragraphInfo->setHeader (m_header);
		m_paragraphInfo->setDevice (m_device);
		m_paragraphInfo->setType (ParaType);
		m_paragraphInfo->setMargins (m_pageLayout->getLeftMargin (), m_pageLayout->getRightMargin ());
		if (!m_paragraphInfo->readFromDevice ())
			return false;

		m_characterInfo->setHeader (m_header);
		m_characterInfo->setDevice (m_device);
		m_characterInfo->setType (CharType);
		m_characterInfo->setFontTable (m_fontTable);
		if (!m_characterInfo->readFromDevice ())
			return false;

#if 0
		DocumentInfo documentInfo;
		FormatParaProperty *paraProperty = (FormatParaProperty *) m_paragraphInfo->begin ();
		int numObjects = 0;
		while (paraProperty)
		{
			if (paraProperty->getIsObject ())
				numObjects++;
			if (paraProperty->getIsHeader ())
			{
				documentInfo.setHasHeader (true);
				if (paraProperty->getIsOnFirstPage ())
					documentInfo.setHasHeaderOnFirstPage (true);
			}
			if (paraProperty->getIsFooter ())
			{
				documentInfo.setHasFooter (true);
				if (paraProperty->getIsOnFirstPage ())
					documentInfo.setHasFooterOnFirstPage (true);
			}
			paraProperty = (FormatParaProperty *) m_paragraphInfo->next ();
		}
		documentInfo.setNumObjects (numObjects);
#endif

		// Get Ready!
		//

		enum Section { InNothing, InBody, InHeader, InFooter } inWhat = InNothing;

		// must call writeBody*() even if document doesn't have one
		bool wroteBody = false;

		PagePointer *pp = m_pageTable->begin ();
		if (m_device->bad ()) return false;

		//
		// Signal callbacks
		//
		#ifdef DEBUG_INTERNALPARSER
			m_device->debug ("@@@ InternalParser: start of document write\n");
		#endif

		if (!m_generator->writeDocumentBegin (m_header->getMagic (), m_pageLayout)) return false;
		m_generator->sigProgress (0);

		// start of text
		if (!m_device->seekInternal (1 * 128, SEEK_SET))
			return false;

		FormatParaProperty *paraProp = (FormatParaProperty *) m_paragraphInfo->begin ();
		if (m_device->bad ()) return false;
		FormatCharProperty *charProp = (FormatCharProperty *) m_characterInfo->begin ();
		if (m_device->bad ()) return false;
		DWord paraStartByte = 0;
		
		if (numCharBytes) while (paraProp)	// loop if not empty document
		{
		#ifdef DEBUG_INTERNALPARSER
			m_device->debug ("@@@ InternalParser: Start of loop - section write\n");
		#endif
			//
			// Section work
			//

			enum Section inWhatNext = InNothing;
			if (paraProp->getIsFooter ())
				inWhatNext = InFooter;
			else if (paraProp->getIsHeader ())
				inWhatNext = InHeader;
			else
				inWhatNext = InBody;

			// beginning of a new section?
			if (inWhatNext != inWhat)
			{
				// end last thing we were in
				switch (inWhat)
				{
				case InFooter:	if (!m_generator->writeFooterEnd ()) return false; else break;
				case InHeader:	if (!m_generator->writeHeaderEnd ()) return false; else break;
				case InBody:	if (!m_generator->writeBodyEnd ()) return false; else break;
				default:	break;	// keep compiler happy
				}

				// start next section
				switch (inWhat = inWhatNext)
				{
				case InFooter:	if (!m_generator->writeFooterBegin ()) return false; else break;
				case InHeader:	if (!m_generator->writeHeaderBegin ()) return false; else break;
				case InBody:	if (!m_generator->writeBodyBegin ()) return false;
					// if there's not pageTable, manually signal start of page for the first and last time
					if (!pp)
						if (!m_generator->writePageNew ())
							return false;

					wroteBody = true;
				default:	break;	// keep compiler happy
				}
			}


			//
			// start paragraph
			//

			bool paraIsText = paraProp->getIsText ();
			int objectType = ObjectType::NotObject;

			DWord paraEndByte, paraAfterEndByte;
			paraAfterEndByte = paraProp->getAfterEndCharByte ();
			paraEndByte = paraAfterEndByte - 1;

			if (paraIsText)
			{
			#ifdef DEBUG_INTERNALPARSER
				m_device->debug ("@@@ InternalParser: Start of paragraph write\n");
			#endif

				// signal paragraph
				if (!m_generator->writeParaInfoBegin (paraProp, NULL, NULL)) return false;
			}
			else
			{
				//
				// Determine whether the object is OLE or not
				// Yes, I know this isn't entirely clean but
				// name a cleaner and more efficient way of doing this...
				//

				Byte data [2];
				Word mappingMode;

				if (!m_device->readInternal (data, 2)) return false;
				ReadWord (mappingMode, data);
				if (!m_device->seekInternal (-2, SEEK_CUR)) return false;	// ungetc()x2

				switch (mappingMode)
				{
				case 0xE4:
					objectType = ObjectType::OLE;

					m_ole = new OLE;
					if (!m_ole)
						ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for OLE object\n");

					m_ole->setDevice (m_device);
					if (!m_ole->readFromDevice ())
						return false;

					if (!m_generator->writeParaInfoBegin (paraProp, m_ole, NULL)) return false;
					break;
				case 0xE3:	// monochrome bitmap?
					objectType = ObjectType::BMP;

					m_image = new Image;
					if (!m_image)
						ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for BMP image object\n");

					m_image->setDevice (m_device);
					if (!m_image->readFromDevice ())
						return false;

					if (!m_generator->writeParaInfoBegin (paraProp, NULL, m_image)) return false;
					break;
				default:
					objectType = ObjectType::WMF;

					m_image = new Image;
					if (!m_image)
						ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for WMF image object\n");

					m_image->setDevice (m_device);
					if (!m_image->readFromDevice ())
						return false;

					if (!m_generator->writeParaInfoBegin (paraProp, NULL, m_image)) return false;
					break;
				}

				// image: BMP/WMF
				if (objectType != ObjectType::OLE)
				{
					if (m_image->getNumHeaderBytes () + m_image->getNumDataBytes ()
							!= paraAfterEndByte - paraStartByte)
					{
						m_device->error (Error::Warn, "imageHeader: numHeaderBytes + numDataBytes != paragraph length\n");

						// we had better seek to where the paragraphs expect us to be to avoid trouble
						if (!m_device->seekInternal (paraAfterEndByte + 128, SEEK_SET)) return false;
					}
				}
			}

		#ifdef DEBUG_INTERNALPARSER
			m_device->debug ("@@@ InternalParser: Start of text write\n");
		#endif

			DWord uptoByte = paraStartByte;

			// loop until we hit end of paragraph (getting one CharProperty on every iteration)
			while (uptoByte < paraAfterEndByte)
			{
				if (charProp)
				{
					if (uptoByte >= charProp->getAfterEndCharByte ())
					{
						charProp = (FormatCharProperty *) m_characterInfo->next ();
						if (m_device->bad ()) return false;
					}

				#ifdef DEBUG_INTERNALPARSER
					m_device->debug ("@@@ InternalParser: character write\n");
				#endif

					if (!m_generator->writeCharInfoBegin (charProp)) return false;
				}

				// ultimately aim for end of CharProperty block; if that's not possible, aim for end of paragraph
				DWord aimUltimateByte = charProp->getEndCharByte () > paraEndByte ? paraEndByte : charProp->getEndCharByte ();

				while (uptoByte <= aimUltimateByte)
				{
					// flag to tell us to generate pageNewWrite/pageTable signal, after writing some normal text
					bool pageTableAck = false;

					// short-term goal (before end of CharProperty, ParaProperty or page)
					DWord aimByte = aimUltimateByte;

					// we want to efficiently send pageNewWrite signals which might be sandwhiched inside
					// a CharProperty block (note: we do NOT end and then restart a CharProperty block because of a writePageNew())
					if (pp)
					{
						if (pp->getFirstCharByte () <= aimByte)
						{
							pageTableAck = true;
							if (pp->getFirstCharByte ())
								// - 1 is because we want the PageNew signal called before the character
								aimByte = pp->getFirstCharByte () - 1;
							else
								aimByte = 0xFFFFFFFF;	// 0 - 1 :)

						#ifdef DEBUG_INTERNALPARSER
							m_device->debug ("@@@ InternalParser: writePageNew pending\n");
						#endif
						}
					}

					// write text (using buffering)
					while (uptoByte <= aimByte && aimByte != 0xFFFFFFFF)
					{
						const DWord amountToRead = aimByte - uptoByte + 1 > 1023
															? 1023 : aimByte - uptoByte + 1;

						if (paraIsText)
						{
							Byte buffer [1024];

							if (!m_device->readInternal (buffer, amountToRead)) return false;

							buffer [amountToRead] = '\0';
							if (!m_generator->processText (buffer, uptoByte + amountToRead - 1 == paraEndByte)) return false;
						}

						uptoByte += amountToRead;
					}		// while (uptoByte <= aimByte && aimByte != 0xFFFFFFFF) {

					// generate pageNewWrite/pageTable signal, if requested
					if (pageTableAck)
					{
					#ifdef DEBUG_INTERNALPARSER
						m_device->debug ("@@@ InternalParser: writePageNew\n");
					#endif

						if (!m_generator->writePageNew (pp->getPageNumber ())) return false;

						pp = m_pageTable->next ();
						if (m_device->bad ()) return false;
					}
				}		// while (uptoByte <= aimUltimateByte) {


				#ifdef DEBUG_INTERNALPARSER
					m_device->debug ("@@@ InternalParser: character end write\n");
				#endif

				// end char info
				if (charProp)
					if (!m_generator->writeCharInfoEnd (charProp, uptoByte == paraAfterEndByte))
						return false;

			}		// while (uptoByte < paraAfterEndByte) {


			//
			// ouptut object
			//

			if (!paraIsText)
			{
				if (objectType == ObjectType::OLE)
				{
					if (!m_generator->writeBinary (m_ole->getExternalObject (), m_ole->getExternalObjectSize ()))
						return false;
				}
				else	// if (objectType == ObjectType::BMP || objectType == ObjectType::WMF)
				{
					if (!m_generator->writeBinary (m_image->getExternalImage (), m_image->getExternalImageSize ()))
						return false;
				}
			}

			//
			// end paragraph
			//

			if (paraIsText)
			{
				// end paragraph
				if (!m_generator->writeParaInfoEnd (paraProp, NULL)) return false;
			}
			else
			{
				switch (objectType)
				{
				case ObjectType::OLE:
					if (!m_generator->writeParaInfoEnd (paraProp, m_ole, NULL)) return false;
					delete m_ole;
					m_ole = NULL;
					break;
				case ObjectType::BMP:
					if (!m_generator->writeParaInfoEnd (paraProp, NULL, m_image)) return false;
					delete m_image;
					m_image = NULL;
					break;
				case ObjectType::WMF:
					if (!m_generator->writeParaInfoEnd (paraProp, NULL, m_image)) return false;
					delete m_image;
					m_image = NULL;
					break;
				}
			}

			paraStartByte = paraAfterEndByte;

			// numCharBytes != 0 because we checked it before we entered the loop
			m_generator->sigProgress (paraStartByte * 100 / numCharBytes);

			// get next paragraph properties
			paraProp = (FormatParaProperty *) m_paragraphInfo->next ();
			if (m_device->bad ()) return false;
		}

		// end last thing we were in
		switch (inWhat)
		{
		case InFooter:	if (!m_generator->writeFooterEnd ()) return false; else break;
		case InHeader:	if (!m_generator->writeHeaderEnd ()) return false; else break;
		case InBody:	if (!m_generator->writeBodyEnd ()) return false; else break;
		default:	break;	// keep compiler happy
		}

		// didn't output a body (usually due to a blank document)
		if (!wroteBody)
		{
		#ifdef DEBUG_INTERNALPARSER
			m_device->debug ("@@@ InternalParser: did not write body, writing one now\n");
		#endif
		
			if (!m_generator->writeBodyBegin ()) return false;
			if (!m_generator->writeBodyEnd ()) return false;
		}

		m_generator->sigProgress (100);
		if (!m_generator->writeDocumentEnd (m_header->getMagic (), m_pageLayout)) return false;

		return true;
	}
Exemplo n.º 15
0
	bool FormatInfo::readFromDevice (void)
	{
	CHECK_DEVICE;

	#ifdef DEBUG_FORMATINFO
		if (m_type == ParaType)
			m_device->debug ("\n<<<< libmswrite.cpp::FormatInfo::readFromDevice (ParaType) >>>>\n");
		else	// if (m_type == CharType)
			m_device->debug ("\n<<<< libmswrite.cpp::FormatInfo::readFromDevice (CharType) >>>>\n");
	#endif

		int formatInfoPageNum;
		if (m_type == ParaType)
			formatInfoPageNum = m_header->getNumPageParaInfo ();
		else	// if (m_type == CharType)
			formatInfoPageNum = m_header->getNumPageCharInfo ();


	#ifdef DEBUG_FORMATINFO
		m_device->debug ("numpages format info=", formatInfoPageNum);
	#endif

		// you have to have information pages that cover the _entire_ document (if it's not empty that is)
		if (m_header->getNumCharBytes () && formatInfoPageNum == 0)
		{
			if (m_type == ParaType)
			{
				ErrorAndQuit (Error::InvalidFormat, "no paragraph formatting information page\n");
			}
			else	// if (m_type == CharType)
			{
				ErrorAndQuit (Error::InvalidFormat, "no character formatting information page\n");
			}
		}

		// seek to start of info pages
		if (!m_device->seek (((m_type == ParaType) ?
										m_header->getPageParaInfo () : m_header->getPageCharInfo ()) * 128, SEEK_SET))
			return false;

		//
		// read in every info page
		// (this eats up all your memory...)
		//
		// The reason this is done is because infoPages (formatting information) are required
		// in between reads of text and on most devices, continually seeking back and forth
		// between the text pages and information pages is inconvenient and inefficient to say
		// the least.
		//
		// Generally speaking there is more text than formatting information some it is probably
		// cheaper (memory-wise) to cache the formatting in memory, rather than the text.
		//
		// A few more good reasons for caching formatting information:
		//
		// * we don't actually expand the formatting pages into the full FormatPointers
		//   and FormatProperty's (until begin()/next() are called) so we save quite a bit of
		//   memory
		// * some filters need to know information like the number of objects in advance
		//   so an extra parse of the formatting information (already cached :)) is required
		//
		for (int i = 0; i < formatInfoPageNum; i++)
		{
			if (!m_formatInfoPageList.addToBack ())
				ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for an information page\n");

			FormatInfoPage &fip = *m_formatInfoPageList.begin (false);
			if (m_device->bad ()) return false;

			fip.setHeader (m_header);
			fip.setDevice (m_device);
			fip.setType (m_type);
			
			if (m_type == ParaType)
				fip.setMargins (m_leftMargin, m_rightMargin);
			else	// if (m_type == CharType)
				fip.setFontTable (m_fontTable);

			if (!fip.readFromDevice ())
				return false;
		}

		return true;
	}
Exemplo n.º 16
0
	bool FormatInfo::add (const void *property, const bool force)
	{
	CHECK_DEVICE;

	#ifdef DEBUG_FORMATINFO
		m_device->debug (">>>> FormatInfo::add <<<<\n");
	#endif
	
		DWord currentChar = m_device->tellInternal () - 128;
		
		// so that export filter writers can be lazy...
		if (m_nextChar == currentChar && !force)
		{
		#ifdef DEBUG_FORMATINFO
			m_device->debug ("\tEmpty FormatProperty, ignoring\n");
		#endif
			return true;
		}

		bool needToAllocate = false;

		if (m_formatInfoPageList.getNumElements ())
		{
			FormatInfoPage &fip = *m_formatInfoPageList.begin (false);
			if (!fip.add (property))
			{
				// a real error
				if (m_device->bad ())
					return false;

				needToAllocate = true;
			}
		}
		else
			needToAllocate = true;

		if (needToAllocate)
		{
			#ifdef DEBUG_FORMATINFO
				m_device->debug ("\tneedToAllocate=yes, FormatInfoPage::firstCharByte=", m_nextChar);
			#endif
				
			if (!m_formatInfoPageList.addToBack ())
				ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for new formatInfoPage\n");
			
			FormatInfoPage &fip = *m_formatInfoPageList.begin (false);
			fip.setDevice (m_device);
			fip.setFirstCharByte (m_nextChar);
			fip.setType (m_type);
			
			if (m_type == ParaType)
				fip.setMargins (m_leftMargin, m_rightMargin);
			else	// if (m_type == CharType)
			{
				assert (m_fontTable);
				fip.setFontTable (m_fontTable);
			}
			
			if (!fip.add (property))
				return false;
		}

		m_nextChar = currentChar;
		return true;
	}