LCOV - code coverage report
Current view: top level - libreoffice/workdir/unxlngi6.pro/UnpackedTarball/mspub/src/lib - MSPUBParser2k.cpp (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 0 383 0.0 %
Date: 2012-12-17 Functions: 0 32 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* libmspub
       3             :  * Version: MPL 1.1 / GPLv2+ / LGPLv2+
       4             :  *
       5             :  * The contents of this file are subject to the Mozilla Public License Version
       6             :  * 1.1 (the "License"); you may not use this file except in compliance with
       7             :  * the License or as specified alternatively below. You may obtain a copy of
       8             :  * the License at http://www.mozilla.org/MPL/
       9             :  *
      10             :  * Software distributed under the License is distributed on an "AS IS" basis,
      11             :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12             :  * for the specific language governing rights and limitations under the
      13             :  * License.
      14             :  *
      15             :  * Major Contributor(s):
      16             :  * Copyright (C) 2012 Brennan Vincent <brennanv@email.arizona.edu>
      17             :  * Copyright (C) 2012 Fridrich Strba <fridrich.strba@bluewin.ch>
      18             :  *
      19             :  * All Rights Reserved.
      20             :  *
      21             :  * For minor contributions see the git repository.
      22             :  *
      23             :  * Alternatively, the contents of this file may be used under the terms of
      24             :  * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
      25             :  * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
      26             :  * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
      27             :  * instead of those above.
      28             :  */
      29             : 
      30             : #include <algorithm>
      31             : 
      32             : #include <boost/shared_ptr.hpp>
      33             : 
      34             : #include <libwpd-stream/libwpd-stream.h>
      35             : 
      36             : #include "MSPUBParser2k.h"
      37             : #include "ColorReference.h"
      38             : #include "ShapeType.h"
      39             : #include "libmspub_utils.h"
      40             : #include "MSPUBCollector.h"
      41             : 
      42           0 : libmspub::MSPUBParser2k::MSPUBParser2k(WPXInputStream *input, MSPUBCollector *collector)
      43             :   : MSPUBParser(input, collector),
      44             :     m_imageDataChunkIndices(),
      45             :     m_quillColorEntries(),
      46           0 :     m_chunkChildIndicesById()
      47             : {
      48           0 : }
      49             : 
      50           0 : unsigned libmspub::MSPUBParser2k::getColorIndexByQuillEntry(unsigned entry)
      51             : {
      52           0 :   unsigned translation = translate2kColorReference(entry);
      53           0 :   std::vector<unsigned>::const_iterator i_entry = std::find(m_quillColorEntries.begin(), m_quillColorEntries.end(), translation);
      54           0 :   if (i_entry == m_quillColorEntries.end())
      55             :   {
      56           0 :     m_quillColorEntries.push_back(translation);
      57           0 :     m_collector->addTextColor(ColorReference(translation));
      58           0 :     return m_quillColorEntries.size() - 1;
      59             :   }
      60           0 :   return i_entry - m_quillColorEntries.begin();
      61             : }
      62             : 
      63           0 : libmspub::MSPUBParser2k::~MSPUBParser2k()
      64             : {
      65           0 : }
      66             : 
      67             : // Takes a line width specifier in Pub2k format and translates it into quarter points
      68           0 : unsigned short translateLineWidth(unsigned char lineWidth)
      69             : {
      70           0 :   if (lineWidth == 0x81)
      71             :   {
      72           0 :     return 0;
      73             :   }
      74           0 :   else if (lineWidth > 0x81)
      75             :   {
      76           0 :     return ((lineWidth - 0x81) / 3) * 4 + ((lineWidth - 0x81) % 3) + 1;
      77             :   }
      78             :   else
      79             :   {
      80           0 :     return lineWidth * 4;
      81             :   }
      82             : }
      83             : 
      84           0 : libmspub::Color libmspub::MSPUBParser2k::getColorBy2kHex(unsigned hex)
      85             : {
      86           0 :   switch ((hex >> 24) & 0xFF)
      87             :   {
      88             :   case 0x80:
      89             :   case 0x00:
      90           0 :     return getColorBy2kIndex(hex & 0xFF);
      91             :   case 0x90:
      92             :   case 0x20:
      93           0 :     return Color(hex & 0xFF, (hex >> 8) & 0xFF, (hex >> 16) & 0xFF);
      94             :   default:
      95           0 :     return Color();
      96             :   }
      97             : }
      98             : 
      99           0 : libmspub::Color libmspub::MSPUBParser2k::getColorBy2kIndex(unsigned char index)
     100             : {
     101           0 :   switch(index)
     102             :   {
     103             :   case 0x00:
     104           0 :     return Color(0, 0, 0);
     105             :   case 0x01:
     106           0 :     return Color(0xff, 0xff, 0xff);
     107             :   case 0x02:
     108           0 :     return Color(0xff, 0, 0);
     109             :   case 0x03:
     110           0 :     return Color(0, 0xff, 0);
     111             :   case 0x04:
     112           0 :     return Color(0, 0, 0xff);
     113             :   case 0x05:
     114           0 :     return Color(0xff, 0xff, 0);
     115             :   case 0x06:
     116           0 :     return Color(0, 0xff, 0xff);
     117             :   case 0x07:
     118           0 :     return Color(0xff, 0, 0xff);
     119             :   case 0x08:
     120           0 :     return Color(128, 128, 128);
     121             :   case 0x09:
     122           0 :     return Color(192, 192, 192);
     123             :   case 0x0A:
     124           0 :     return Color(128, 0, 0);
     125             :   case 0x0B:
     126           0 :     return Color(0, 128, 0);
     127             :   case 0x0C:
     128           0 :     return Color(0, 0, 128);
     129             :   case 0x0D:
     130           0 :     return Color(128, 128, 0);
     131             :   case 0x0E:
     132           0 :     return Color(0, 128, 128);
     133             :   case 0x0F:
     134           0 :     return Color(128, 0, 128);
     135             :   case 0x10:
     136           0 :     return Color(255, 153, 51);
     137             :   case 0x11:
     138           0 :     return Color(51, 0, 51);
     139             :   case 0x12:
     140           0 :     return Color(0, 0, 153);
     141             :   case 0x13:
     142           0 :     return Color(0, 153, 0);
     143             :   case 0x14:
     144           0 :     return Color(153, 153, 0);
     145             :   case 0x15:
     146           0 :     return Color(204, 102, 0);
     147             :   case 0x16:
     148           0 :     return Color(153, 0, 0);
     149             :   case 0x17:
     150           0 :     return Color(204, 153, 204);
     151             :   case 0x18:
     152           0 :     return Color(102, 102, 255);
     153             :   case 0x19:
     154           0 :     return Color(102, 255, 102);
     155             :   case 0x1A:
     156           0 :     return Color(255, 255, 153);
     157             :   case 0x1B:
     158           0 :     return Color(255, 204, 153);
     159             :   case 0x1C:
     160           0 :     return Color(255, 102, 102);
     161             :   case 0x1D:
     162           0 :     return Color(255, 153, 0);
     163             :   case 0x1E:
     164           0 :     return Color(0, 102, 255);
     165             :   case 0x1F:
     166           0 :     return Color(255, 204, 0);
     167             :   case 0x20:
     168           0 :     return Color(153, 0, 51);
     169             :   case 0x21:
     170           0 :     return Color(102, 51, 0);
     171             :   case 0x22:
     172           0 :     return Color(66, 66, 66);
     173             :   case 0x23:
     174           0 :     return Color(255, 153, 102);
     175             :   case 0x24:
     176           0 :     return Color(153, 51, 0);
     177             :   case 0x25:
     178           0 :     return Color(255, 102, 0);
     179             :   case 0x26:
     180           0 :     return Color(51, 51, 0);
     181             :   case 0x27:
     182           0 :     return Color(153, 204, 0);
     183             :   case 0x28:
     184           0 :     return Color(255, 255, 153);
     185             :   case 0x29:
     186           0 :     return Color(0, 51, 0);
     187             :   case 0x2A:
     188           0 :     return Color(51, 153, 102);
     189             :   case 0x2B:
     190           0 :     return Color(204, 255, 204);
     191             :   case 0x2C:
     192           0 :     return Color(0, 51, 102);
     193             :   case 0x2D:
     194           0 :     return Color(51, 204, 204);
     195             :   case 0x2E:
     196           0 :     return Color(204, 255, 255);
     197             :   case 0x2F:
     198           0 :     return Color(51, 102, 255);
     199             :   case 0x30:
     200           0 :     return Color(0, 204, 255);
     201             :   case 0x31:
     202           0 :     return Color(153, 204, 255);
     203             :   case 0x32:
     204           0 :     return Color(51, 51, 153);
     205             :   case 0x33:
     206           0 :     return Color(102, 102, 153);
     207             :   case 0x34:
     208           0 :     return Color(153, 51, 102);
     209             :   case 0x35:
     210           0 :     return Color(204, 153, 255);
     211             :   case 0x36:
     212           0 :     return Color(51, 51, 51);
     213             :   case 0x37:
     214           0 :     return Color(150, 150, 150);
     215             :   default:
     216           0 :     return Color();
     217             :   }
     218             : }
     219             : 
     220             : // takes a color reference in 2k format and translates it into 2k2 format that collector understands.
     221           0 : unsigned libmspub::MSPUBParser2k::translate2kColorReference(unsigned ref2k)
     222             : {
     223           0 :   switch ((ref2k >> 24) & 0xFF)
     224             :   {
     225             :   case 0xC0: //index into user palette
     226             :   case 0xE0:
     227           0 :     return (ref2k & 0xFF) | (0x08 << 24);
     228             :   default:
     229             :   {
     230           0 :     Color c = getColorBy2kHex(ref2k);
     231           0 :     return (c.r) | (c.g << 8) | (c.b << 16);
     232             :   }
     233             :   }
     234             : }
     235             : 
     236             : //FIXME: Valek found different values; what does this depend on?
     237           0 : libmspub::ShapeType libmspub::MSPUBParser2k::getShapeType(unsigned char shapeSpecifier)
     238             : {
     239           0 :   switch (shapeSpecifier)
     240             :   {
     241             :   case 0x1:
     242           0 :     return RIGHT_TRIANGLE;
     243             :     /*
     244             :     case 0x2:
     245             :       return GENERAL_TRIANGLE;
     246             :     */
     247             :   case 0x3:
     248           0 :     return UP_ARROW;
     249             :   case 0x4:
     250           0 :     return STAR;
     251             :   case 0x5:
     252           0 :     return HEART;
     253             :   case 0x6:
     254           0 :     return ISOCELES_TRIANGLE;
     255             :   case 0x7:
     256           0 :     return PARALLELOGRAM;
     257             :     /*
     258             :     case 0x8:
     259             :       return TILTED_TRAPEZOID;
     260             :     */
     261             :   case 0x9:
     262           0 :     return UP_DOWN_ARROW;
     263             :   case 0xA:
     264           0 :     return SEAL_16;
     265             :   case 0xB:
     266           0 :     return WAVE;
     267             :   case 0xC:
     268           0 :     return DIAMOND;
     269             :   case 0xD:
     270           0 :     return TRAPEZOID;
     271             :   case 0xE:
     272           0 :     return CHEVRON;
     273             :   case 0xF:
     274           0 :     return BENT_ARROW;
     275             :   case 0x10:
     276           0 :     return SEAL_24;
     277             :     /*
     278             :     case 0x11:
     279             :       return PIE;
     280             :     */
     281             :   case 0x12:
     282           0 :     return PENTAGON;
     283             :   case 0x13:
     284           0 :     return HOME_PLATE;
     285             :     /*
     286             :     case 0x14:
     287             :       return NOTCHED_TRIANGLE;
     288             :     */
     289             :   case 0x15:
     290           0 :     return U_TURN_ARROW;
     291             :   case 0x16:
     292           0 :     return IRREGULAR_SEAL_1;
     293             :     /*
     294             :     case 0x17:
     295             :       return CHORD;
     296             :     */
     297             :   case 0x18:
     298           0 :     return HEXAGON;
     299             :     /*
     300             :     case 0x19:
     301             :       return NOTCHED_RECTANGLE;
     302             :     */
     303             :     /*
     304             :     case 0x1A:
     305             :       return W_SHAPE; //This is a bizarre shape; the number of vertices depends on one of the adjust values.
     306             :                       //We need to refactor our escher shape drawing routines before we can handle it.
     307             :     */
     308             :     /*
     309             :     case 0x1B:
     310             :       return ROUND_RECT_CALLOUT_2K; //This is not quite the same as the round rect. found in 2k2 and above.
     311             :     */
     312             :   case 0x1C:
     313           0 :     return IRREGULAR_SEAL_2;
     314             :   case 0x1D:
     315           0 :     return BLOCK_ARC;
     316             :   case 0x1E:
     317           0 :     return OCTAGON;
     318             :   case 0x1F:
     319           0 :     return PLUS;
     320             :   case 0x20:
     321           0 :     return CUBE;
     322             :     /*
     323             :     case 0x21:
     324             :       return OVAL_CALLOUT_2K; //Not sure yet if this is the same as the 2k2 one.
     325             :     */
     326             :   case 0x22:
     327           0 :     return LIGHTNING_BOLT;
     328             :   default:
     329           0 :     return UNKNOWN_SHAPE;
     330             :   }
     331             : }
     332             : 
     333           0 : void libmspub::MSPUBParser2k::parseContentsTextIfNecessary(WPXInputStream *)
     334             : {
     335           0 : }
     336             : 
     337           0 : bool libmspub::MSPUBParser2k::parseContents(WPXInputStream *input)
     338             : {
     339           0 :   parseContentsTextIfNecessary(input);
     340           0 :   input->seek(0x16, WPX_SEEK_SET);
     341           0 :   unsigned trailerOffset = readU32(input);
     342           0 :   input->seek(trailerOffset, WPX_SEEK_SET);
     343           0 :   unsigned numBlocks = readU16(input);
     344           0 :   unsigned chunkOffset = 0;
     345           0 :   for (unsigned i = 0; i < numBlocks; ++i)
     346             :   {
     347           0 :     input->seek(input->tell() + 2, WPX_SEEK_SET);
     348           0 :     unsigned short id = readU16(input);
     349           0 :     unsigned short parent = readU16(input);
     350           0 :     chunkOffset = readU32(input);
     351           0 :     if (m_contentChunks.size() > 0)
     352             :     {
     353           0 :       m_contentChunks.back().end = chunkOffset;
     354             :     }
     355           0 :     unsigned offset = input->tell();
     356           0 :     input->seek(chunkOffset, WPX_SEEK_SET);
     357           0 :     unsigned short typeMarker = readU16(input);
     358           0 :     input->seek(offset, WPX_SEEK_SET);
     359           0 :     switch (typeMarker)
     360             :     {
     361             :     case 0x0014:
     362             :       MSPUB_DEBUG_MSG(("Found page chunk of id 0x%x and parent 0x%x\n", id, parent));
     363           0 :       m_contentChunks.push_back(ContentChunkReference(PAGE, chunkOffset, 0, id, parent));
     364           0 :       m_pageChunkIndices.push_back(unsigned(m_contentChunks.size() - 1));
     365           0 :       m_chunkChildIndicesById[parent].push_back(unsigned(m_contentChunks.size() - 1));
     366           0 :       break;
     367             :     case 0x0015:
     368             :       MSPUB_DEBUG_MSG(("Found document chunk of id 0x%x and parent 0x%x\n", id, parent));
     369           0 :       m_contentChunks.push_back(ContentChunkReference(DOCUMENT, chunkOffset, 0, id, parent));
     370           0 :       m_documentChunkIndex = unsigned(m_contentChunks.size() - 1);
     371           0 :       m_chunkChildIndicesById[parent].push_back(unsigned(m_contentChunks.size() - 1));
     372           0 :       break;
     373             :     case 0x0002:
     374             :       MSPUB_DEBUG_MSG(("Found image_2k chunk of id 0x%x and parent 0x%x\n", id, parent));
     375           0 :       m_contentChunks.push_back(ContentChunkReference(IMAGE_2K, chunkOffset, 0, id, parent));
     376           0 :       m_shapeChunkIndices.push_back(unsigned(m_contentChunks.size() - 1));
     377           0 :       m_chunkChildIndicesById[parent].push_back(unsigned(m_contentChunks.size() - 1));
     378           0 :       break;
     379             :     case 0x0021:
     380             :       MSPUB_DEBUG_MSG(("Found image_2k_data chunk of id 0x%x and parent 0x%x\n", id, parent));
     381           0 :       m_contentChunks.push_back(ContentChunkReference(IMAGE_2K_DATA, chunkOffset, 0, id, parent));
     382           0 :       m_imageDataChunkIndices.push_back(unsigned(m_contentChunks.size() - 1));
     383           0 :       m_chunkChildIndicesById[parent].push_back(unsigned(m_contentChunks.size() - 1));
     384           0 :       break;
     385             :     case 0x0000:
     386             :     case 0x0004:
     387             :     case 0x0005:
     388             :     case 0x0006:
     389             :     case 0x0007:
     390             :     case 0x0008:
     391             :       MSPUB_DEBUG_MSG(("Found shape chunk of id 0x%x and parent 0x%x\n", id, parent));
     392           0 :       m_contentChunks.push_back(ContentChunkReference(SHAPE, chunkOffset, 0, id, parent));
     393           0 :       m_shapeChunkIndices.push_back(unsigned(m_contentChunks.size() - 1));
     394           0 :       m_chunkChildIndicesById[parent].push_back(unsigned(m_contentChunks.size() - 1));
     395           0 :       break;
     396             :     case 0x0047:
     397             :       MSPUB_DEBUG_MSG(("Found palette chunk of id 0x%x and parent 0x%x\n", id, parent));
     398           0 :       m_contentChunks.push_back(ContentChunkReference(PALETTE, chunkOffset, 0, id, parent));
     399           0 :       m_paletteChunkIndices.push_back(unsigned(m_contentChunks.size() - 1));
     400           0 :       m_chunkChildIndicesById[parent].push_back(unsigned(m_contentChunks.size() - 1));
     401           0 :       break;
     402             :     case 0x000F:
     403             :       MSPUB_DEBUG_MSG(("Found group chunk of id 0x%x and parent 0x%x\n", id, parent));
     404           0 :       m_contentChunks.push_back(ContentChunkReference(GROUP, chunkOffset, 0, id, parent));
     405           0 :       m_shapeChunkIndices.push_back(unsigned(m_contentChunks.size() - 1));
     406           0 :       m_chunkChildIndicesById[parent].push_back(unsigned(m_contentChunks.size() - 1));
     407           0 :       break;
     408             :     default:
     409             :       MSPUB_DEBUG_MSG(("Found unknown chunk of id 0x%x and parent 0x%x\n", id, parent));
     410           0 :       m_contentChunks.push_back(ContentChunkReference(UNKNOWN_CHUNK, chunkOffset, 0, id, parent));
     411           0 :       m_unknownChunkIndices.push_back(unsigned(m_contentChunks.size() - 1));
     412           0 :       m_chunkChildIndicesById[parent].push_back(unsigned(m_contentChunks.size() - 1));
     413           0 :       break;
     414             :     }
     415             :   }
     416           0 :   if (m_contentChunks.size() > 0)
     417             :   {
     418           0 :     m_contentChunks.back().end = chunkOffset;
     419             :   }
     420             : 
     421           0 :   if (!parseDocument(input))
     422             :   {
     423             :     MSPUB_DEBUG_MSG(("No document chunk found.\n"));
     424           0 :     return false;
     425             :   }
     426             : 
     427             : 
     428           0 :   for (unsigned i = 0; i < m_paletteChunkIndices.size(); ++i)
     429             :   {
     430           0 :     const ContentChunkReference &chunk = m_contentChunks.at(m_paletteChunkIndices[i]);
     431           0 :     input->seek(chunk.offset, WPX_SEEK_SET);
     432           0 :     input->seek(0xA0, WPX_SEEK_CUR);
     433           0 :     for (unsigned j = 0; j < 8; ++j)
     434             :     {
     435           0 :       unsigned hex = readU32(input);
     436           0 :       Color color = getColorBy2kHex(hex);
     437           0 :       m_collector->addPaletteColor(color);
     438             :     }
     439             :   }
     440             : 
     441           0 :   for (unsigned i = 0; i < m_imageDataChunkIndices.size(); ++i)
     442             :   {
     443           0 :     const ContentChunkReference &chunk = m_contentChunks.at(m_imageDataChunkIndices[i]);
     444           0 :     input->seek(chunk.offset + 4, WPX_SEEK_SET);
     445           0 :     unsigned toRead = readU32(input);
     446           0 :     WPXBinaryData img;
     447           0 :     while (toRead > 0 && stillReading(input, (unsigned long)-1))
     448             :     {
     449           0 :       unsigned long howManyRead = 0;
     450           0 :       const unsigned char *buf = input->read(toRead, howManyRead);
     451           0 :       img.append(buf, howManyRead);
     452           0 :       toRead -= howManyRead;
     453             :     }
     454           0 :     m_collector->addImage(++m_lastAddedImage, WMF, img);
     455           0 :   }
     456             : 
     457           0 :   for (unsigned i = 0; i < m_shapeChunkIndices.size(); ++i)
     458             :   {
     459           0 :     parse2kShapeChunk(m_contentChunks.at(m_shapeChunkIndices[i]), input);
     460             :   }
     461             : 
     462           0 :   return true;
     463             : }
     464             : 
     465           0 : bool libmspub::MSPUBParser2k::parseDocument(WPXInputStream *input)
     466             : {
     467           0 :   if (m_documentChunkIndex.is_initialized())
     468             :   {
     469           0 :     input->seek(m_contentChunks[m_documentChunkIndex.get()].offset, WPX_SEEK_SET);
     470           0 :     input->seek(0x14, WPX_SEEK_CUR);
     471           0 :     unsigned width = readU32(input);
     472           0 :     unsigned height = readU32(input);
     473           0 :     m_collector->setWidthInEmu(width);
     474           0 :     m_collector->setHeightInEmu(height);
     475           0 :     return true;
     476             :   }
     477           0 :   return false;
     478             : }
     479             : 
     480           0 : void libmspub::MSPUBParser2k::parseShapeRotation(WPXInputStream *input, bool isGroup, bool isLine,
     481             :     unsigned seqNum, unsigned chunkOffset)
     482             : {
     483           0 :   input->seek(chunkOffset + 4, WPX_SEEK_SET);
     484             :   // shape transforms are NOT compounded with group transforms. They are equal to what they would be
     485             :   // if the shape were not part of a group at all. This is different from how MSPUBCollector handles rotations;
     486             :   // we work around the issue by simply not setting the rotation of any group, thereby letting it default to zero.
     487             :   //
     488             :   // Furthermore, line rotations are redundant and need to be treated as zero.
     489           0 :   unsigned short counterRotationInDegreeTenths = readU16(input);
     490           0 :   if (!isGroup && !isLine)
     491             :   {
     492           0 :     m_collector->setShapeRotation(seqNum, 360. - double(counterRotationInDegreeTenths) / 10);
     493             :   }
     494           0 : }
     495             : 
     496           0 : bool libmspub::MSPUBParser2k::parse2kShapeChunk(const ContentChunkReference &chunk, WPXInputStream *input,
     497             :     boost::optional<unsigned> pageSeqNum, bool topLevelCall)
     498             : {
     499           0 :   unsigned page = pageSeqNum.get_value_or(chunk.parentSeqNum);
     500           0 :   input->seek(chunk.offset, WPX_SEEK_SET);
     501           0 :   if (topLevelCall)
     502             :   {
     503             :     // ignore non top level shapes
     504           0 :     int i_page = -1;
     505           0 :     for (unsigned j = 0; j < m_pageChunkIndices.size(); ++j)
     506             :     {
     507           0 :       unsigned pageIndex = m_pageChunkIndices[j];
     508           0 :       if (m_contentChunks.at(pageIndex).seqNum == chunk.parentSeqNum)
     509             :       {
     510           0 :         i_page = pageIndex;
     511           0 :         break;
     512             :       }
     513             :     }
     514           0 :     if (i_page == -1)
     515             :     {
     516           0 :       return false;
     517             :     }
     518           0 :     if (getPageTypeBySeqNum(m_contentChunks[i_page].seqNum) != NORMAL)
     519             :     {
     520           0 :       return false;
     521             :     }
     522             :     // if the parent of this is a page and hasn't yet been added, then add it.
     523           0 :     if (!m_collector->hasPage(chunk.parentSeqNum))
     524             :     {
     525           0 :       m_collector->addPage(chunk.parentSeqNum);
     526             :     }
     527             :   }
     528           0 :   m_collector->setShapePage(chunk.seqNum, page);
     529           0 :   m_collector->setShapeBorderPosition(chunk.seqNum, INSIDE_SHAPE); // This appears to be the only possibility for MSPUB2k
     530           0 :   bool isImage = false;
     531           0 :   bool isRectangle = false;
     532           0 :   bool isGroup = false;
     533           0 :   bool isLine = false;
     534           0 :   unsigned flagsOffset(0); // ? why was this changed from boost::optional ?
     535           0 :   parseShapeType(input, chunk.seqNum, chunk.offset, isGroup, isLine, isImage, isRectangle, flagsOffset);
     536           0 :   parseShapeRotation(input, isGroup, isLine, chunk.seqNum, chunk.offset);
     537           0 :   parseShapeCoordinates(input, chunk.seqNum, chunk.offset);
     538           0 :   parseShapeFlips(input, flagsOffset, chunk.seqNum, chunk.offset);
     539           0 :   if (isGroup)
     540             :   {
     541           0 :     return parseGroup(input, chunk.seqNum, page);
     542             :   }
     543           0 :   if (isImage)
     544             :   {
     545           0 :     assignShapeImgIndex(chunk.seqNum);
     546             :   }
     547             :   else
     548             :   {
     549           0 :     parseShapeFill(input, chunk.seqNum, chunk.offset);
     550             :   }
     551           0 :   parseShapeLine(input, isRectangle, chunk.offset, chunk.seqNum);
     552           0 :   m_collector->setShapeOrder(chunk.seqNum);
     553           0 :   return true;
     554             : }
     555             : 
     556           0 : unsigned libmspub::MSPUBParser2k::getShapeFillTypeOffset() const
     557             : {
     558           0 :   return 0x2A;
     559             : }
     560             : 
     561           0 : unsigned libmspub::MSPUBParser2k::getShapeFillColorOffset() const
     562             : {
     563           0 :   return 0x22;
     564             : }
     565             : 
     566           0 : void libmspub::MSPUBParser2k::parseShapeFill(WPXInputStream *input, unsigned seqNum, unsigned chunkOffset)
     567             : {
     568           0 :   input->seek(chunkOffset + getShapeFillTypeOffset(), WPX_SEEK_SET);
     569           0 :   unsigned char fillType = readU8(input);
     570           0 :   if (fillType == 2) // other types are gradients and patterns which are not implemented yet. 0 is no fill.
     571             :   {
     572           0 :     input->seek(chunkOffset + getShapeFillColorOffset(), WPX_SEEK_SET);
     573           0 :     unsigned fillColorReference = readU32(input);
     574           0 :     unsigned translatedFillColorReference = translate2kColorReference(fillColorReference);
     575           0 :     m_collector->setShapeFill(seqNum, boost::shared_ptr<Fill>(new SolidFill(ColorReference(translatedFillColorReference), 1, m_collector)), false);
     576             :   }
     577           0 : }
     578             : 
     579           0 : bool libmspub::MSPUBParser2k::parseGroup(WPXInputStream *input, unsigned seqNum, unsigned page)
     580             : {
     581           0 :   bool retVal = true;
     582           0 :   m_collector->beginGroup();
     583           0 :   m_collector->setCurrentGroupSeqNum(seqNum);
     584           0 :   for (unsigned i = 0; i < m_chunkChildIndicesById[seqNum].size(); ++i)
     585             :   {
     586           0 :     const ContentChunkReference &childChunk = m_contentChunks.at(m_chunkChildIndicesById[seqNum][i]);
     587           0 :     if (childChunk.type == SHAPE || childChunk.type == GROUP)
     588             :     {
     589           0 :       retVal = retVal && parse2kShapeChunk(childChunk, input, page, false);
     590             :     }
     591             :   }
     592           0 :   m_collector->endGroup();
     593           0 :   return retVal;
     594             : }
     595             : 
     596           0 : void libmspub::MSPUBParser2k::assignShapeImgIndex(unsigned seqNum)
     597             : {
     598           0 :   int i_dataIndex = -1;
     599           0 :   for (unsigned j = 0; j < m_imageDataChunkIndices.size(); ++j)
     600             :   {
     601           0 :     if (m_contentChunks.at(m_imageDataChunkIndices[j]).parentSeqNum == seqNum)
     602             :     {
     603           0 :       i_dataIndex = j;
     604           0 :       break;
     605             :     }
     606             :   }
     607           0 :   if (i_dataIndex >= 0)
     608             :   {
     609           0 :     m_collector->setShapeImgIndex(seqNum, i_dataIndex + 1);
     610             :   }
     611           0 : }
     612             : 
     613           0 : void libmspub::MSPUBParser2k::parseShapeCoordinates(WPXInputStream *input, unsigned seqNum,
     614             :     unsigned chunkOffset)
     615             : {
     616           0 :   input->seek(chunkOffset + 6, WPX_SEEK_SET);
     617           0 :   int xs = translateCoordinateIfNecessary(readS32(input));
     618           0 :   int ys = translateCoordinateIfNecessary(readS32(input));
     619           0 :   int xe = translateCoordinateIfNecessary(readS32(input));
     620           0 :   int ye = translateCoordinateIfNecessary(readS32(input));
     621           0 :   m_collector->setShapeCoordinatesInEmu(seqNum, xs, ys, xe, ye);
     622           0 : }
     623             : 
     624           0 : int libmspub::MSPUBParser2k::translateCoordinateIfNecessary(int coordinate) const
     625             : {
     626           0 :   return coordinate;
     627             : }
     628             : 
     629           0 : void libmspub::MSPUBParser2k::parseShapeFlips(WPXInputStream *input, unsigned flagsOffset, unsigned seqNum,
     630             :     unsigned chunkOffset)
     631             : {
     632           0 :   if (flagsOffset)
     633             :   {
     634           0 :     input->seek(chunkOffset + flagsOffset, WPX_SEEK_SET);
     635           0 :     unsigned char flags = readU8(input);
     636           0 :     bool flipV = flags & 0x1;
     637           0 :     bool flipH = flags & (0x2 | 0x10); // FIXME: this is a guess
     638           0 :     m_collector->setShapeFlip(seqNum, flipV, flipH);
     639             :   }
     640           0 : }
     641             : 
     642           0 : void libmspub::MSPUBParser2k::parseShapeType(WPXInputStream *input,
     643             :     unsigned seqNum, unsigned chunkOffset,
     644             :     bool &isGroup, bool &isLine, bool &isImage, bool &isRectangle,
     645             :     unsigned &flagsOffset)
     646             : {
     647           0 :   input->seek(chunkOffset, WPX_SEEK_SET);
     648           0 :   unsigned short typeMarker = readU16(input);
     649           0 :   if (typeMarker == 0x000f)
     650             :   {
     651           0 :     isGroup = true;
     652             :   }
     653           0 :   else if (typeMarker == 0x0004)
     654             :   {
     655           0 :     isLine = true;
     656           0 :     flagsOffset = 0x41;
     657           0 :     m_collector->setShapeType(seqNum, LINE);
     658             :   }
     659           0 :   else if (typeMarker == 0x0002)
     660             :   {
     661           0 :     isImage = true;
     662           0 :     m_collector->setShapeType(seqNum, RECTANGLE);
     663           0 :     isRectangle = true;
     664             :   }
     665           0 :   else if (typeMarker == 0x0005)
     666             :   {
     667           0 :     m_collector->setShapeType(seqNum, RECTANGLE);
     668           0 :     isRectangle = true;
     669             :   }
     670           0 :   else if (typeMarker == 0x0006)
     671             :   {
     672           0 :     input->seek(chunkOffset + 0x31, WPX_SEEK_SET);
     673           0 :     ShapeType shapeType = getShapeType(readU8(input));
     674           0 :     flagsOffset = 0x33;
     675           0 :     if (shapeType != UNKNOWN_SHAPE)
     676             :     {
     677           0 :       m_collector->setShapeType(seqNum, shapeType);
     678             :     }
     679             :   }
     680           0 :   else if (typeMarker == 0x0007)
     681             :   {
     682           0 :     m_collector->setShapeType(seqNum, ELLIPSE);
     683             :   }
     684           0 :   else if (typeMarker == getTextMarker())
     685             :   {
     686           0 :     m_collector->setShapeType(seqNum, RECTANGLE);
     687           0 :     isRectangle = true;
     688           0 :     input->seek(chunkOffset + getTextIdOffset(), WPX_SEEK_SET);
     689           0 :     unsigned txtId = readU16(input);
     690           0 :     m_collector->addTextShape(txtId, seqNum);
     691             :   }
     692           0 : }
     693             : 
     694           0 : unsigned libmspub::MSPUBParser2k::getTextIdOffset() const
     695             : {
     696           0 :   return 0x58;
     697             : }
     698             : 
     699           0 : unsigned short libmspub::MSPUBParser2k::getTextMarker() const
     700             : {
     701           0 :   return 0x0008;
     702             : }
     703             : 
     704           0 : unsigned libmspub::MSPUBParser2k::getFirstLineOffset() const
     705             : {
     706           0 :   return 0x2C;
     707             : }
     708             : 
     709           0 : unsigned libmspub::MSPUBParser2k::getSecondLineOffset() const
     710             : {
     711           0 :   return 0x35;
     712             : }
     713             : 
     714           0 : void libmspub::MSPUBParser2k::parseShapeLine(WPXInputStream *input, bool isRectangle, unsigned offset,
     715             :     unsigned seqNum)
     716             : {
     717           0 :   input->seek(offset + getFirstLineOffset(), WPX_SEEK_SET);
     718           0 :   unsigned short leftLineWidth = readU8(input);
     719           0 :   bool leftLineExists = leftLineWidth != 0;
     720           0 :   unsigned leftColorReference = readU32(input);
     721           0 :   unsigned translatedLeftColorReference = translate2kColorReference(leftColorReference);
     722           0 :   if (isRectangle)
     723             :   {
     724           0 :     input->seek(offset + getSecondLineOffset(), WPX_SEEK_SET);
     725           0 :     unsigned char topLineWidth = readU8(input);
     726           0 :     bool topLineExists = topLineWidth != 0;
     727           0 :     unsigned topColorReference = readU32(input);
     728           0 :     unsigned translatedTopColorReference = translate2kColorReference(topColorReference);
     729             :     m_collector->addShapeLine(seqNum, Line(ColorReference(translatedTopColorReference),
     730           0 :                                            translateLineWidth(topLineWidth) * EMUS_IN_INCH / (4 * POINTS_IN_INCH), topLineExists));
     731             : 
     732           0 :     input->seek(1, WPX_SEEK_CUR);
     733           0 :     unsigned char rightLineWidth = readU8(input);
     734           0 :     bool rightLineExists = rightLineWidth != 0;
     735           0 :     unsigned rightColorReference = readU32(input);
     736           0 :     unsigned translatedRightColorReference = translate2kColorReference(rightColorReference);
     737             :     m_collector->addShapeLine(seqNum, Line(ColorReference(translatedRightColorReference),
     738           0 :                                            translateLineWidth(rightLineWidth) * EMUS_IN_INCH / (4 * POINTS_IN_INCH), rightLineExists));
     739             : 
     740           0 :     input->seek(1, WPX_SEEK_CUR);
     741           0 :     unsigned char bottomLineWidth = readU8(input);
     742           0 :     bool bottomLineExists = bottomLineWidth != 0;
     743           0 :     unsigned bottomColorReference = readU32(input);
     744           0 :     unsigned translatedBottomColorReference = translate2kColorReference(bottomColorReference);
     745             :     m_collector->addShapeLine(seqNum, Line(ColorReference(translatedBottomColorReference),
     746           0 :                                            translateLineWidth(bottomLineWidth) * EMUS_IN_INCH / (4 * POINTS_IN_INCH), bottomLineExists));
     747             :   }
     748             :   m_collector->addShapeLine(seqNum, Line(ColorReference(translatedLeftColorReference),
     749           0 :                                          translateLineWidth(leftLineWidth) * EMUS_IN_INCH / (4 * POINTS_IN_INCH), leftLineExists));
     750           0 : }
     751             : 
     752           0 : bool libmspub::MSPUBParser2k::parse()
     753             : {
     754           0 :   WPXInputStream *contents = m_input->getDocumentOLEStream("Contents");
     755           0 :   if (!contents)
     756             :   {
     757             :     MSPUB_DEBUG_MSG(("Couldn't get contents stream.\n"));
     758           0 :     return false;
     759             :   }
     760           0 :   if (!parseContents(contents))
     761             :   {
     762             :     MSPUB_DEBUG_MSG(("Couldn't parse contents stream.\n"));
     763           0 :     delete contents;
     764           0 :     return false;
     765             :   }
     766           0 :   WPXInputStream *quill = m_input->getDocumentOLEStream("Quill/QuillSub/CONTENTS");
     767           0 :   if (!quill)
     768             :   {
     769             :     MSPUB_DEBUG_MSG(("Couldn't get quill stream.\n"));
     770           0 :     return false;
     771             :   }
     772           0 :   if (!parseQuill(quill))
     773             :   {
     774             :     MSPUB_DEBUG_MSG(("Couldn't parse quill stream.\n"));
     775           0 :     delete quill;
     776           0 :     return false;
     777             :   }
     778           0 :   return m_collector->go();
     779             : }
     780             : 
     781           0 : libmspub::PageType libmspub::MSPUBParser2k::getPageTypeBySeqNum(unsigned seqNum)
     782             : {
     783           0 :   switch(seqNum)
     784             :   {
     785             :   case 0x116:
     786             :   case 0x108:
     787             :   case 0x10B:
     788             :   case 0x10D:
     789             :   case 0x119:
     790           0 :     return DUMMY_PAGE;
     791             :   case 0x109:
     792           0 :     return MASTER;
     793             :   default:
     794           0 :     return NORMAL;
     795             :   }
     796           0 : }
     797             : 
     798             : /* vim:set shiftwidth=2 softtabstop=2 expandtab: */

Generated by: LCOV version 1.10