void Parser9x::parsePicture( const PictureData& data ) { wvlog << "Parser9x::parsePicture" << std::endl; OLEStreamReader* stream = m_fib.nFib < Word8nFib ? m_wordDocument : m_data; stream->push(); // saveState would be overkill //go to the position in the stream after the PICF, where the actual picture data/escher is if ( !stream->seek( data.fcPic + data.picf->cbHeader, G_SEEK_SET ) ) { wvlog << "Error: Parser9x::parsePicture couldn't seek properly" << std::endl; stream->pop(); return; } if ( data.picf->mfp.mm == 0x64 || data.picf->mfp.mm == 0x66 ) { wvlog << "Linked graphic in Escher object" << std::endl; parsePictureEscher( data, stream, data.picf->lcb, data.fcPic ); } else { switch ( data.picf->mfp.mm ) { case 94: // A .bmp or a .gif name is stored after the PICF case 98: // The .tiff name is stored after the PICF parsePictureExternalHelper( data, stream ); break; case 99: // A full bmp is stored after the PICF -- not handled in OOo?? parsePictureBitmapHelper( data, stream ); break; default: // It has to be a .wmf or .emf file (right after the PICF) wvlog << "assuming WMF/EMF file... not sure this is correct" << std::endl; parsePictureWmfHelper( data, stream ); break; } } stream->pop(); }
// Some basic test for the storage system. Please don't change the oletest.doc // file as some tests depend on exacly that file (e.g. directory names) int main( int, char** ) { std::cerr << "Testing the OLE storage and the streams..." << std::endl; std::cerr << "###############################################################################" << std::endl; std::cerr << "Test 1: Open the sample file: "; OLEStorage storage( "testole.doc" ); test( storage.open( OLEStorage::ReadOnly ) ); std::cerr << "###############################################################################" << std::endl; std::cerr << "Test2: List the contents of the root directory:" << std::endl; std::list<std::string> dir = storage.listDirectory(); test( storage.isValid() ); std::list<std::string>::const_iterator it = dir.begin(); std::list<std::string>::const_iterator end = dir.end(); for ( ; it != end; ++it ) std::cerr << " - " << *it << std::endl; std::cerr << "###############################################################################" << std::endl; std::cerr << "Test3: Stat a stream: skipped" << std::endl; /* MsOleStat s = storage.stat( "WordDocument" ); test( storage.lastError() == MS_OLE_ERR_OK && s.type == MsOleStreamT && s.size != static_cast<unsigned int>( -1 ), "### Error in Test 3: " + int2string( storage.lastError() ), "Passed." ); */ std::cerr << "Test4: Stat a storage (directory): skipped" << std::endl; /* s = storage.stat( "ObjectPool" ); test( storage.lastError() == MS_OLE_ERR_OK && s.type == MsOleStorageT && s.size != static_cast<unsigned int>( -1 ) , "### Error in Test 4: " + int2string( storage.lastError() ), "Passed." ); */ std::cerr << "Test5: Enter a directory: "; test( storage.enterDirectory( "ObjectPool" ) ); std::cerr << "###############################################################################" << std::endl; std::cerr << "Test6: List the contents of the current directory:" << std::endl; dir = storage.listDirectory(); test( storage.isValid() ); it = dir.begin(); end = dir.end(); for ( ; it != end; ++it ) std::cerr << " - " << *it << std::endl; std::cerr << "###############################################################################" << std::endl; std::cerr << "Test7: Leave a directory." << std::endl; storage.leaveDirectory(); storage.leaveDirectory(); // we can do that as often as we want to storage.leaveDirectory(); // as we will never leave '/' std::cerr << "###############################################################################" << std::endl; std::cerr << "Test8: List the contents of the current directory (should be the root dir):" << std::endl; dir = storage.listDirectory(); test( storage.isValid() ); it = dir.begin(); end = dir.end(); for ( ; it != end; ++it ) std::cerr << " - " << *it << std::endl; std::cerr << "###############################################################################" << std::endl; // go somewhere (for testing purpose) storage.enterDirectory( "ObjectPool" ); std::cerr << "Test9: Set a few custom paths:" << std::endl; std::cerr << " Trying '/ObjectPool/_1020966487': "; test( storage.setPath("/ObjectPool/_1020966487") ); std::cerr << " Trying '/ObjectPool/_1020966487': "; test( storage.setPath("/ObjectPool/_1020966487") ); std::cerr << " Trying 'ObjectPool/_1020966487': "; test( storage.setPath("ObjectPool/_1020966487") ); std::cerr << " Trying 'ObjectPool/_1020966487/': "; test( storage.setPath("ObjectPool/_1020966487/") ); std::cerr << " Trying '/ObjectPool/_1020966487/': "; test( storage.setPath("/ObjectPool/_1020966487/") ); std::cerr << " Trying '/ObjectPool_1020966487': "; test( !storage.setPath("/ObjectPool_1020966487") ); std::cerr << " Trying '/': "; test( storage.setPath("/") && storage.path()=="/" ); std::cerr << "###############################################################################" << std::endl; std::cerr << "Test10: Open a stream for reading: "; OLEStreamReader* reader = storage.createStreamReader( "1Table" ); test( reader && reader->isValid() ); std::cerr << "Test11: Check whether we are at 0 right after opening: "; test( reader->tell() == 0 ); std::cerr << "Test12: Check the size of the stream: "; test( reader->size() == 0x20a6 ); std::cerr << "Test13: Seek in the stream: "; reader->seek( 0x100 ); test( reader->seek( 1, G_SEEK_CUR ) && reader->tell() == 0x101 ); reader->push(); // save the current pos (0x101) std::cerr << "Test14: More seeking: "; test( reader->seek( -2, G_SEEK_CUR ) && reader->tell() == 0xff ); reader->push(); // save the current pos (0xff) std::cerr << "Test15: Even more seeking: "; test( reader->seek( -2, G_SEEK_END ) && reader->tell() == 0x20a4 ); std::cerr << "Test16: Checking the stack: "; test( reader->pop() && reader->tell() == 0xff ); std::cerr << "Test17: Checking the stack again: "; test( reader->pop() && reader->tell() == 0x101 ); // clean up the current stream delete reader; reader = 0; std::cerr << "Test18: Open another stream for reading: "; reader = storage.createStreamReader( "WordDocument" ); test( reader && reader->isValid() ); std::cerr << "Test19: Read the magic 16 Bit value: "; test( reader->readU16() == 0xa5ec ); std::cerr << "Test20: Check the nFib: "; test( reader->readU16() == 193 ); std::cerr << "Test21: Check the byte reading: "; reader->seek( 2 ); test( reader->readU8() == 0xc1 ); std::cerr << "Test22: Check the word reading: "; reader->seek( 0 ); test( reader->readU32() == 0x00c1a5ec ); // Get rid of our test document // The warning we get is the intended behavior :) storage.close(); // Open a new document for write tests (make sure // it doesn't exist) system( "rm test123456.doc &> /dev/null" ); storage.setName( "test123456.doc" ); test( storage.open( OLEStorage::WriteOnly ) ); std::cerr << "Test23: Open a stream for writing (I): "; OLEStreamWriter* writer = storage.createStreamWriter( "Check1" ); test( writer && writer->isValid() ); writer->write( static_cast<U32>( 0x11111111 ) ); writer->write( static_cast<U32>( 0x11111111 ) ); writer->write( static_cast<U32>( 0x11111111 ) ); writer->write( static_cast<U32>( 0x11111111 ) ); writer->write( static_cast<U32>( 0x11111111 ) ); writer->write( static_cast<U32>( 0x11111111 ) ); writer->write( static_cast<U32>( 0x11111111 ) ); writer->write( static_cast<U32>( 0x11111111 ) ); writer->write( static_cast<U32>( 0x11111111 ) ); // write it to disk... delete writer; writer = 0; std::cerr << "Test24: Open a stream for writing (II): "; writer = storage.createStreamWriter( "Check2" ); test( writer && writer->isValid() ); writer->write( static_cast<U8>( 200 ) ); writer->write( static_cast<S8>( 123 ) ); writer->write( static_cast<U16>( 42420 ) ); writer->write( static_cast<S16>( -21420 ) ); writer->write( static_cast<U32>( 0xdeadbeef ) ); writer->write( static_cast<S32>( 0x7fffffff ) ); // write it to disk... delete writer; writer = 0; #ifndef SMALL_BLOCKS_ONLY std::cerr << "Test25: Open a stream for writing (III): "; writer = storage.createStreamWriter( "Check3" ); test( writer && writer->isValid() ); for ( int i = 0; i < 10000; ++i ) { writer->write( static_cast<S32>( 0x22222222 ) ); writer->write( static_cast<S32>( 0x22222222 ) ); writer->write( static_cast<S32>( 0x22222222 ) ); writer->write( static_cast<S32>( 0x22222222 ) ); writer->write( static_cast<S32>( 0x22222222 ) ); } delete writer; writer = 0; #endif std::cerr << "Test26: Open a stream for writing (IV): "; writer = storage.createStreamWriter( "Check4" ); test( writer && writer->isValid() ); srand( time( 0 ) ); U8 buffer1[ 256 ]; for ( int i = 0; i< 256; ++i ) buffer1[ i ] = rand() % 256; writer->write( buffer1, 256 ); delete writer; writer = 0; storage.close(); std::cerr << "Test27: Read back the created file: "; test( storage.open( OLEStorage::ReadOnly ) && storage.isValid() ); std::cerr << "Test28: Open the stream I for reading: "; reader = storage.createStreamReader( "Check1" ); test( reader && reader->isValid() ); std::cerr << "Test29: Check the size of the stream I: "; test( reader->size() == 36 ); delete reader; reader = 0; std::cerr << "Test30: Open the stream II for reading: "; reader = storage.createStreamReader( "Check2" ); test( reader && reader->isValid() ); std::cerr << "Test31: Check the size of the stream II: "; test( reader->size() == 14 ); std::cerr << "Test32: Check the contents of the stream II: "; test( reader->readU8() == 200 && reader->readS8() == 123 && reader->readU16() == 42420 && reader->readS16() == -21420 && reader->readU32() == 0xdeadbeef && reader->readS32() == 0x7fffffff ); delete reader; reader = 0; std::cerr << "Test33: Open the stream IV for reading: "; reader = storage.createStreamReader( "Check4" ); test( reader && reader->isValid() ); std::cerr << "Test34: Read back and compare the content with the expected values: "; U8 buffer2[ 256 ]; reader->read( buffer2, 256 ); bool success = true; for ( int i = 0; i < 256; ++i ) if ( buffer1[ i ] != buffer2[ i ] ) { success = false; break; } test( success ); storage.close(); // missing delete reader; intendet, doesn't result in memleaks std::cerr << "Done." << std::endl; return 0; }
// A small testcase for the word97_helper stuff int main( int, char** ) { std::cerr << "Testing some auxilliary classes..." << std::endl; OLEStorage storage( std::string( "testole.doc" ) ); test( storage.open( OLEStorage::ReadOnly ) ); OLEStreamReader* document = storage.createStreamReader( "WordDocument" ); test( document && document->isValid(), "Error: Couldn't open the WordDocument stream" ); //document->dumpStream( "document.stream" ); Word97::FIB fib( document, true ); OLEStreamReader* table = storage.createStreamReader( fib.fWhichTblStm ? "1Table" : "0Table" ); test( table && table->isValid(), "Error: Couldn't open the Table stream" ); // Test STTBFASSOC reading from memory std::cerr << "Test 1: Read the STTBFASSOC from memory: "; table->seek( fib.fcSttbfAssoc ); //table->dumpStream( "table.stream" ); U8* data = new U8[ fib.lcbSttbfAssoc ]; table->read( data, fib.lcbSttbfAssoc ); STTBF sttbf( 0x0400, data ); delete [] data; test( sttbf.count() == 18 ); for ( UString s = sttbf.firstString(); !s.isNull(); s = sttbf.nextString() ) std::cerr << "String: '" << s.ascii() << "'" << std::endl; // Test STTBFASSOC reading from a stream std::cerr << "Test 2: Read the STTBFASSOC from a stream: "; table->seek( fib.fcSttbfAssoc ); STTBF sttbf2( 0x0400, table ); UString s1 = sttbf.firstString(), s2 = sttbf2.firstString(); bool failed = false; for ( ; !s1.isNull() && !s2.isNull(); s1 = sttbf.nextString(), s2 = sttbf2.nextString() ) { if ( s1 != s2 ) { failed = true; break; } } test( !failed ); // Testing PLF reading/iterating std::cerr << "Test 3a: Reading a PLF (LFO): "; table->seek( fib.fcPlfLfo ); PLF<Word97::LFO> plf( table ); test( plf.count() == 10 ); // we have some padding data at the end, so the size is screwed std::cerr << "Test 3b: Reading a PLF (LSTF, \"short count\" PLF): "; table->seek( fib.fcPlcfLst ); PLF<Word97::LSTF, true> plf1( table ); test( plf1.count() * Word97::LSTF::sizeOf + 2 == fib.lcbPlcfLst ); std::cerr << "Test 3c: Trying to match the list IDs: "; // Check whether all list ids match, then the file is okay (and we read it correctly) // Yes, I know that this is O(n^2), but hey, this is a test case for 10 elements ;) bool success = true; bool found = false; for ( const Word97::LSTF* lstf = plf1.first(); lstf != 0; lstf = plf1.next() ) { found = false; for ( const Word97::LFO* lfo = plf.first(); lfo != 0; lfo = plf.next() ) if ( lstf->lsid == lfo->lsid ) { found = true; break; } if ( !found ) { success = false; break; } } test( success ); table->seek( fib.fcPlcfbtePapx ); std::cerr << "Test 4: Reading a PLCF: " << std::endl; //std::cerr << "Size: " << fib.lcbPlcfbtePapx << std::endl; PLCF<Word97::BTE> plcf( fib.lcbPlcfbtePapx, table ); std::cerr << "Test 4a: Checking the size of the PLCF: "; test( plcf.count() == 6 ); PLCFIterator<Word97::BTE> it( plcf ); for ( ; it.current(); ++it ) { std::cerr << "Item: " << std::endl; std::cerr << " start: " << it.currentStart() << std::endl; std::cerr << " lim: " << it.currentLim() << std::endl; std::cerr << " value: " << it.current()->pn << std::endl; } // Test the FKP template it.toFirst(); // rewind the iterator ;) std::cerr << "Test 5: Reading a FKP: " << std::endl; document->seek( it.current()->pn << 9, G_SEEK_SET ); FKP< BX<Word97::PHE> > fkp( document, false ); std::cerr << "crun: " << fkp.crun() << std::endl; FKPIterator< BX<Word97::PHE> > it2( fkp ); for ( int i = 0; !it2.atEnd(); ++it2, ++i ) { std::cerr << "Item(" << i << "): " << std::endl; std::cerr << " start: " << it2.currentStart() << std::endl; std::cerr << " lim: " << it2.currentLim() << std::endl; if ( it2.current() ) std::cerr << " plain entry" << std::endl; else std::cerr << " null entry" << std::endl; } std::cerr << "sizeof(PRM): " << sizeof(Word97::PRM) << std::endl; std::cerr << "sizeof(PRM2): " << sizeof(Word97::PRM2) << std::endl; std::cerr << "sizeof(PCD): " << sizeof(Word97::PCD) << std::endl; std::cerr << "sizeof(DTTM): " << sizeof(Word97::DTTM) << std::endl; std::cerr << "sizeof(BTE): " << sizeof(Word97::BTE) << std::endl; std::cerr << "sizeof(PHE): " << sizeof(Word97::PHE) << std::endl; std::cerr << "sizeof(BX): " << sizeof(BX<Word97::PHE>) << std::endl; delete document; delete table; std::cerr << "Done." << std::endl; return 0; }
void parseRecord(int rec_type, long rec_len, OLEStreamReader& reader, std::string& text) { switch(rec_type) { case RT_CSTRING: case RT_TEXT_CHARS_ATOM: { if (m_verbose_logging) *m_log_stream << "RT_TextCharsAtom or RT_CString\n"; std::vector<unsigned char> buf(2); long text_len = rec_len / 2; for (int i = 0; i < text_len; i++) { reader.read((U8*)&*buf.begin(), 2); U16 u = getU16LittleEndian(buf.begin()); if (u != 0x0D) text += unicodeCharToUTF8(u); else text += '\n'; } text += '\n'; break; } case RT_DOCUMENT: if (m_verbose_logging) *m_log_stream << "RT_Document\n"; break; case RT_DRAWING: if (m_verbose_logging) *m_log_stream << "RT_Drawing\n"; break; case RT_END_DOCUMENT_ATOM: if (m_verbose_logging) *m_log_stream << "RT_DocumentEnd\n"; reader.seek(rec_len, G_SEEK_CUR); break; case RT_LIST: if (m_verbose_logging) *m_log_stream << "RT_List\n"; break; case RT_MAIN_MASTER: if (m_verbose_logging) *m_log_stream << "RT_MainMaster\n"; #warning TODO: Make extracting text from main master slide configurable reader.seek(rec_len, G_SEEK_CUR); break; case RT_SLIDE: if (m_verbose_logging) *m_log_stream << "RT_Slide\n"; break; case RT_SLIDE_BASE: break; case RT_SLIDE_LIST_WITH_TEXT: if (m_verbose_logging) *m_log_stream << "RT_SlideListWithText\n"; break; case RT_TEXT_BYTES_ATOM: { if (m_verbose_logging) *m_log_stream << "RT_TextBytesAtom\n"; std::vector<unsigned char> buf(2); for (int i = 0; i < rec_len; i++) { reader.read((U8*)&*buf.begin(), 1); if (buf[0] != 0x0D) text += unicodeCharToUTF8(buf[0]); else text += '\n'; } text += '\n'; break; } case OFFICE_ART_CLIENT_TEXTBOX: if (m_verbose_logging) *m_log_stream << "OfficeArtClientTextbox\n"; break; case OFFICE_ART_DG_CONTAINER: if (m_verbose_logging) *m_log_stream << "OfficeArtDgContainer\n"; break; case OFFICE_ART_SPGR_CONTAINER: if (m_verbose_logging) *m_log_stream << "OfficeArtSpgrContainer\n"; break; case OFFICE_ART_SP_CONTAINER: if (m_verbose_logging) *m_log_stream << "OfficeArtSpContainer\n"; break; default: reader.seek(rec_len, G_SEEK_CUR); } }