filters

structures.cpp

00001 /* This file is part of the LibMSWrite Library
00002    Copyright (C) 2001-2003 Clarence Dang <clarencedang@users.sourceforge.net>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License Version 2 as published by the Free Software Foundation.
00007 
00008    This library is distributed in the hope that it will be useful,
00009    but WITHOUT ANY WARRANTY; without even the implied warranty of
00010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011    Library General Public License Version 2 for more details.
00012 
00013    You should have received a copy of the GNU Library General Public License
00014    Version 2 along with this library; see the file COPYING.LIB.  If not,
00015    write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00016  * Boston, MA 02110-1301, USA.
00017 
00018    LibMSWrite Project Website:
00019    http://sourceforge.net/projects/libmswrite/
00020 */
00021 
00022 /*
00023  * structures.cpp - Process Internal Microsoft(r) Write file structures
00024  * This file has ugly reading/writing code that couldn't be generated.
00025  * It performs some higher-level sanity checks.
00026  *
00027  */
00028 
00029 #include "structures.h"
00030 #include "structures_private.h"
00031 
00032 namespace MSWrite
00033 {
00034     PageLayout::PageLayout () : m_numModified (0)
00035     {
00036     }
00037 
00038     PageLayout::~PageLayout ()
00039     {
00040     }
00041 
00042     PageLayout &PageLayout::operator= (const PageLayout &rhs)
00043     {
00044         if (this == &rhs)
00045             return *this;
00046 
00047         PageLayoutGenerated::operator= (rhs);
00048         NeedsHeader::operator= (rhs);
00049 
00050         m_numModified = rhs.m_numModified;
00051 
00052         return *this;
00053     }
00054 
00055     bool PageLayout::readFromDevice (void)
00056     {
00057     CHECK_DEVICE;
00058 
00059     #ifdef DEBUG_PAGELAYOUT
00060         m_device->debug ("\n<<<< PageLayout::readFromDevice >>>>\n");
00061     #endif
00062 
00063         int numPageLayoutPages = m_header->getNumPageSectionProperty ();
00064 
00065     #ifdef DEBUG_PAGELAYOUT
00066         m_device->debug ("num pageLayoutPages: ", numPageLayoutPages);
00067     #endif
00068 
00069         // no PageLayout
00070         if (numPageLayoutPages == 0)
00071             return true;
00072         else if (numPageLayoutPages > 1)
00073             ErrorAndQuit (Error::InvalidFormat, "invalid #pageLayoutPages\n");
00074 
00075         // seek to the PageLayout in the file
00076         if (!m_device->seekInternal (m_header->getPageSectionProperty () * 128, SEEK_SET))
00077             ErrorAndQuit (Error::FileError, "could not seek to pageLayout\n");
00078 
00079         if (!PageLayoutGenerated::readFromDevice ())
00080             return false;
00081 
00082     #ifdef DEBUG_PAGELAYOUT
00083         Dump (magic102);
00084         Dump (magic512);
00085 
00086         Dump (pageHeight);
00087         Dump (pageWidth);
00088         Dump (pageNumberStart);
00089         Dump (topMargin);
00090         Dump (textHeight);
00091         Dump (leftMargin);
00092         Dump (textWidth);
00093 
00094         Dump (magic256);
00095 
00096         Dump (headerFromTop);
00097         Dump (footerFromTop);
00098 
00099         Dump (magic720);
00100         Dump (zero);
00101         Dump (magic1080);
00102         Dump (unknown);
00103         Dump (zero2);
00104     #endif
00105 
00106         #define UpdateModifiedCount(variable) if (m_##variable != variable##Default) m_numModified++
00107         UpdateModifiedCount (magic102);
00108         UpdateModifiedCount (magic512);
00109         UpdateModifiedCount (pageHeight);
00110         UpdateModifiedCount (pageWidth);
00111         UpdateModifiedCount (pageNumberStart);
00112         UpdateModifiedCount (topMargin);
00113         UpdateModifiedCount (textHeight);
00114         UpdateModifiedCount (leftMargin);
00115         UpdateModifiedCount (textWidth);
00116         UpdateModifiedCount (magic256);
00117         UpdateModifiedCount (headerFromTop);
00118         UpdateModifiedCount (footerFromTop);
00119         UpdateModifiedCount (magic720);
00120         UpdateModifiedCount (zero);
00121         UpdateModifiedCount (magic1080);
00122         //UpdateModifiedCount (unknown);    // no reliable default for unknown
00123         UpdateModifiedCount (zero2);
00124         #undef UpdateModifiedCount
00125 
00126         return true;
00127     }
00128 
00129     bool PageLayout::writeToDevice (void)
00130     {
00131     CHECK_DEVICE;
00132 
00133     #ifdef DEBUG_PAGELAYOUT
00134         m_device->debug ("\n>>>> PageLayout::writeToDevice <<<<\n");
00135     #endif
00136 
00137         m_header->setPageSectionProperty (m_device->tellInternal () / 128);
00138 
00139         // if we're just using defaults, we don't need a pageLayout
00140         if (!getIsModified ())
00141             return true;
00142 
00143         if (!PageLayoutGenerated::writeToDevice ())
00144             return false;
00145 
00146         return true;
00147     }
00148 
00149 
00150     Font::Font (const Byte *name, const Byte family) : m_name (NULL)
00151     {
00152         if (name) setName (name);
00153         FontGenerated::m_family = family;
00154     }
00155 
00156     Font::~Font ()
00157     {
00158         delete [] m_name;
00159     }
00160 
00161     Font &Font::operator= (const Font &rhs)
00162     {
00163         if (this == &rhs)
00164             return *this;
00165 
00166         FontGenerated::operator= (rhs);
00167 
00168         setName (rhs.getName ());
00169 
00170         return *this;
00171     }
00172 
00173     bool Font::readFromDevice (void)
00174     {
00175     CHECK_DEVICE;
00176 
00177         if (!FontGenerated::readFromDevice ())
00178             return false;
00179 
00180     #ifdef DEBUG_FONT
00181         Dump (numDataBytes);
00182         Dump (family);
00183     #endif
00184 
00185         // is this font on the next page?
00186         if (m_numDataBytes == 0xFFFF)
00187             return false;   // Device::m_error will be clear so this is ok
00188 
00189         // is this the last font _ever_?
00190         if (m_numDataBytes == 0)
00191             return false;   // Device::m_error will be clear so this is ok
00192 
00193         // Font structure size can't exceed a page anyway
00194         if (m_numDataBytes > 128 - sizeof (m_numDataBytes))
00195             ErrorAndQuit (MSWrite::Error::InvalidFormat, "Font nameLen is too big\n");
00196 
00197         // calculate length of name
00198         int nameLen = m_numDataBytes - sizeof (m_family) - 1    /* NUL */;
00199 
00200         // we should really call this->setName()...
00201         m_name = new Byte [nameLen + 1];
00202         if (!m_name)
00203             ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for fontName\n");
00204 
00205         // read fontName
00206         if (!m_device->readInternal (m_name, nameLen + 1))
00207             ErrorAndQuit (Error::FileError, "could not read fontName\n");
00208 
00209         // check name is valid
00210         if (m_name [nameLen] != '\0')
00211             ErrorAndQuit (Error::InvalidFormat, "fontName not NUL-terminated\n");
00212 
00213     #ifdef DEBUG_FONT
00214         m_device->debug ("\tfontName=", (const char *) m_name);
00215     #endif
00216         return true;
00217     }
00218 
00219     bool Font::writeToDevice (void)
00220     {
00221     CHECK_DEVICE;
00222 
00223         // should I be on the next page? (TODO: this check is stupid if it's the last font)
00224         Word offset = m_device->tellInternal () % 128;  // from start of current page
00225         if (offset + sizeof (m_numDataBytes) + m_numDataBytes + sizeof (m_numDataBytes)/*for next Font's 0xFFFF*/ > 128)
00226         {
00227             // signal that font is on next page
00228             Byte scratch [2] = {0xFF, 0xFF};
00229             if (!m_device->writeInternal (scratch, 2))
00230                 ErrorAndQuit (Error::FileError, "could not write Font 0xFFFF\n");
00231             return false;   // Device::m_error will be clear so this is ok
00232         }
00233 
00234         // --- we don't have to write 0 to indicate last font (since we write the right number of elements) ---
00235 
00236         // write numDataBytes, family
00237         if (!FontGenerated::writeToDevice ())
00238             return false;
00239 
00240         if (!m_device->writeInternal (m_name, m_numDataBytes - sizeof (m_family)))
00241             ErrorAndQuit (Error::FileError, "could not write fontName\n");
00242 
00243         return true;
00244     }
00245 
00246 
00247     FormatCharProperty::FormatCharProperty () : m_fontTable (NULL)
00248     {
00249         // m_afterEndCharByte =
00250         // m_font =
00251     }
00252 
00253     FormatCharProperty::~FormatCharProperty ()
00254     {
00255     }
00256 
00257     FormatCharProperty &FormatCharProperty::operator= (const FormatCharProperty &rhs)
00258     {
00259         if (this == &rhs)
00260             return *this;
00261 
00262         FormatCharPropertyGenerated::operator= (rhs);
00263 
00264         m_afterEndCharByte = rhs.m_afterEndCharByte;
00265         m_fontTable = rhs.m_fontTable;
00266         m_font = rhs.m_font;
00267 
00268         return *this;
00269     }
00270 
00271     bool FormatCharProperty::operator== (FormatCharProperty &rhs)
00272     {
00273         DWord numDataBytes;
00274 
00275         if ((numDataBytes = getNumDataBytes ()) != rhs.getNumDataBytes ())
00276             return false;
00277 
00278         writeToArray ();
00279         rhs.writeToArray ();
00280 
00281         return memcmp (m_data + sizeof (m_numDataBytes), rhs.m_data + sizeof (m_numDataBytes), numDataBytes) == 0;
00282     }
00283 
00284     bool FormatCharProperty::readFromDevice (void)
00285     {
00286     CHECK_DEVICE;
00287 
00288     #ifdef DEBUG_CHAR
00289         m_device->debug ("\nFormatCharProperty::readFromDevice\n");
00290     #endif
00291 
00292         if (!FormatCharPropertyGenerated::readFromDevice ())
00293             return false;
00294 
00295         if (!m_fontTable)
00296             ErrorAndQuit (Error::InternalError, "m_fontTable not setup for FormatCharProperty::readFromDevice\n");
00297 
00298         // note: the converse is done in FormatInfoPage::add(), not FormatCharProperty::writeToDevice
00299         if (!updateFont ()) return false;
00300 
00301         return true;
00302     }
00303 
00304     bool FormatCharProperty::writeToDevice (void)
00305     {
00306     CHECK_DEVICE;
00307 
00308     #ifdef DEBUG_CHAR
00309         m_device->debug ("\nFormatCharProperty::writeToDevice, #bytes=", getNumDataBytes ());
00310     #endif
00311 
00312         return FormatCharPropertyGenerated::writeToDevice ();
00313     }
00314 
00315     bool FormatCharProperty::updateFont (void)
00316     {
00317         Font *fontPtr = m_fontTable->getFont (getFontCode ());
00318         if (!fontPtr)
00319             ErrorAndQuit (Error::InvalidFormat, "fontCode out of range\n");
00320 
00321         m_font = *fontPtr;
00322         return true;
00323     }
00324 
00325     bool FormatCharProperty::updateFontCode (void)
00326     {
00327         DWord code = m_fontTable->addFont (&m_font);
00328         if (code == 0xFFFFFFFF)
00329             return false;
00330         else
00331         {
00332             setFontCode (code);
00333             return true;
00334         }
00335     }
00336 
00337 
00338     FormatParaPropertyTabulator::FormatParaPropertyTabulator ()
00339     {
00340     }
00341 
00342     FormatParaPropertyTabulator::~FormatParaPropertyTabulator ()
00343     {
00344     }
00345 
00346     FormatParaPropertyTabulator &FormatParaPropertyTabulator::operator= (const FormatParaPropertyTabulator &rhs)
00347     {
00348         if (this == &rhs)
00349             return *this;
00350 
00351         FormatParaPropertyTabulatorGenerated::operator= (rhs);
00352 
00353         return *this;
00354     }
00355 
00356     bool FormatParaPropertyTabulator::readFromDevice (void)
00357     {
00358     CHECK_DEVICE;
00359 
00360     #ifdef DEBUG_PARA_TAB
00361         m_device->debug ("\nFormatParaPropertyTabulator::readFromDevice\n");
00362     #endif
00363 
00364         if (!FormatParaPropertyTabulatorGenerated::readFromDevice ())
00365             return false;
00366 
00367     #ifdef DEBUG_PARA_TAB
00368         Dump (indent);
00369         Dump (type);
00370         Dump (zero);
00371     #endif
00372 
00373         return true;
00374     }
00375 
00376     bool FormatParaPropertyTabulator::writeToDevice (void)
00377     {
00378     CHECK_DEVICE;
00379 
00380     #ifdef DEBUG_PARA_TAB
00381         m_device->debug ("\nFormatParaPropertyTabulator::writeToDevice\n");
00382     #endif
00383 
00384         return FormatParaPropertyTabulatorGenerated::writeToDevice ();
00385     }
00386 
00387 
00388     FormatParaProperty::FormatParaProperty () : m_leftMargin (0xFFFF),
00389                                                                 m_rightMargin (0xFFFF),
00390                                                                 m_numTabulators (0),
00391                                                                 m_addedTooManyTabs (false)
00392     {
00393         // m_afterEndCharByte =
00394     }
00395 
00396     FormatParaProperty::~FormatParaProperty ()
00397     {
00398     }
00399 
00400     FormatParaProperty &FormatParaProperty::operator= (const FormatParaProperty &rhs)
00401     {
00402         if (this == &rhs)
00403             return *this;
00404 
00405         FormatParaPropertyGenerated::operator= (rhs);
00406 
00407         m_afterEndCharByte = rhs.m_afterEndCharByte;
00408         m_leftMargin = rhs.m_leftMargin, m_rightMargin = rhs.m_rightMargin;
00409         m_numTabulators = rhs.m_numTabulators;
00410         m_addedTooManyTabs = rhs.m_addedTooManyTabs;
00411 
00412         return *this;
00413     }
00414 
00415     bool FormatParaProperty::operator== (FormatParaProperty &rhs)
00416     {
00417         DWord numDataBytes;
00418         if ((numDataBytes = getNumDataBytes ()) != rhs.getNumDataBytes ())
00419             return false;
00420 
00421         writeToArray ();
00422         rhs.writeToArray ();
00423 
00424         return memcmp (m_data + sizeof (m_numDataBytes), rhs.m_data + sizeof (m_numDataBytes), numDataBytes) == 0;
00425     }
00426 
00427     bool FormatParaProperty::readFromDevice (void)
00428     {
00429     CHECK_DEVICE;
00430 
00431     #ifdef DEBUG_PARA
00432         m_device->debug ("\nFormatParaProperty::readFromDevice\n");
00433     #endif
00434 
00435     #ifdef CHECK_INTERNAL
00436         if (m_leftMargin == 0xFFFF && m_rightMargin == 0xFFFF)
00437             ErrorAndQuit (Error::InternalError, "FormatParaProperty::readFromDevice call not setup\n");
00438     #endif
00439 
00440         if (!FormatParaPropertyGenerated::readFromDevice ())
00441             return false;
00442 
00443         // Correct indentation in Header and Footer:
00444         //
00445         // For unknown reasons, Write adds the leftMargin to the leftIndent
00446         // and rightMargin to rightIndent in the Header and Footer only but
00447         // does not touch the leftIndentFirstLine
00448         //
00449         // TODO: what if it's an image in the header/footer?
00450         if (getIsNotNormalParagraph ())
00451         {
00452             // adjust leftIndent
00453             if (m_leftMargin < m_leftIndent)
00454                 m_leftIndent -= m_leftMargin;
00455             else
00456                 m_leftIndent = 0;
00457 
00458             // adjust rightIndent
00459             if (m_rightMargin < m_rightIndent)
00460                 m_rightIndent -= m_rightMargin;
00461             else
00462                 m_rightIndent = 0;
00463         }
00464 
00465         if (m_numDataBytes > 22)
00466             m_numTabulators = (m_numDataBytes - 22) / FormatParaPropertyTabulator::s_size;
00467         else
00468             m_numTabulators = 0;
00469 
00470         // for impexp
00471         if (getNumDataBytes () != m_numDataBytes && !m_numTabulators)
00472             m_device->error (Error::Warn, "m_numDataBytes != getNumDataBytes ()\n");
00473         UseThisMuch::signalHaveSetData (false, m_numDataBytes * 8);
00474 
00475         return true;
00476     }
00477 
00478     bool FormatParaProperty::writeToDevice (void)
00479     {
00480     CHECK_DEVICE;
00481 
00482     #ifdef CHECK_INTERNAL
00483         if (m_leftMargin == 0xFFFF && m_rightMargin == 0xFFFF)
00484             ErrorAndQuit (Error::InternalError, "FormatParaProperty::writeToDevice call not setup\n");
00485     #endif
00486 
00487     #ifdef DEBUG_PARA
00488         m_device->debug ("\nFormatParaProperty::writeToDevice, #bytes=", getNumDataBytes ());
00489     #endif
00490 
00491         if (m_addedTooManyTabs)
00492             ErrorAndQuit (Error::InternalError, "cannot have more than 14 tabulators; shouldn't even have more than 12\n");
00493 
00494         if (m_numTabulators > 12)
00495             m_device->error (Error::Warn, "should not have more than 12 tabulators since you can only access 12 tabs via the GUI\n");
00496 
00497         // --- indents adjusted in updateIndents() called by FormatInfoPage::add() ---
00498 
00499         if (!FormatParaPropertyGenerated::writeToDevice ())
00500             return false;
00501 
00502         return true;
00503     }
00504 
00505 
00506     Image::Image () : m_externalImage (NULL),
00507                             m_externalImageSize (0),
00508                             m_externalImageUpto (0),
00509                             m_originalWidth (0), m_originalHeight (0),
00510                             m_displayedWidth (0), m_displayedHeight (0)
00511     {
00512     }
00513 
00514     Image::~Image ()
00515     {
00516         delete [] m_externalImage;
00517     }
00518 
00519     Image &Image::operator= (const Image &rhs)
00520     {
00521         if (this == &rhs)
00522             return *this;
00523 
00524         ImageGenerated::operator= (rhs);
00525 
00526         m_externalImageSize = rhs.m_externalImageSize;
00527         m_externalImageUpto = rhs.m_externalImageUpto;
00528 
00529         delete [] m_externalImage;
00530         m_externalImage = new Byte [m_externalImageSize];
00531         if (!m_externalImage)
00532             return *this;  // TODO: error check
00533 
00534         if (rhs.m_externalImage)
00535             memcpy (m_externalImage, rhs.m_externalImage, m_externalImageUpto);
00536 
00537         m_originalWidth = rhs.m_originalWidth;
00538         m_originalHeight = rhs.m_originalHeight;
00539 
00540         m_displayedWidth = rhs.m_displayedWidth;
00541         m_displayedHeight = rhs.m_displayedHeight;
00542 
00543         return *this;
00544     }
00545 
00546     // returns how many bytes are needed for each scanline (with byte padding)
00547     int Image::getBytesPerScanLine (const int width, const int bitsPerPixel, const int padBytes)
00548     {
00549         int bitWidth;
00550         int byteWidth;
00551 
00552         // figure out how many bytes it would take to represent "width" pixels, each taking "bitsPerPixel" bits
00553         bitWidth = width * bitsPerPixel;
00554         byteWidth = bitWidth / 8;
00555         if (bitWidth % 8)
00556             byteWidth++;
00557 
00558         // pad the number of bytes taken to the next multiple of "padBytes"
00559         // (if not divisible by "padBytes")
00560         byteWidth = (byteWidth + padBytes - 1) / padBytes * padBytes;
00561 
00562         return byteWidth;
00563     }
00564 
00565     bool Image::readFromDevice (void)
00566     {
00567     CHECK_DEVICE;
00568 
00569     #ifdef DEBUG_IMAGE
00570         m_device->debug ("\n<<<< Image::readFromDevice >>>>\n");
00571     #endif
00572 
00573         if (!ImageGenerated::readFromDevice ())
00574             return false;
00575 
00576     #ifdef DEBUG_IMAGE
00577         Dump (mappingMode);
00578         Dump (MFP_width);
00579         Dump (MFP_height);
00580         Dump (MFP_unknown);
00581 
00582         Dump (indent);
00583         Dump (width);
00584         Dump (height);
00585         Dump (zero);
00586 
00587         Dump (numHeaderBytes);
00588         Dump (numDataBytes);
00589         Dump (horizontalScalingRel1000);
00590         Dump (verticalScalingRel1000);
00591     #endif
00592 
00593         if (getIsWMF ())
00594         {
00595             //
00596             // get image dimensions
00597             //
00598 
00599             if (m_bmh->getWidth () || m_bmh->getHeight ())
00600                 m_device->error (Error::Warn, "m_bmh structure should be 0 for WMFs\n");
00601 
00602             m_originalWidth = Milli2Twip (double (m_MFP_width) / 100.0) * 4.0/3.0;
00603             m_originalHeight = Milli2Twip (double (m_MFP_height) / 100.0) * 4.0/3.0;
00604 
00605             m_displayedWidth = double (m_width);
00606             m_displayedHeight = double (m_height);
00607 
00608             if (m_horizontalScalingRel1000 != 1000)
00609                 m_device->error (Error::Warn, "horizontal scaling should not be set for WMFs\n");
00610             if (m_verticalScalingRel1000 != 1000)
00611                 m_device->error (Error::Warn, "vertical scaling should not be set for WMFs\n");
00612 
00613 
00614             //
00615             // read image
00616             //
00617 
00618             m_externalImage = new Byte [m_externalImageSize = getNumDataBytes ()];
00619             if (!m_externalImage)
00620                 ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for external WMF image\n");
00621 
00622             if (!m_device->readInternal (m_externalImage, m_externalImageSize))
00623                 ErrorAndQuit (Error::FileError, "could not read internal WMF\n");
00624 
00625             // Header check
00626             WMFHeader wmfHeader;
00627             m_device->setCache (m_externalImage);
00628                 wmfHeader.setDevice (m_device);
00629                 if (!wmfHeader.readFromDevice ())
00630                     return false;
00631 
00632                 // TODO: fix this incorrect check (see wmf.cpp)
00633                 //if (wmfHeader.getFileSize () * sizeof (Word) != m_numDataBytes)
00634                 //  m_device->error (Error::Warn, "wmfHeader.fileSize != numDataBytes\n");
00635             m_device->setCache (NULL);
00636         }
00637         else    //  if (getIsBMP ())
00638         {
00639             //
00640             // get image dimensions
00641             //
00642 
00643             m_originalWidth = Point2Twip (DWord (m_bmh->getWidth ()));
00644             m_originalHeight = Point2Twip (DWord (m_bmh->getHeight ()));
00645 
00646             m_displayedWidth = m_originalWidth / 1.38889 * m_horizontalScalingRel1000 / 1000;
00647             m_displayedHeight = m_originalHeight / 1.38889 * m_verticalScalingRel1000 / 1000;
00648 
00649 #define MSWrite_fabs(val) (((val)>=0)?(val):(-(val)))
00650 
00651             if (MSWrite_fabs (m_MFP_width / double (m_bmh->getWidth ()) - 2.64) > .3)
00652                 m_device->error (Error::Warn, "m_MFP_width != m_bmh->getWidth() * 2.64\n");
00653             if (MSWrite_fabs (m_MFP_height / double (m_bmh->getHeight ()) - 2.64) > .3)
00654                 m_device->error (Error::Warn, "m_MFP_height != m_bmh->getHeight() * 2.64\n");
00655 
00656 #undef MSWrite_fabs
00657 
00658             if (m_width)
00659                 m_device->error (Error::Warn, "m_width should not be set for BMPs\n");
00660 
00661             if (m_height)
00662                 m_device->error (Error::Warn, "m_height should not be set for BMPs\n");
00663 
00664 
00665             //
00666             // read image
00667             //
00668 
00669             Byte *internalData = new Byte [getNumDataBytes ()];
00670             if (!internalData)
00671                 ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for internal BMP image\n");
00672             if (!m_device->readInternal (internalData, getNumDataBytes ()))
00673                 ErrorAndQuit (Error::FileError, "could not read internal BMP\n");
00674 
00675             // infoHeader
00676             BMP_BitmapInfoHeader infoHeader;
00677             infoHeader.setWidth (m_bmh->getWidth ());
00678             infoHeader.setHeight (m_bmh->getHeight ());
00679             if (m_bmh->getNumPlanes () != 1)
00680                 ErrorAndQuit (Error::InvalidFormat, "bmh.m_numPlanes != 1\n");
00681             infoHeader.setNumPlanes (m_bmh->getNumPlanes ());
00682             infoHeader.setBitsPerPixel (m_bmh->getBitsPerPixel ());
00683             infoHeader.setCompression (0);  // BI_RGB (uncompressed)
00684             infoHeader.setSizeImage (0);        // lazy
00685             infoHeader.setXPixelsPerMeter (0), infoHeader.setYPixelsPerMeter (0);
00686             infoHeader.setColoursUsed (1 << infoHeader.getBitsPerPixel ());
00687             infoHeader.setColoursImportant (infoHeader.getColoursUsed ());
00688 
00689             if (infoHeader.getColoursUsed () != 2)
00690                 ErrorAndQuit (Error::InternalError, "colour bitmap???  Please email clarencedang@users.sourceforge.net this file\n");
00691 
00692             Word colourTableSize = infoHeader.getColoursUsed () * BMP_BitmapColourIndex::s_size;
00693 
00694             // fileHeader
00695             BMP_BitmapFileHeader fileHeader;
00696             DWord fileSize = BMP_BitmapFileHeader::s_size + BMP_BitmapInfoHeader::s_size
00697                                         + colourTableSize
00698                                         + (m_bmh->getHeight ()
00699                                             * getBytesPerScanLine (m_bmh->getWidth (), m_bmh->getBitsPerPixel (), 4));
00700 
00701             fileHeader.setTotalBytes (fileSize);
00702             fileHeader.setActualImageOffset (BMP_BitmapFileHeader::s_size + BMP_BitmapInfoHeader::s_size
00703                                                         + colourTableSize);
00704 
00705             // colourTable
00706             BMP_BitmapColourIndex *colourIndex = new BMP_BitmapColourIndex [infoHeader.getColoursUsed ()];
00707             if (!colourIndex)
00708                 ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for colourIndex[]\n");
00709 
00710 
00711             // black and white...
00712             colourIndex [0].setRed (0), colourIndex [0].setGreen (0), colourIndex [0].setBlue (0);
00713             colourIndex [1].setRed (0xFF), colourIndex [1].setGreen (0xFF), colourIndex [1].setBlue (0xFF);
00714 
00715             m_externalImage = new Byte [m_externalImageSize = fileSize];
00716             if (!m_externalImage)
00717                 ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for external BMP image\n");
00718 
00719             MemoryDevice device;
00720             device.setCache (m_externalImage);
00721             fileHeader.setDevice (&device);
00722             fileHeader.writeToDevice ();
00723             infoHeader.setDevice (&device);
00724             infoHeader.writeToDevice ();
00725             for (int i = 0; i < 2; i++)
00726             {
00727                 colourIndex [i].setDevice (&device);
00728                 colourIndex [i].writeToDevice ();
00729             }
00730 
00731             // write out each scanline
00732             // (BMP padded to 4 bytes vs WRI input bitmap which is actually padded to 2)
00733             Word scanLineWRILength = getBytesPerScanLine (infoHeader.getWidth (), infoHeader.getBitsPerPixel (), 2);
00734             if (scanLineWRILength != m_bmh->getWidthBytes ())
00735                 ErrorAndQuit (Error::InvalidFormat, "scanLineWRILength != m_bmh->getWidthBytes()\n");
00736             Word scanLineBMPLength = getBytesPerScanLine (infoHeader.getWidth (), infoHeader.getBitsPerPixel (), 4);
00737 
00738         #ifdef DEBUG_IMAGE
00739             m_device->debug ("in: scanLineWRILength: ", scanLineWRILength);
00740             m_device->debug ("out: scanLineBMPLength: ", scanLineBMPLength);
00741         #endif
00742 
00743             Byte *padding = new Byte [scanLineBMPLength - scanLineWRILength];
00744             if (!padding)
00745                 ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for scanline\n");
00746             memset (padding, 0, scanLineBMPLength - scanLineWRILength);
00747 
00748             // the DIB is upside-down...
00749             for (int i = (int) infoHeader.getHeight () - 1; i >= 0; i--)
00750             {
00751                 // write bitmap scanline
00752                 device.writeInternal (internalData + i * scanLineWRILength, scanLineWRILength * sizeof (Byte));
00753 
00754                 // write padding for scanline
00755                 device.writeInternal (padding, (scanLineBMPLength - scanLineWRILength) * sizeof (Byte));
00756             }
00757 
00758             delete [] padding;
00759 
00760             device.setCache (NULL);
00761 
00762             delete [] colourIndex;
00763             delete [] internalData;
00764         }
00765 
00766         return true;
00767     }
00768 
00769     bool Image::writeToDevice (void)
00770     {
00771     CHECK_DEVICE;
00772 
00773     #ifdef DEBUG_IMAGE
00774         m_device->debug ("\n>>>> Image::writeToDevice <<<<\n");
00775     #endif
00776 
00777     #ifdef DEBUG_IMAGE
00778         Dump (mappingMode);
00779         //Dump (MFP_width); // will change below
00780         //Dump (MFP_height);
00781         Dump (MFP_unknown);
00782 
00783         Dump (indent);
00784         //Dump (width);
00785         //Dump (height);
00786         Dump (zero);
00787 
00788         Dump (numHeaderBytes);
00789         //Dump (numDataBytes);
00790         //Dump (horizontalScalingRel1000);
00791         //Dump (verticalScalingRel1000);
00792     #endif
00793 
00794         //
00795         // write data
00796         //
00797         //
00798         if (getIsWMF ())
00799         {
00800             // Header check
00801             WMFHeader wmfHeader;
00802             m_device->setCache (m_externalImage);
00803                 wmfHeader.setDevice (m_device);
00804                 if (!wmfHeader.readFromDevice ()) return false;
00805 
00806                 // TODO: fix this incorrect check (see wmf.cpp)
00807                 //if (wmfHeader.getFileSize () * sizeof (Word) != m_externalImageSize)
00808                 //  m_device->error (Error::Warn, "wmfHeader.fileSize != externalImageSize\n");
00809             m_device->setCache (NULL);
00810 
00811 
00812             //
00813             // set image dimensions
00814             //
00815 
00816             // entire BitmapHeader is unused with WMFs
00817             m_bmh->setWidth (0);
00818             m_bmh->setHeight (0);
00819             m_bmh->setWidthBytes (0);
00820             m_bmh->setNumPlanes (0);
00821             m_bmh->setBitsPerPixel (0);
00822 
00823             m_MFP_width = Word (Twip2Milli (m_originalWidth * 0.75) * 100.0);
00824             m_MFP_height = Word (Twip2Milli (m_originalHeight * 0.75) * 100.0);
00825 
00826             m_width = Word (m_displayedWidth);
00827             m_height = Word (m_displayedHeight);
00828 
00829             // not used by WMFs
00830             m_horizontalScalingRel1000 = m_verticalScalingRel1000 = 1000;
00831 
00832 
00833             // write header
00834             setNumDataBytes (m_externalImageSize);
00835             if (!ImageGenerated::writeToDevice ())
00836                 return false;
00837 
00838             // external=internal with WMF (i.e. we really do write a WMF)
00839             if (!m_device->writeInternal (m_externalImage, m_externalImageSize)) return false;
00840         }
00841         else    //  if (getIsBMP ())
00842         {
00843             m_device->setCache (m_externalImage);
00844 
00845             BMP_BitmapFileHeader fileHeader;
00846             fileHeader.setDevice (m_device);
00847             if (!fileHeader.readFromDevice ()) return false;
00848 
00849 
00850             /*Word colourTableSize = (1 << m_bmh->getNumPlanes ()) * BMP_BitmapColourIndex::s_size;
00851 
00852             // fileHeader
00853             DWord fileSize = BMP_BitmapFileHeader::s_size + BMP_BitmapInfoHeader::s_size
00854                                                 + colourTableSize
00855                                                 + (m_bmh->getHeight ()
00856                                                     * getBytesPerScanLine (m_bmh->getWidth (), m_bmh->getBitsPerPixel (), 4));
00857 
00858             fileHeader.setTotalBytes (fileSize);
00859             fileHeader.setActualImageOffset (BMP_BitmapFileHeader::s_size + BMP_BitmapInfoHeader::s_size
00860                                                         + colourTableSize);*/
00861 
00862             // infoHeader
00863             BMP_BitmapInfoHeader infoHeader;
00864             infoHeader.setDevice (m_device);
00865             if (!infoHeader.readFromDevice ()) return false;
00866 
00867             // write out each scanline
00868             // to .WRI (padded to 2) vs input BMP (padded to 4
00869             Word scanLineWRILength = getBytesPerScanLine (infoHeader.getWidth (), infoHeader.getBitsPerPixel (), 2);
00870             Word scanLineBMPLength = getBytesPerScanLine (infoHeader.getWidth (), infoHeader.getBitsPerPixel (), 4);
00871 
00872             if (infoHeader.getWidth () != Word (Twip2Point (m_originalWidth)))
00873                 ErrorAndQuit (Error::Warn, "infoHeader width != m_originalWidth\n");
00874             if (infoHeader.getHeight () != Word (Twip2Point (m_originalHeight)))
00875                 ErrorAndQuit (Error::Warn, "infoHeader.height != m_originalHeight\n");
00876 
00877             m_bmh->setWidth (infoHeader.getWidth ());
00878             m_bmh->setHeight (infoHeader.getHeight ());
00879             m_bmh->setWidthBytes (scanLineWRILength);
00880             if (infoHeader.getNumPlanes () != 1)
00881                 ErrorAndQuit (Error::InvalidFormat, "infoHeader.getNumPlanes() != 1\n");
00882             m_bmh->setNumPlanes (infoHeader.getNumPlanes ());
00883             m_bmh->setBitsPerPixel (infoHeader.getBitsPerPixel ());
00884             if (infoHeader.getCompression () != 0)  // BI_RGB (uncompressed)
00885                 ErrorAndQuit (Error::Unsupported, "compressed bitmaps unsupported\n");
00886             //infoHeader.setSizeImage (0);      // lazy
00887             //infoHeader.setXPixelsPerMeter (0), infoHeader.setYPixelsPerMeter (0);
00888             infoHeader.setColoursUsed (1 << infoHeader.getBitsPerPixel ()); // make life easier
00889             //infoHeader.setColoursImportant (infoHeader.getColoursUsed ());
00890 
00891             if (infoHeader.getColoursUsed () != 2)
00892                 ErrorAndQuit (Error::Unsupported, "can't save colour BMPs, use WMFs for that purpose\n");
00893 
00894             // colourTable
00895             BMP_BitmapColourIndex *colourIndex = new BMP_BitmapColourIndex [infoHeader.getColoursUsed ()];
00896             if (!colourIndex)
00897                 ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for colourIndex[]\n");
00898             colourIndex [0].setDevice (m_device);
00899             if (!colourIndex [0].readFromDevice ()) return false;
00900             if (colourIndex [0].getRed () != 0 || colourIndex [0].getGreen () != 0 || colourIndex [0].getBlue () != 0)
00901                 m_device->error (Error::Warn, "black not black\n");
00902             colourIndex [1].setDevice (m_device);
00903             if (!colourIndex [1].readFromDevice ()) return false;
00904             if (colourIndex [1].getRed () != 0xFF || colourIndex [1].getGreen () != 0xFF || colourIndex [1].getBlue () != 0xFF)
00905                 m_device->error (Error::Warn, "white not white\n");
00906 
00907             // finish reading from m_externalImage
00908             m_device->setCache (NULL);
00909 
00910 
00911             //
00912             // set image dimensions
00913             //
00914 
00915             m_MFP_width = Word (Twip2Point (m_originalWidth) * 2.64);
00916             m_MFP_height = Word (Twip2Point (m_originalHeight) * 2.64);
00917 
00918             // BMPs don't use
00919             m_width = 0, m_height = 0;
00920 
00921             m_horizontalScalingRel1000 = Word (m_displayedWidth * 1.38889 * 1000.0 / m_originalWidth);
00922             m_verticalScalingRel1000 = Word (m_displayedHeight * 1.38889 * 1000.0 / m_originalHeight);
00923 
00924 
00925             // write header
00926             setNumDataBytes (infoHeader.getHeight () * scanLineBMPLength);
00927             if (!ImageGenerated::writeToDevice ())
00928                 return false;
00929 
00930             // the DIB is upside-down...
00931             Byte *bmpData = m_externalImage + fileHeader.getActualImageOffset () + (infoHeader.getHeight () - 1) * scanLineBMPLength;
00932             for (int i = (int) infoHeader.getHeight () - 1; i >= 0; i--)
00933             {
00934                 // write bitmap scanline (padded to 2)
00935                 //if (!m_device->writeInternal (m_externalImage + fileHeader.getActualImageOffset () + i * scanLineBMPLength, scanLineWRILength))
00936                 if (!m_device->writeInternal (bmpData, scanLineWRILength))
00937                     return false;
00938 
00939                 bmpData -= scanLineBMPLength;
00940             }
00941 
00942             delete [] colourIndex;
00943         }
00944 
00945         return true;
00946     }
00947 
00948 
00949     OLE::OLE () : m_externalObject (NULL),
00950                         m_externalObjectSize (0), m_externalObjectUpto (0)
00951     {
00952     }
00953 
00954     OLE::~OLE ()
00955     {
00956         delete [] m_externalObject;
00957     }
00958 
00959     OLE &OLE::operator= (const OLE &rhs)
00960     {
00961         if (this == &rhs)
00962             return *this;
00963 
00964         OLEGenerated::operator= (rhs);
00965 
00966         m_externalObjectSize = rhs.m_externalObjectSize;
00967         m_externalObjectUpto = rhs.m_externalObjectUpto;
00968 
00969         delete [] m_externalObject;
00970         m_externalObject = new Byte [m_externalObjectSize];
00971         if (!m_externalObject)
00972             return *this;  // TODO: error check
00973 
00974         if (rhs.m_externalObject)
00975             memcpy (m_externalObject, rhs.m_externalObject, m_externalObjectUpto);
00976 
00977         return *this;
00978     }
00979 
00980     bool OLE::readFromDevice (void)
00981     {
00982     CHECK_DEVICE;
00983 
00984     #ifdef DEBUG_OBJECT
00985         m_device->debug ("\n<<<< OLE::readFromDevice >>>>\n");
00986     #endif
00987 
00988         if (!OLEGenerated::readFromDevice ())
00989             return false;
00990 
00991     #ifdef DEBUG_OBJECT
00992         Dump (zero);
00993 
00994         switch (m_objectType)
00995         {
00996         case OLEType::Static:
00997             m_device->debug ("\tobjectType: 1 - static\n");
00998             break;
00999         case OLEType::Embedded:
01000             m_device->debug ("\tobjectType: 2 - embedded\n");
01001             break;
01002         case OLEType::Link:
01003             m_device->debug ("\tobjectType: 3 - link\n");
01004             break;
01005         }
01006 
01007         Dump (indent);
01008         Dump (width);
01009         Dump (height);
01010         Dump (zero2);
01011         Dump (numDataBytes);
01012         Dump (zero3);
01013         Dump (objectName);
01014         Dump (zero4);
01015         Dump (numHeaderBytes);
01016         Dump (zero5);
01017         Dump (widthScaledRel1000);
01018         Dump (heightScaledRel1000);
01019     #endif
01020 
01021         // OPT: TODO: this is dumb, we read it only to give it back to the parser who tells the generator to write it
01022         m_externalObject = new Byte [m_externalObjectSize = getNumDataBytes ()];
01023         if (!m_externalObject)
01024             ErrorAndQuit (Error::OutOfMemory, "could not allocate memory for external OLE object\n");
01025 
01026         if (!m_device->readInternal (m_externalObject, m_externalObjectSize))
01027             return false;
01028 
01029         return true;
01030     }
01031 
01032     bool OLE::writeToDevice (void)
01033     {
01034     CHECK_DEVICE;
01035 
01036     #ifdef DEBUG_OBJECT
01037         m_device->debug ("\n>>>> OLE::writeToDevice <<<<\n");
01038     #endif
01039 
01040     #ifdef DEBUG_OBJECT
01041         Dump (zero);
01042 
01043         switch (m_objectType)
01044         {
01045         case OLEType::Static:
01046             m_device->debug ("\tobjectType: 1 - static\n");
01047             break;
01048         case OLEType::Embedded:
01049             m_device->debug ("\tobjectType: 2 - embedded\n");
01050             break;
01051         case OLEType::Link:
01052             m_device->debug ("\tobjectType: 3 - link\n");
01053             break;
01054         }
01055 
01056         Dump (indent);
01057         Dump (width);
01058         Dump (height);
01059         Dump (zero2);
01060         Dump (numDataBytes);
01061         Dump (zero3);
01062         Dump (objectName);
01063         Dump (zero4);
01064         Dump (numHeaderBytes);
01065         Dump (zero5);
01066         Dump (widthScaledRel1000);
01067         Dump (heightScaledRel1000);
01068     #endif
01069 
01070         // write header
01071         if (!OLEGenerated::writeToDevice ())
01072             return false;
01073 
01074         // write data
01075         if (!m_device->writeInternal (m_externalObject, m_externalObjectSize))
01076             return false;
01077 
01078         return true;
01079     }
01080 
01081 }   // namespace MSWrite    {
01082 
01083 // end of structures.cpp
KDE Home | KDE Accessibility Home | Description of Access Keys