/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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.
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */