/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * This file is part of xlslib -- A multiplatform, C/C++ library * for dynamic generation of Excel(TM) files. * * xlslib is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * xlslib is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with xlslib. If not, see . * * Copyright 2004 Yeico S. A. de C. V. * Copyright 2008 David Hoerl * * $Source: /cvsroot/xlslib/xlslib/src/oledoc/oledoc.cpp,v $ * $Revision: 1.3 $ * $Author: dhoerl $ * $Date: 2008/10/25 18:39:53 $ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * File description: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include using namespace std; using namespace xlslib_core; /* *********************************** COleDoc class implementation *********************************** */ const unsigned8_t COleDoc::OLE_FILETYPE[] = { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1}; COleDoc::COleDoc() { } /* COleDoc::COleDoc(const string& file_name) { Open(file_name); } */ COleDoc::~COleDoc() { } /* *********************************** *********************************** */ int COleDoc::DumpHeader(blocks bks, unsigned32_t total_data_size) { unsigned32_t i, total_data_blocks, sectorID, msatID; int errcode = NO_ERRORS; total_data_blocks = total_data_size/BIG_BLOCK_SIZE; #if OLE_DEBUG fprintf(stderr, "dataBlocks=%u\n", total_data_blocks), fflush(stderr); #endif // [00]FILETYPE WriteByteArray(COleDoc::OLE_FILETYPE, /*(unsigned32_t)*/sizeof(COleDoc::OLE_FILETYPE)); // [08]UK1 WriteSigned32(HEADVAL_DFLT_UK1); // [0c]UK2 WriteSigned32(HEADVAL_DFLT_UK2); // [10]UK2b WriteSigned32(HEADVAL_DFLT_UK2b); // [14]UK3 WriteSigned32(HEADVAL_DFLT_UK3); // [18]UK4 WriteSigned16(HEADVAL_DFLT_UK4); // [1a]UK5 WriteSigned16(HEADVAL_DFLT_UK5); // [1c]UK6 WriteSigned16(HEADVAL_DFLT_UK6); // [1e]LOG_2_BIG_BLOCK WriteSigned16(HEADVAL_DFLT_LOG2_BIGBLOCK); // [20]LOG_2_SMALL_BLOCK WriteSigned32(HEADVAL_DFLT_LOG2_SMALLBLOCK); // [24]UK7 WriteSigned32(HEADVAL_DFLT_UK7); // [28]UK8 WriteSigned32(HEADVAL_DFLT_UK8); // [2c] BAT_COUNT (BBDEPOT NUM BLOCKS) WriteUnsigned32(bks.bat_count); //[30] PROPERTIES_START_BLOCK // Since the big block depot will go immediately after the data, I need // to know the size of the data and the size of the BAT in blocks (prev) WriteUnsigned32(bks.msat_count+total_data_blocks+bks.bat_count); #if OLE_DEBUG fprintf(stderr, "HEADER says directory at %d\n", bks.msat_count+total_data_blocks+bks.bat_count); #endif // [34] UK9 WriteSigned32(HEADVAL_DFLT_UK9); // [38] UK10 WriteSigned32(HEADVAL_DFLT_UK10); // [3c] SBAT_START // No small blocks will be used, so this is set to the default empty value WriteSigned32(HEADVAL_DFLT_SBAT_START); // [40] SBAT_BLOCKCOUNT_NUMBER // Use the default value WriteSigned32(HEADVAL_DFLT_SBAT_COUNT); // [44] XBAT_START // we will use first and possibly additional blocks for large files WriteSigned32(bks.msat_count ? 0 : HEADVAL_DFLT_XBAT_START); #if OLE_DEBUG fprintf(stderr, "xbatStart=%d\n", bks.msat_count ? 0 : HEADVAL_DFLT_XBAT_START), fflush(stderr); #endif // [48] XBAT_COUNT WriteUnsigned32(bks.msat_count); // was HEADVAL_DFLT_XBAT_COUNT (0) #if OLE_DEBUG fprintf(stderr, "msat_count=%d\n", bks.msat_count), fflush(stderr); #endif // [4C] BAT_ARRAY // The BAT_ARRAY shall be calculated from the number of BAT blocks and their position // The additional blocks, if needed, are directly below the header block, so we can write // them out contiguously. The special conditions are: // * for each MSAT block, the last entry needs to be a pointer to the next block // * the fill is -1 for all unused entries // * if there are MSAT blocks, the very last entry in the last block is a special marker // first sector ID sectorID = bks.msat_count + total_data_blocks; for(i=0; iGetType() == PTYPE_FILE) { for(DataList_Itor_t j = (*i)->GetDataPointer()->begin(); j != (*i)->GetDataPointer()->end(); j++) { WriteByteArray((*j)->GetBuffer(), (*j)->GetDataSize()); } } } return errcode; } /* *********************************** *********************************** */ int COleDoc::DumpDepots(blocks bks) { int errcode = NO_ERRORS; NodeList_t node_list; GetAllNodes(node_list); unsigned32_t bat_index; bat_index = 0; // tells Excel that these are used by the MSAT for(unsigned32_t i=0; iSetStartBlock(bat_index); // Write the chain for this node element data_size = (*node)->GetDataPointer()->GetDataSize(); chain_len = data_size/BIG_BLOCK_SIZE - 1; #if OLE_DEBUG fprintf(stderr, "NODE[%d]: start_block=%d data=%d Sectors= %d\n", foo, bat_index, chain_len + 1 /* directory_terminator */); #endif for(unsigned32_t i = 0; i < chain_len; i++) { WriteSigned32(++bat_index); ++bks._bat_entries; } // Set the terminator number WriteSigned32(BAT_END_CHAIN); ++bat_index; ++bks._bat_entries; } #if OLE_DEBUG fprintf(stderr, "BAT_SELF_PLACE=%d -> %d TOTAL=%d\n", bat_index+1, bat_index+1+bks.bat_count+1, bks.bat_count); #endif // Write the -3 number for every index in the BAT that references to some BAT block (uh!?) for(unsigned32_t i=0; i bat_block_capacity || bat_num_blocks != bat_blocks_needed) { bat_num_blocks = bat_blocks_needed; if(bat_num_blocks > HEADER_SAT_SIZE) { msat_bats = bat_num_blocks - HEADER_SAT_SIZE; msat_blocks = msat_bats/BAT_BLOCKS_PER_MSAT_BLOCK; if(msat_bats % BAT_BLOCKS_PER_MSAT_BLOCK) ++msat_blocks; } bat_num_entries = msat_blocks + data_bat_entries + bat_num_blocks + dir_bat_entries; // bat_bat_entries // based on what we know now, this is what we need bat_blocks_needed = bat_num_entries/BAT_ENTRIES_PER_BLOCK; if(bat_num_entries % BAT_ENTRIES_PER_BLOCK) ++bat_blocks_needed; // number of slots available bat_block_capacity = HEADER_SAT_SIZE + BAT_BLOCKS_PER_MSAT_BLOCK*msat_blocks; #if OLE_DEBUG fprintf(stderr, "bat_blocks=%d capacity=%d needed=%d\n", bat_num_blocks, bat_block_capacity, bat_blocks_needed); #endif } if(bat_num_blocks > HEADER_SAT_SIZE) { extra_bats = bat_num_blocks - HEADER_SAT_SIZE; bks.msat_count = msat_blocks; bks.header_bat_count = HEADER_SAT_SIZE; bks.extra_bat_count = extra_bats; last_block_extras = extra_bats % BAT_BLOCKS_PER_MSAT_BLOCK; if(last_block_extras) { bks.extra_fill = BAT_BLOCKS_PER_MSAT_BLOCK - last_block_extras; } } else { bks.header_bat_count = bat_num_blocks; bks.header_fill = HEADER_SAT_SIZE - bat_num_blocks; } bks.bat_entries = bat_num_entries; bks.bat_count = bat_num_blocks; #if OLE_DEBUG fprintf(stderr, "entries=%u bats=%d msats=%d headerBats=%d extraBats=%d headFill=%d extraFill=%d\n", bks.bat_entries, bks.bat_count, bks.msat_count, bks.header_bat_count, bks.extra_bat_count, bks.header_fill, bks.extra_fill); #endif return bks; } /* *********************************** *********************************** */ // NOTE: name_unicode has to be deleted after this function finishes. // Ideally, this function should be implemented as part of a std::string // derived class, so the array would be deleted automatically signed16_t COleDoc::GetUnicodeName(const char* name, char** ppname_unicode) { unsigned16_t name_size = strlen(name); if(name_size > PROPERTY_MAX_NAME_LENGTH) name_size = PROPERTY_MAX_NAME_LENGTH; unsigned8_t size_unicode = (name_size+1)*2; if(*ppname_unicode != NULL) delete[] *ppname_unicode; *ppname_unicode = (char*)new unsigned8_t[size_unicode]; memset(*ppname_unicode, 0x00, size_unicode); for(int i=0; i<(size_unicode/2-1); i++) (*ppname_unicode)[2*i] = name[i]; return size_unicode; } /* *********************************** *********************************** */ int COleDoc::DumpNode(COleProp& node) { int errcode = NO_ERRORS; char* name_unicode = NULL; // Get the unicode name and its size signed16_t size_name = GetUnicodeName(node.GetName().c_str(), &name_unicode); // [00] PROPERTY_NAME WriteByteArray((const unsigned8_t*)name_unicode, size_name); // Fill the rest of the name field with 0x00 SerializeFixedArray(PROPERTY_DFLT_NOTUSED, PPTPOS_NAMELENGTH - size_name); // [40] NAME_SIZE WriteSigned16(size_name); // [42] PROPERTY_TYPE WriteByte(node.GetType()); // [43] NODE_COLOR WriteByte(node.GetColor()); // [44] PREVIOUS_PROP WriteSigned32(node.GetPreviousIndex()); // [48] NEXT_PROP WriteSigned32(node.GetNextIndex()); // [4c] CHILD_PROP WriteSigned32(node.GetChildIndex()); // Fill empty block SerializeFixedArray(PROPERTY_DFLT_NOTUSED, (PPTPOS_SECS1 - PPTPOS_UNUSED_EMPTY0)); //[64]...[70] // SECONDS_1, DAYS_2, SECONDS_2, DAYS_2 WriteSigned32(node.GetCreatedSecs()); WriteSigned32(node.GetCreatedDays()); WriteSigned32(node.GetModifiedDays()); WriteSigned32(node.GetModifiedSecs()); // [74] START_BLOCK #if OLE_DEBUG fprintf(stderr, "START_BLOCK_1=%d\n", node.GetStartBlock() ); #endif WriteSigned32(node.GetStartBlock()); // [78] SIZE if(node.GetType() == PTYPE_FILE) WriteSigned32(node.GetSize()); else WriteSigned32(0); // A unused space: WriteSigned32(PROPERTY_DFLT_NOTUSED); delete[] name_unicode; name_unicode = NULL; return errcode; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * $Log: oledoc.cpp,v $ * Revision 1.3 2008/10/25 18:39:53 dhoerl * 2008 * * Revision 1.2 2004/09/01 00:47:04 darioglz * + Modified to gain independence of target * * Revision 1.1.1.1 2004/08/27 16:31:43 darioglz * Initial Import. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */