/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * This file is part of xlslib -- A multiplatform, C/C++ library * for dynamic generation of Excel(TM) files. * * Copyright 2004 Yeico S. A. de C. V. All Rights Reserved. * Copyright 2008-2013 David Hoerl All Rights Reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY David Hoerl ''AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL David Hoerl OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include "../common/stringtok.h" #include "../xlslib/record.h" #include "../oledoc/olefs.h" #include "../xlslib/datast.h" using namespace xlslib_core; using namespace xlslib_strings; /* *********************************** * COleFileSystem class Implementation *********************************** */ COleFileSystem::COleFileSystem() : m_RootEntry((signed32_t) 0, "Root Entry"), m_nProperty_Count(0) { m_RootEntry.SetType(PTYPE_ROOT); m_RootEntry.SetSize(0); m_RootEntry.SetPreviousIndex(PLINK_EMPTY); m_RootEntry.SetNextIndex(PLINK_EMPTY); m_RootEntry.SetChildIndex(PLINK_EMPTY); m_RootEntry.SetStartBlock(PBLOCK_END); m_RootEntry.SetColor(PROPERTY_COLOR_NODE_BLACK); m_RootEntry.SetDataPointer(NULL); m_RootEntry.SetCreatedSecs(PPT_DFLT_SECS1); m_RootEntry.SetCreatedDays(PPT_DFLT_DAYS1); m_RootEntry.SetModifiedSecs(PPT_DFLT_SECS2); m_RootEntry.SetModifiedDays(PPT_DFLT_DAYS2); } COleFileSystem::~COleFileSystem() { } int COleFileSystem::GetNode(string const &path, Tree_Level_Itor_t& node) { StringList_t path_list; stringtok(path_list, path, "/"); int retval = SearchNode(&m_RootEntry, path_list, node); // Delete dynamically created strings of path_list // anyway the list is deleted inside SearchNode... for (StringListItor_t pl = path_list.begin(); pl != path_list.end(); pl++) { delete *pl; } return retval; } int COleFileSystem::SearchNode(COleProp* base_node, StringList_t& path_list, Tree_Level_Itor_t& node_level) { int errcode = FS_INVALID_PATH; if(!((base_node->m_Child_List).empty())) { for (StringListItor_t node_name = path_list.begin(); node_name != path_list.end(); ++node_name) { for(node_level = (base_node->m_Child_List).begin(); node_level != (base_node->m_Child_List).end(); node_level++) { if (**node_name == (*node_level)->GetName()) { delete path_list.front(); path_list.pop_front(); // Remove the found element from path if(path_list.empty()) { // If it was the last element return it return FS_NO_ERRORS; } else { // Recursively continue the search return SearchNode(*node_level, path_list, node_level); } } } } } return errcode; } int COleFileSystem::AddDirectory(string const &dir_path) { int errcode = NO_ERRORS; StringList_t path_list; stringtok(path_list, dir_path, "/"); errcode = AddNode(&m_RootEntry, path_list); // Delete dynamically created strings of path_list for (StringListItor_t pl = path_list.begin(); pl != path_list.end(); pl++) { delete *pl; } if(errcode == FS_NO_ERRORS) { Tree_Level_Itor_t newnode; GetNode(dir_path, newnode); (*newnode)->SetChildIndex(PLINK_EMPTY); (*newnode)->SetType(PTYPE_DIRECTORY); (*newnode)->SetSize(0); (*newnode)->SetColor(PROPERTY_COLOR_NODE_BLACK); (*newnode)->SetDataPointer(NULL); (*newnode)->SetCreatedSecs(PPT_DFLT_SECS1); (*newnode)->SetCreatedDays(PPT_DFLT_DAYS1); (*newnode)->SetModifiedSecs(PPT_DFLT_SECS2); (*newnode)->SetModifiedDays(PPT_DFLT_DAYS2); } return errcode; } #define MIN_DATA_SIZE (0x1000) // TODO: Change the DataStorage pass-argument (???) int COleFileSystem::AddFile(string const &dir_path, CDataStorage* pdata) { int errcode = NO_ERRORS; StringList_t path_list; // NOTE: Token analysis can be done inside of AddNode: stringtok(path_list, dir_path, "/"); errcode = AddNode(&m_RootEntry, path_list); // Delete dynamically created strings of path_list for (StringListItor_t pl = path_list.begin(); pl != path_list.end(); pl++) { delete *pl; } if(errcode == FS_NO_ERRORS) { Tree_Level_Itor_t newnode; GetNode(dir_path, newnode); (*newnode)->SetType(PTYPE_FILE); (*newnode)->SetChildIndex(PLINK_EMPTY); // Calculate the trail data size needed to complete a BIG_BLOCK size_t trail_size = (pdata->GetDataSize() % BIG_BLOCK_SIZE) ? (BIG_BLOCK_SIZE - (pdata->GetDataSize() % BIG_BLOCK_SIZE)) : 0; // This library won't use Small Blocks, so all data elements shall be >0x1000 if ((trail_size + pdata->GetDataSize()) < MIN_DATA_SIZE) { trail_size = MIN_DATA_SIZE - pdata->GetDataSize(); (*newnode)->SetSize(MIN_DATA_SIZE); } else { // The size stored in the node is the actual size of the data (not the filled-to-bigblock one) (*newnode)->SetSize(pdata->GetDataSize() + trail_size); } // create the trail data unit. CUnit* ptraildata = pdata->MakeCUnit(); ptraildata->AddFixedDataArray(0x00, trail_size); (*pdata) += ptraildata; (*newnode)->SetDataPointer(pdata); (*newnode)->SetColor(PROPERTY_COLOR_NODE_BLACK); (*newnode)->SetCreatedSecs(PPT_DFLT_SECS1); (*newnode)->SetCreatedDays(PPT_DFLT_DAYS1); (*newnode)->SetModifiedSecs(PPT_DFLT_SECS2); (*newnode)->SetModifiedDays(PPT_DFLT_DAYS2); } return errcode; } /* *********************************** * Some special adding-node cases: * - The path to reach the node doesn't exist * - The the node already exists *********************************** */ int COleFileSystem::AddNode(COleProp* base_node, StringList_t& path_list) { int errcode; if(!(base_node->m_Child_List).empty()) { for(Tree_Level_Itor_t node_child = (base_node->m_Child_List).begin(); node_child != (base_node->m_Child_List).end(); node_child++) { if((*node_child)->GetName() == **path_list.begin()) { delete path_list.front(); path_list.pop_front(); // Remove the found element from path return AddNode(*node_child, path_list); } } } //if the path element wasn't found, the program gets here //... and we have two possible reasons: // 1. The path isn't correct, so no node is created and an error msg have to be returned // (one of the intermediate nodes is empty or doesn't exist: there are more than one path elements left) // 2. The node is the new one we want to create. // if the size of the path is 0, the node already existed if(path_list.size() != 1) { if (path_list.size() == 0) { errcode = FS_NODE_ALREADY_EXISTS; } else { errcode = FS_INVALID_PATH; } } else { unsigned8_t base_node_type = base_node->GetType(); if(base_node_type == PTYPE_DIRECTORY || base_node_type == PTYPE_ROOT) { COleProp* newnode = new COleProp(++m_nProperty_Count, **path_list.begin()); size_t childnum = (base_node->m_Child_List).size(); if(!(base_node->m_Child_List).empty()) { //if this is the first child of the node... Tree_Level_Itor_t lastnode = (base_node->m_Child_List).end(); lastnode--; if(1 == childnum) { base_node->SetChildIndex(newnode->GetIndex()); // The 2nd child is the entry always newnode->SetPreviousIndex((*lastnode)->GetIndex()); // The previous is the only element of the list } else { (*lastnode)->SetNextIndex(newnode->GetIndex()); newnode->SetPreviousIndex(PLINK_EMPTY); // there is no previous } newnode->SetNextIndex(PLINK_EMPTY); // there is no next newnode->SetChildIndex(PLINK_EMPTY); // there is no child } else { base_node->SetChildIndex(m_nProperty_Count); // the new one is the child newnode->SetPreviousIndex(PLINK_EMPTY); // there is no previous newnode->SetNextIndex(PLINK_EMPTY); // there is no next newnode->SetChildIndex(PLINK_EMPTY); // there is no child } (base_node->m_Child_List).push_back(newnode); errcode = FS_NO_ERRORS; } else { errcode = FS_NODE_NOT_A_DIRECTORY; } } return errcode; } void COleFileSystem::GetAllNodes(NodeList_t& node_list) { GetAllNodesList(node_list, &m_RootEntry); SortList(node_list); } void COleFileSystem::GetAllNodesList(NodeList_t& node_list, COleProp* base_node) { if(!(base_node->m_Child_List).empty()) { for(Tree_Level_Itor_t child_node = (base_node->m_Child_List).begin(); child_node != (base_node->m_Child_List).end(); child_node++ ) { GetAllNodesList(node_list, (*child_node)); node_list.push_back((*child_node)); } } else { return; } } static inline bool oleCompare (const COleProp *left, const COleProp *right) { return left->GetIndex() < right->GetIndex(); } void COleFileSystem::SortList(NodeList_t& node_list) { //printf("sort len = %d\n", node_list.size() ); sort(node_list.begin(), node_list.end(), oleCompare); // stable_sort Compare } size_t COleFileSystem::GetTotalDataSize() { NodeList_t node_list; GetAllNodes(node_list); size_t total_size = 0; for(NodeList_Itor_t i = node_list.begin(); i != node_list.end(); i++) { if((*i)->GetType() == PTYPE_FILE) { total_size += (*i)->GetDataPointer()->GetDataSize(); } } return total_size; } unsigned32_t COleFileSystem::GetNumDataFiles() { NodeList_t node_list; GetAllNodes(node_list); unsigned32_t total_files = 0; for(NodeList_Itor_t i = node_list.begin(); i != node_list.end(); i++) { if((*i)->GetType() == PTYPE_FILE) { total_files++; } } return total_files; } COleProp& COleFileSystem::GetRootEntry() { return m_RootEntry; }