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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
// 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; }
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; }
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; }