mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-07-11 11:55:36 +08:00
CompoundDocument reader/writer
git-svn-id: svn://fileserver/activex/AVS/Sources/TeamlabOffice/trunk/ServerComponents@57649 954022d7-b5bf-4e40-9824-e11837661b57
This commit is contained in:
committed by
Alexander Trofimov
parent
97a1a37e85
commit
be359013ee
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -317,6 +317,8 @@ Common/ASCDocxFormat/Lib/Release/Common.lib svn_mime_002dtype=application%2Focte
|
||||
Common/ASCDocxFormat/Lib/Release/DocxFormat.lib svn_mime_002dtype=application%2Foctet-stream
|
||||
Common/ASCDocxFormat/Lib/Release/Utility.lib svn_mime_002dtype=application%2Foctet-stream
|
||||
Common/ASCDocxFormat/Lib/Release/XML.lib svn_mime_002dtype=application%2Foctet-stream
|
||||
Common/DocxFormat/Source/CompoundDocument svnc_tsvn_003alogminsize=5
|
||||
Common/DocxFormat/Source/CompoundDocument/detail svnc_tsvn_003alogminsize=5
|
||||
Common/DocxFormat/Source/SystemUtility/Solution/FileSystemTest/app.ico svn_mime_002dtype=application%2Foctet-stream
|
||||
Common/DocxFormat/Source/XML/libxml2/LIBXML2_LIB_TEST svnc_tsvn_003alogminsize=5
|
||||
Common/DocxFormat/Source/XML/libxml2/XML/doc/DOM.gif svn_mime_002dtype=application%2Foctet-stream
|
||||
|
||||
205
Common/DocxFormat/Source/CompoundDocument/detail/alloctable.hpp
Normal file
205
Common/DocxFormat/Source/CompoundDocument/detail/alloctable.hpp
Normal file
@ -0,0 +1,205 @@
|
||||
/* POLE - Portable C++ library to access OLE Storage
|
||||
Copyright (C) 2005-2006 Jorge Lodos Vigil
|
||||
Copyright (C) 2002-2005 Ariya Hidayat <ariya@kde.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of the authors nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
|
||||
*/
|
||||
|
||||
// AllocTableT header
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include "util.hpp"
|
||||
|
||||
namespace POLE
|
||||
{
|
||||
|
||||
template<typename _>
|
||||
class AllocTableT
|
||||
{
|
||||
public:
|
||||
static const ULONG32 Eof;
|
||||
static const ULONG32 Avail;
|
||||
static const ULONG32 Bat;
|
||||
static const ULONG32 MetaBat;
|
||||
|
||||
// Construction/destruction
|
||||
public:
|
||||
AllocTableT(ULONG32 block_size = 4096) { set_block_size(block_size); }
|
||||
|
||||
// Attributes
|
||||
public:
|
||||
size_t count() const { return _data.size(); } // number of blocks
|
||||
ULONG32 block_size() const { return _block_size; } // block size
|
||||
ULONG32 operator[]( size_t index ) const { return _data[index]; }
|
||||
bool follow( ULONG32 start, std::vector<ULONG32>& chain ) const;
|
||||
|
||||
// Operations
|
||||
public:
|
||||
void set_block_size(ULONG32 size) { _block_size = size; _data.clear(); resize( 128 ); }
|
||||
void set_chain( const std::vector<ULONG32>& chain );
|
||||
|
||||
bool load( const unsigned char* buffer, size_t len );
|
||||
bool save( unsigned char* buffer, size_t len );
|
||||
#ifndef NDEBUG
|
||||
void debug() const;
|
||||
#endif
|
||||
|
||||
// Implementation
|
||||
private:
|
||||
void resize( size_t newsize ) { _data.resize( newsize, Avail); }
|
||||
size_t unused();
|
||||
void preserve( size_t n ) { unused(); }
|
||||
void set( size_t index, ULONG32 val );
|
||||
|
||||
std::vector<ULONG32> _data;
|
||||
ULONG32 _block_size;
|
||||
|
||||
AllocTableT( const AllocTableT& ); // No copy construction
|
||||
AllocTableT& operator=( const AllocTableT& ); // No copy operator
|
||||
};
|
||||
|
||||
typedef AllocTableT<void> AllocTable;
|
||||
|
||||
// =========== AllocTableT Implementation ==========
|
||||
|
||||
template<typename _>
|
||||
const ULONG32 AllocTableT<_>::Avail = 0xffffffff;
|
||||
template<typename _>
|
||||
const ULONG32 AllocTableT<_>::Eof = 0xfffffffe;
|
||||
template<typename _>
|
||||
const ULONG32 AllocTableT<_>::Bat = 0xfffffffd;
|
||||
template<typename _>
|
||||
const ULONG32 AllocTableT<_>::MetaBat = 0xfffffffc;
|
||||
|
||||
|
||||
template<typename _>
|
||||
void AllocTableT<_>::set( size_t index, ULONG32 value )
|
||||
{
|
||||
if ( index >= count() )
|
||||
resize( index + 1);
|
||||
_data[ index ] = value;
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
void AllocTableT<_>::set_chain( const std::vector<ULONG32>& chain )
|
||||
{
|
||||
size_t chain_size = chain.size();
|
||||
if ( chain_size )
|
||||
{
|
||||
for( size_t i = 0; i<chain_size-1; i++ )
|
||||
set( chain[i], chain[i+1] );
|
||||
set( chain[ chain_size-1 ], Eof );
|
||||
}
|
||||
}
|
||||
|
||||
// follow
|
||||
template<typename _>
|
||||
bool AllocTableT<_>::follow( ULONG32 start, std::vector<ULONG32>& chain ) const
|
||||
{
|
||||
//assert(chain.size() == 0);
|
||||
|
||||
size_t blocks = count();
|
||||
if( start >= blocks )
|
||||
return false;
|
||||
|
||||
ULONG32 p = start;
|
||||
chain.reserve(blocks);
|
||||
for (size_t loop_control = 0; p < blocks; ++loop_control)
|
||||
{
|
||||
if (loop_control >= blocks)
|
||||
return false;
|
||||
chain.push_back( p );
|
||||
p = _data[ p ];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
size_t AllocTableT<_>::unused()
|
||||
{
|
||||
// find first available block
|
||||
size_t blocks = count();
|
||||
for( size_t i = 0; i < blocks; i++ )
|
||||
if( _data[i] == Avail )
|
||||
return i;
|
||||
|
||||
// completely full, so enlarge the table
|
||||
resize( blocks + 10 );
|
||||
return count();
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
bool AllocTableT<_>::load( const unsigned char* buffer, size_t len )
|
||||
{
|
||||
if (len%4 || !buffer)
|
||||
return false;
|
||||
|
||||
resize( len / 4 );
|
||||
size_t blocks = count();
|
||||
for( size_t i = 0; i < blocks; i++ )
|
||||
_data[ i ] = readU32( buffer + i*4 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
bool AllocTableT<_>::save( unsigned char* buffer, size_t len )
|
||||
{
|
||||
if (len < 4*count() || !buffer)
|
||||
return false;
|
||||
|
||||
size_t blocks = count();
|
||||
for( size_t i = 0; i < blocks; i++ )
|
||||
writeU32( buffer + i*4, _data[i] );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
template<typename _>
|
||||
void AllocTableT<_>::debug() const
|
||||
{
|
||||
std::cout << "block size " << _data.size() << std::endl;
|
||||
for( size_t i=0; i< _data.size(); i++ )
|
||||
{
|
||||
if( _data[i] == Avail )
|
||||
continue;
|
||||
std::cout << i << ": ";
|
||||
if( _data[i] == Eof )
|
||||
std::cout << "[eof]";
|
||||
else if( _data[i] == Bat )
|
||||
std::cout << "[bat]";
|
||||
else if( _data[i] == MetaBat )
|
||||
std::cout << "[metabat]";
|
||||
else std::cout << _data[i];
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace POLE
|
||||
791
Common/DocxFormat/Source/CompoundDocument/detail/dirtree.hpp
Normal file
791
Common/DocxFormat/Source/CompoundDocument/detail/dirtree.hpp
Normal file
@ -0,0 +1,791 @@
|
||||
/* POLE - Portable C++ library to access OLE Storage
|
||||
Copyright (C) 2005-2006 Jorge Lodos Vigil
|
||||
Copyright (C) 2002-2005 Ariya Hidayat <ariya@kde.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of the authors nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
|
||||
*/
|
||||
|
||||
// dirtree header
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include "util.hpp"
|
||||
|
||||
namespace POLE
|
||||
{
|
||||
|
||||
template<typename _>
|
||||
class DirEntryT
|
||||
{
|
||||
public:
|
||||
static const unsigned End;
|
||||
|
||||
// Construction/destruction
|
||||
public:
|
||||
DirEntryT():
|
||||
_name("Root Entry"),
|
||||
_type(5),
|
||||
_size(0),
|
||||
_start(End),
|
||||
_prev(End),
|
||||
_next(End),
|
||||
_child(End),
|
||||
_index(0),
|
||||
_parent(0)
|
||||
{}
|
||||
DirEntryT(const std::string& name, ULONG8 type, ULONG32 size, ULONG32 start, ULONG32 prev, ULONG32 next, ULONG32 child, ULONG32 index, ULONG32 parent)
|
||||
{
|
||||
set(name, type, size, start, prev, next, child, index, parent);
|
||||
}
|
||||
|
||||
// Attributes
|
||||
public:
|
||||
bool valid() const;
|
||||
const std::string& name() const { return _name; }
|
||||
ULONG8 type() const { return _type; }
|
||||
bool root() const { return (_type == 5); }
|
||||
bool dir() const { return ((_type == 1) || (_type == 5)); }
|
||||
bool file() const { return (_type == 2); }
|
||||
ULONG32 size() const { return _size; }
|
||||
ULONG32 start() const { return _start; }
|
||||
ULONG32 prev() const { return _prev; }
|
||||
ULONG32 next() const { return _next; }
|
||||
ULONG32 child() const { return _child; }
|
||||
ULONG32 index() const { return _index; }
|
||||
ULONG32 parent() const { return _parent; }
|
||||
|
||||
// Operations
|
||||
public:
|
||||
void set(const std::string& name, ULONG8 type, ULONG32 size, ULONG32 start, ULONG32 prev, ULONG32 next, ULONG32 child, ULONG32 index, ULONG32 parent)
|
||||
{
|
||||
_name = name;
|
||||
_type = type;
|
||||
_size = size;
|
||||
_start = start;
|
||||
_prev = prev;
|
||||
_next = next;
|
||||
_child = child;
|
||||
_index = index;
|
||||
_parent = parent;
|
||||
}
|
||||
void set_prev(ULONG32 prev) { _prev = prev; }
|
||||
void set_next(ULONG32 next) { _next = next; }
|
||||
void set_child(ULONG32 child) { _child = child; }
|
||||
void set_parent(ULONG32 parent) { _parent = parent; }
|
||||
#ifndef NDEBUG
|
||||
void debug() const;
|
||||
#endif
|
||||
|
||||
// Implementation
|
||||
private:
|
||||
std::string _name; // the name, not in unicode anymore
|
||||
ULONG8 _type; // true if directory
|
||||
ULONG32 _size; // size (not valid if directory)
|
||||
ULONG32 _start; // starting block
|
||||
ULONG32 _prev; // previous sibling
|
||||
ULONG32 _next; // next sibling
|
||||
ULONG32 _child; // first child
|
||||
ULONG32 _index; // index of the entry in the directory
|
||||
ULONG32 _parent; // parent in the directory structure. Must be a folder.
|
||||
};
|
||||
|
||||
typedef DirEntryT<void> DirEntry;
|
||||
|
||||
template<typename _>
|
||||
class DirTreeT
|
||||
{
|
||||
// Construction/destruction
|
||||
public:
|
||||
DirTreeT() { clear(); }
|
||||
|
||||
// Attributes
|
||||
public:
|
||||
size_t entryCount() const { return _entries.size(); }
|
||||
void listAll(std::vector<const DirEntry*>&) const;
|
||||
ULONG32 parent( ULONG32 index ) const;
|
||||
ULONG32 parentDirectory( ULONG32 index ) const;
|
||||
void fullName( ULONG32 index, std::string& ) const;
|
||||
void current_path( std::string& result) const { fullName( _current, result ); }
|
||||
const DirEntry* root_entry() const { return entry( 0 ); }
|
||||
const DirEntry* current_entry() const { return entry( _current ); }
|
||||
void children( ULONG32 index, std::vector<ULONG32>& ) const;
|
||||
void listDirectory(std::vector<const DirEntry*>&) const;
|
||||
const DirEntry* entry( ULONG32 index ) const;
|
||||
|
||||
// Operations
|
||||
public:
|
||||
void clear();
|
||||
const DirEntry* entry( const std::string& name, bool create=false ) { return _entry(name, create); }
|
||||
bool enterDirectory( const std::string& dir );
|
||||
void leaveDirectory();
|
||||
|
||||
bool delete_entry(const std::string& path) { return delete_entry(path, 0); }
|
||||
ULONG32 search_prev_link( ULONG32 entry );
|
||||
ULONG32 find_rightmost_sibling(ULONG32 left_sib);
|
||||
bool set_prev_link(ULONG32 prev_link, ULONG32 entry, ULONG32 value);
|
||||
|
||||
bool load( unsigned char* buffer, size_t len );
|
||||
bool save( unsigned char* buffer, size_t len );
|
||||
#ifndef NDEBUG
|
||||
void debug() const;
|
||||
#endif
|
||||
|
||||
// Implementation
|
||||
private:
|
||||
DirEntry* entry( ULONG32 index );
|
||||
DirEntry* _entry( const std::string& name, bool create = false );
|
||||
void find_siblings( std::vector<ULONG32>& result, ULONG32 index ) const;
|
||||
bool delete_entry(const std::string& path, int level);
|
||||
void set_parents();
|
||||
void set_parents(DirEntry * cur_entry, ULONG32 cur_parent);
|
||||
|
||||
ULONG32 _current;
|
||||
std::vector<DirEntry> _entries;
|
||||
|
||||
DirTreeT( const DirTreeT<_>& );
|
||||
DirTreeT<_>& operator=( const DirTreeT<_>& );
|
||||
};
|
||||
|
||||
typedef DirTreeT<void> DirTree;
|
||||
|
||||
// =========== DirEntryT ==========
|
||||
|
||||
template<typename _>
|
||||
const unsigned DirEntryT<_>::End = 0xffffffff;
|
||||
|
||||
template<typename _>
|
||||
bool DirEntryT<_>::valid() const
|
||||
{
|
||||
//if ((_type == 1 ) && (_size != 0 ))
|
||||
// return false;
|
||||
if ((_type != 1 ) && (_type != 2 ) && (_type != 5 ))
|
||||
return false;
|
||||
if (_name.empty())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
template<typename _>
|
||||
void DirEntryT<_>::debug() const
|
||||
{
|
||||
if( !valid() ) std::cout << "INVALID ";
|
||||
std::cout << name() << " ";
|
||||
if( valid() ) std::cout << "(Valid) ";
|
||||
else std::cout << "(Invalid) ";
|
||||
if( dir() ) std::cout << "(Dir) ";
|
||||
else std::cout << "(File) ";
|
||||
std::cout << index() << " ";
|
||||
std::cout << size() << " ";
|
||||
std::cout << "s:" << start() << " ";
|
||||
std::cout << "(";
|
||||
if( child() == DirEntry::End ) std::cout << "-"; else std::cout << child();
|
||||
std::cout << " ";
|
||||
if( prev() == DirEntry::End ) std::cout << "-"; else std::cout << prev();
|
||||
std::cout << ":";
|
||||
if( next() == DirEntry::End ) std::cout << "-"; else std::cout << next();
|
||||
std::cout << ") ";
|
||||
std::cout << parent();
|
||||
std::cout << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
// =========== DirTree ==========
|
||||
|
||||
template<typename _>
|
||||
void DirTreeT<_>::clear()
|
||||
{
|
||||
// leave only the root entry
|
||||
_entries.resize( 1 );
|
||||
_current = 0;
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
const DirEntry* DirTreeT<_>::entry( ULONG32 index ) const
|
||||
{
|
||||
if( index >= entryCount() ) return NULL;
|
||||
return &_entries[ index ];
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
DirEntry* DirTreeT<_>::entry( ULONG32 index )
|
||||
{
|
||||
if( index >= entryCount() ) return NULL;
|
||||
return &_entries[ index ];
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
ULONG32 DirTreeT<_>::parentDirectory( ULONG32 index ) const
|
||||
{
|
||||
const DirEntry * e = entry(index);
|
||||
if (!e) return DirEntry::End;
|
||||
assert(e->valid());
|
||||
|
||||
#ifndef NDEBUG
|
||||
const DirEntry * test = entry(e->parent());
|
||||
assert(test);
|
||||
assert(test->valid());
|
||||
assert(test->dir());
|
||||
#endif
|
||||
|
||||
return e->parent();
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
ULONG32 DirTreeT<_>::parent( ULONG32 index ) const
|
||||
{
|
||||
// brute-force, basically we iterate for all entries, find its children
|
||||
// and check if one of the children is 'index'
|
||||
std::vector<DirEntry>::const_iterator it;
|
||||
for (it = _entries.begin(); it != _entries.end(); ++it)
|
||||
if (it->valid() && it->child() == index)
|
||||
return it->index();
|
||||
|
||||
return DirEntry::End;
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
void DirTreeT<_>::fullName( ULONG32 index, std::string& result ) const
|
||||
{
|
||||
const DirEntry* e = entry( index );
|
||||
if( !e )
|
||||
return;
|
||||
|
||||
// don't use root name ("Root Entry"), just give "/"
|
||||
if( index == 0 )
|
||||
{
|
||||
result = "/";
|
||||
return;
|
||||
}
|
||||
|
||||
result = e->name();
|
||||
result.insert( 0, "/" );
|
||||
ULONG32 p = parentDirectory( index );
|
||||
if (p == -1)
|
||||
return;
|
||||
const DirEntry* _entry = 0;
|
||||
while( p > 0 )
|
||||
{
|
||||
_entry = entry( p );
|
||||
if (_entry && _entry->dir() && _entry->valid())
|
||||
{
|
||||
result.insert( 0, _entry->name());
|
||||
result.insert( 0, "/" );
|
||||
}
|
||||
p = parentDirectory(p);
|
||||
if (p == DirEntry::End)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Given a fullname (e.g "/ObjectPool/_1020961869"), find the entry.
|
||||
// If not found and create is false, return 0.
|
||||
// If create is true, and name ends with '/' a new dir entry is returned.
|
||||
// If create is true, and name does not end with '/' a new file entry is returned.
|
||||
template<typename _>
|
||||
DirEntry* DirTreeT<_>::_entry( const std::string& name, bool create )
|
||||
{
|
||||
if( name.empty() )
|
||||
return NULL;
|
||||
|
||||
// quick check for "/" (that's root)
|
||||
if( name == "/" ) return &_entries[0];
|
||||
|
||||
// get the parent and child, e.g "/ObjectPool/_1020961869" will become:
|
||||
// "/ObjectPool" and "_1020961869". "/Data" will become "/" and "Data".
|
||||
|
||||
std::string parent;
|
||||
std::string child;
|
||||
std::string::size_type name_pos = name.rfind('/');
|
||||
if ( name_pos == name.length()-1)
|
||||
name_pos = name.rfind('/', name_pos);
|
||||
if (name_pos != std::string::npos && name_pos != 0)
|
||||
{
|
||||
parent = name.substr( 0, name_pos );
|
||||
child = name.substr(name_pos+1);
|
||||
}
|
||||
else if (name_pos == 0)
|
||||
{
|
||||
parent = "/";
|
||||
child = name.substr(1);
|
||||
}
|
||||
else
|
||||
child = name;
|
||||
if (child[child.length()-1] == '/')
|
||||
child.erase(child.length()-1);
|
||||
|
||||
// start from root when name is absolute
|
||||
// or current directory when name is relative
|
||||
ULONG32 index = (name[0] == '/' ) ? 0 : _current;
|
||||
|
||||
const DirEntry* pe = (parent.empty()) ? entry( index ) : entry( parent, create );
|
||||
if (!pe) return NULL;
|
||||
if (!pe->valid()) return NULL;
|
||||
assert(pe->dir());
|
||||
|
||||
// search entries with the same parent
|
||||
std::vector<DirEntry>::iterator it;
|
||||
for (it = _entries.begin(); it != _entries.end(); ++it)
|
||||
if (pe->index() == it->parent() && it->valid())
|
||||
if (it->name().length() == child.length())
|
||||
{
|
||||
size_t j;
|
||||
for (j = 0; j<it->name().length(); ++j)
|
||||
if( tolower(child[j]) != tolower(it->name()[j]) )
|
||||
break;
|
||||
if (j == it->name().length())
|
||||
return &(*it); // found
|
||||
}
|
||||
|
||||
if (!create)
|
||||
return NULL; // not found
|
||||
|
||||
// create a new entry
|
||||
assert(parent.empty());
|
||||
DirEntry* ep = &_entries[index];
|
||||
ULONG8 type = (name[name.length()-1] == '/') ? 1 : 2;
|
||||
index = (ULONG32)entryCount();
|
||||
DirEntry ne(child, type, 0, 0, DirEntry::End, DirEntry::End, ep->child(), index, ep->index());
|
||||
_entries.push_back( ne );
|
||||
ep->set_child(index);
|
||||
return entry( index );
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
void DirTreeT<_>::children( ULONG32 index, std::vector<ULONG32>& result ) const
|
||||
{
|
||||
const DirEntry* e = entry( index );
|
||||
if( e && e->valid() && e->dir() )
|
||||
find_siblings( result, e->child() );
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
void DirTreeT<_>::listAll(std::vector<const DirEntry*>& result) const
|
||||
{
|
||||
size_t size = _entries.size();
|
||||
result.reserve(size);
|
||||
for( size_t i = 0; i < size; i++ )
|
||||
if (_entries[i].valid())
|
||||
result.push_back( &_entries[i] );
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
void DirTreeT<_>::listDirectory(std::vector<const DirEntry*>& result) const
|
||||
{
|
||||
std::vector<ULONG32> chi;
|
||||
children( _current, chi );
|
||||
size_t size = chi.size();
|
||||
result.reserve(size);
|
||||
for( size_t i = 0; i < size; i++ )
|
||||
result.push_back( entry( chi[i] ) );
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
bool DirTreeT<_>::enterDirectory( const std::string& dir )
|
||||
{
|
||||
const DirEntry* e = entry( dir );
|
||||
if( !e )
|
||||
return false;
|
||||
if( !e->valid() )
|
||||
return false;
|
||||
if( !e->dir() )
|
||||
return false;
|
||||
|
||||
ULONG32 index = e->index();
|
||||
if( index == DirEntry::End) return false;
|
||||
|
||||
_current = index;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
void DirTreeT<_>::leaveDirectory()
|
||||
{
|
||||
// already at root ?
|
||||
if( _current == 0 )
|
||||
return;
|
||||
|
||||
ULONG32 p = parentDirectory( _current );
|
||||
if( p != DirEntry::End)
|
||||
_current = p;
|
||||
#ifndef NDEBUG
|
||||
else
|
||||
assert(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
bool DirTreeT<_>::load( unsigned char* buffer, size_t size )
|
||||
{
|
||||
_entries.clear();
|
||||
_current = 0;
|
||||
size_t init_count = size / 128;
|
||||
|
||||
_entries.reserve(init_count);
|
||||
for( unsigned i = 0; i < init_count; i++ )
|
||||
{
|
||||
unsigned p = i * 128;
|
||||
|
||||
// Name's length
|
||||
int name_len = readU16( buffer + 0x40+p );
|
||||
// parse name of this entry, which stored as Unicode 16-bit
|
||||
std::string name;
|
||||
name.reserve(name_len);
|
||||
// Read name char by char
|
||||
if( name_len > 64 ) name_len = 64;
|
||||
for( int j=0; ( buffer[j + p]) && (j < name_len); j+= 2 )
|
||||
name.append( 1, buffer[j + p] );
|
||||
|
||||
// 1 = directory (aka storage), 2 = file (aka stream), 5 = root
|
||||
ULONG8 type = buffer[ 0x42 + p];
|
||||
ULONG32 start = readU32( buffer + 0x74+p );
|
||||
ULONG32 size = readU32( buffer + 0x78+p );
|
||||
ULONG32 prev = readU32( buffer + 0x44+p );
|
||||
ULONG32 next = readU32( buffer + 0x48+p );
|
||||
ULONG32 child = readU32( buffer + 0x4C+p );
|
||||
|
||||
DirEntry e(name, type, size, start, prev, next, child, i, 0);
|
||||
_entries.push_back( e );
|
||||
}
|
||||
set_parents();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
bool DirTreeT<_>::save( unsigned char* buffer, size_t len )
|
||||
{
|
||||
size_t size = 128*entryCount();
|
||||
if (len < size)
|
||||
return false;
|
||||
memset( buffer, 0, size );
|
||||
|
||||
for( unsigned i = 0; i < entryCount(); i++ )
|
||||
{
|
||||
const DirEntry* e = entry( i );
|
||||
if( !e ) return false;
|
||||
|
||||
// max length for name is 32 chars
|
||||
std::string name = e->name();
|
||||
if( name.length() > 32 )
|
||||
name.erase( 32, name.length() );
|
||||
|
||||
// write name as Unicode 16-bit
|
||||
for( unsigned j = 0; j < name.length(); j++ )
|
||||
buffer[ i*128 + j*2 ] = name[j];
|
||||
|
||||
writeU16( buffer + i*128 + 0x40, (ULONG16)(name.length()*2 + 2) );
|
||||
writeU32( buffer + i*128 + 0x74, e->start() );
|
||||
writeU32( buffer + i*128 + 0x78, e->size() );
|
||||
writeU32( buffer + i*128 + 0x44, e->prev() );
|
||||
writeU32( buffer + i*128 + 0x48, e->next() );
|
||||
writeU32( buffer + i*128 + 0x4c, e->child() );
|
||||
buffer[ i*128 + 0x42 ] = e->type();
|
||||
buffer[ i*128 + 0x43 ] = 1; // always black
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
template<typename _>
|
||||
void DirTreeT<_>::debug() const
|
||||
{
|
||||
for( unsigned i = 0; i < entryCount(); i++ )
|
||||
{
|
||||
const DirEntry* e = entry( i );
|
||||
if( !e ) continue;
|
||||
std::cout << i << ": ";
|
||||
e->debug();
|
||||
}
|
||||
std::vector<size_t> res;
|
||||
children(0, res);
|
||||
std::cout << std::endl << std::endl << "--------------------------" << std::endl;
|
||||
for (unsigned int i = 0; i < res.size(); ++i)
|
||||
{
|
||||
std::cout << res[i] << std::endl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// helper function: recursively find siblings of index
|
||||
template<typename _>
|
||||
void DirTreeT<_>::find_siblings( std::vector<ULONG32>& result, ULONG32 index ) const
|
||||
{
|
||||
const DirEntry* e = entry( index );
|
||||
if( !e ) return;
|
||||
if( !e->valid() ) return;
|
||||
|
||||
// search entries with the same parent
|
||||
result.reserve(_entries.size()); // for efficiency
|
||||
std::vector<DirEntry>::const_iterator it;
|
||||
for (it = _entries.begin(); it != _entries.end(); ++it)
|
||||
if (e->parent() == it->parent() && it->valid() && !it->root())
|
||||
{
|
||||
result.push_back(it->index());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
bool DirTreeT<_>::delete_entry(const std::string& path, int level)
|
||||
{
|
||||
// Deletion is not posible over Root Entry
|
||||
if (path == "/")
|
||||
return false;
|
||||
DirEntry *e = _entry(path);
|
||||
// Hack: Should an invalid path throw and exception?
|
||||
if (!e)
|
||||
return false;
|
||||
// Is a Storage?
|
||||
if (e->type() == 1)
|
||||
{
|
||||
// Has Child?
|
||||
if (e->child() != DirEntry::End)
|
||||
{
|
||||
DirEntry *child = entry(e->child());
|
||||
std::string _child_path = path + ((path[path.size()] == '/') ? child->name() : std::string("/") + child->name());
|
||||
level++;
|
||||
if (!delete_entry(_child_path, level))
|
||||
return false;
|
||||
e->set_child(DirEntry::End);
|
||||
level--;
|
||||
}
|
||||
}
|
||||
// This is not the first call. Searching for brothers
|
||||
if (level)
|
||||
{
|
||||
// Has right sibling?
|
||||
if (e->prev() != DirEntry::End)
|
||||
{
|
||||
// Find the previous entry
|
||||
DirEntry *pe = entry(e->prev());
|
||||
if (!pe)
|
||||
return false;
|
||||
std::string _child_path;
|
||||
std::string::size_type _pos = path.find_last_of("/");
|
||||
|
||||
if (_pos != std::string::npos)
|
||||
_child_path = path.substr(0, path.size() - ((path.size() - _pos) - 1)) + pe->name();
|
||||
else
|
||||
return false;
|
||||
|
||||
level++;
|
||||
if (!delete_entry(_child_path, level))
|
||||
return false;
|
||||
e->set_prev(DirEntry::End);
|
||||
level--;
|
||||
}
|
||||
// Has left sibling?
|
||||
if (e->next() != DirEntry::End)
|
||||
{
|
||||
// Find the previous entry
|
||||
DirEntry *pe = entry(e->next());
|
||||
if (!pe)
|
||||
return false;
|
||||
std::string _child_path;
|
||||
std::string::size_type _pos = path.find_last_of("/");
|
||||
|
||||
if (_pos != std::string::npos)
|
||||
_child_path = path.substr(0, path.size() - ((path.size() - _pos) - 1)) + pe->name();
|
||||
else
|
||||
return false;
|
||||
|
||||
level++;
|
||||
if (!delete_entry(_child_path, level))
|
||||
return false;
|
||||
e->set_next(DirEntry::End);
|
||||
level--;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the entry
|
||||
if (level == 0)
|
||||
{
|
||||
// This is not an recursive call
|
||||
// Find the entry that points to the entry is being deleted
|
||||
size_t prev_link = search_prev_link(e->index());
|
||||
if (prev_link == -1)
|
||||
return false;
|
||||
// Last entry?
|
||||
if (e->next() == DirEntry::End &&
|
||||
e->prev() == DirEntry::End)
|
||||
{
|
||||
// Set the end of chain mark in the entry that points to the entry
|
||||
// being deleted
|
||||
if (!set_prev_link(prev_link, e->index(), DirEntry::End))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// It is not the last one, but has a sibling
|
||||
if(e->next() == DirEntry::End ||
|
||||
e->prev() == DirEntry::End)
|
||||
{
|
||||
// If hasn't a previous sibling, set previous link to point
|
||||
// to the next field of the entry being deleted
|
||||
if (e->prev() == DirEntry::End)
|
||||
{
|
||||
if (!set_prev_link(prev_link, e->index(), e->next()))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
// If hasn't a next sibling, set previous link to point
|
||||
// to the prev field of the entry being deleted
|
||||
if (!set_prev_link(prev_link, e->index(), e->prev()))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If has a previous and a next sibling, find the right most sibling
|
||||
// pointed by the next field of the entry being deleted, set this entry's previous field
|
||||
// to point to the prev field of the entry being deleted.
|
||||
// Then set previous link to point to the next field of the entry being deleted.
|
||||
size_t right_most = find_rightmost_sibling(e->next());
|
||||
if (right_most == -1)
|
||||
return false;
|
||||
DirEntry *_right = entry(right_most);
|
||||
if (!_right) return false;
|
||||
_right->set_prev(e->prev());
|
||||
|
||||
if (!set_prev_link(prev_link, e->index(), e->next()))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
e->set("", 0, 0, 0, 0, DirEntry::End, DirEntry::End, DirEntry::End, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
ULONG32 DirTreeT<_>::search_prev_link( ULONG32 _entry )
|
||||
{
|
||||
// Find parent
|
||||
size_t par_index = parent(_entry);
|
||||
if (par_index == -1)
|
||||
return false;
|
||||
if (_entries[par_index].child() == _entry)
|
||||
return par_index;
|
||||
else
|
||||
{
|
||||
std::vector<ULONG32> brothers;
|
||||
children(par_index, brothers);
|
||||
if (brothers.size() == 0)
|
||||
return false;
|
||||
for (size_t ndx = 0; ndx < brothers.size(); ++ndx)
|
||||
{
|
||||
if (_entries[brothers[ndx]].next() == _entry ||
|
||||
_entries[brothers[ndx]].prev() == _entry)
|
||||
{
|
||||
return brothers[ndx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DirEntry::End;
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
bool DirTreeT<_>::set_prev_link(ULONG32 prev_link, ULONG32 index, ULONG32 value)
|
||||
{
|
||||
DirEntry * pl = entry(prev_link);
|
||||
if (!pl) return false;
|
||||
|
||||
if (pl->prev() == index)
|
||||
pl->set_prev(value);
|
||||
if (pl->next() == index)
|
||||
pl->set_next(value);
|
||||
if (pl->child() == index)
|
||||
pl->set_child(value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
ULONG32 DirTreeT<_>::find_rightmost_sibling(ULONG32 sib)
|
||||
{
|
||||
DirEntry * _ent = entry(sib);
|
||||
if (!_ent)
|
||||
return DirEntry::End;
|
||||
if (_ent->prev() == DirEntry::End)
|
||||
return _ent->index();
|
||||
return find_rightmost_sibling(_ent->prev());
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
void DirTreeT<_>::set_parents()
|
||||
{
|
||||
if (_entries.size())
|
||||
{
|
||||
// The parent is already set to 0
|
||||
if (_entries[0].valid())
|
||||
{
|
||||
DirEntry * _child = entry(_entries[0].child());
|
||||
if (_child && _child->valid())
|
||||
{
|
||||
_child->set_parent(0);
|
||||
set_parents(_child, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
void DirTreeT<_>::set_parents(DirEntry * cur_entry, ULONG32 cur_parent)
|
||||
{
|
||||
assert(cur_entry);
|
||||
assert(cur_entry->valid());
|
||||
|
||||
if (cur_entry->dir())
|
||||
{
|
||||
DirEntry * _child = entry(cur_entry->child());
|
||||
// the last condition prevents loops
|
||||
if (_child && _child->valid() && _child->parent() == 0)
|
||||
{
|
||||
_child->set_parent(cur_entry->index());
|
||||
set_parents(_child, cur_entry->index());
|
||||
}
|
||||
}
|
||||
|
||||
DirEntry * _prev = entry(cur_entry->prev());
|
||||
// the last condition prevents loops
|
||||
if (_prev && _prev->valid() && _prev->parent() == 0)
|
||||
{
|
||||
_prev->set_parent(cur_parent);
|
||||
set_parents(_prev, cur_parent);
|
||||
}
|
||||
|
||||
DirEntry * _next = entry(cur_entry->next());
|
||||
// the last condition prevents loops
|
||||
if (_next && _next->valid() && _next->parent() == 0)
|
||||
{
|
||||
_next->set_parent(cur_parent);
|
||||
set_parents(_next, cur_parent);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
213
Common/DocxFormat/Source/CompoundDocument/detail/header.hpp
Normal file
213
Common/DocxFormat/Source/CompoundDocument/detail/header.hpp
Normal file
@ -0,0 +1,213 @@
|
||||
/* POLE - Portable C++ library to access OLE Storage
|
||||
Copyright (C) 2005-2006 Jorge Lodos Vigil
|
||||
Copyright (C) 2002-2005 Ariya Hidayat <ariya@kde.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of the authors nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
|
||||
*/
|
||||
|
||||
// header.hpp
|
||||
#pragma once
|
||||
#include "alloctable.hpp"
|
||||
|
||||
namespace POLE
|
||||
{
|
||||
|
||||
template<typename _>
|
||||
class HeaderT
|
||||
{
|
||||
public:
|
||||
static const unsigned char pole_magic[];
|
||||
|
||||
// Construction/destruction
|
||||
public:
|
||||
HeaderT();
|
||||
|
||||
// Attributes
|
||||
public:
|
||||
const unsigned char* id() const { return _id; }
|
||||
unsigned b_shift() const { return _b_shift; }
|
||||
unsigned s_shift() const { return _s_shift; }
|
||||
unsigned num_bat() const { return _num_bat; }
|
||||
unsigned dirent_start() const { return _dirent_start; }
|
||||
unsigned threshold() const { return _threshold; }
|
||||
unsigned sbat_start() const { return _sbat_start; }
|
||||
unsigned num_sbat() const { return _num_sbat; }
|
||||
unsigned mbat_start() const { return _mbat_start; }
|
||||
unsigned num_mbat() const { return _num_mbat; }
|
||||
const ULONG32* bb_blocks() const { return _bb_blocks; }
|
||||
bool valid() const;
|
||||
bool is_ole() const;
|
||||
|
||||
// Operations
|
||||
public:
|
||||
bool load( const unsigned char* buffer, size_t len );
|
||||
bool save( unsigned char* buffer, size_t len );
|
||||
#ifndef NDEBUG
|
||||
void debug() const;
|
||||
#endif
|
||||
|
||||
// Implementation
|
||||
private:
|
||||
unsigned char _id[8]; // signature, or magic identifier
|
||||
unsigned _b_shift; // bbat->blockSize = 1 << b_shift [_uSectorShift]
|
||||
unsigned _s_shift; // sbat->blockSize = 1 << s_shift [_uMiniSectorShift]
|
||||
unsigned _num_bat; // blocks allocated for big bat [_csectFat]
|
||||
unsigned _dirent_start; // starting block for directory info [_secDirStart]
|
||||
unsigned _threshold; // switch from small to big file (usually 4K) [_ulMiniSectorCutoff]
|
||||
unsigned _sbat_start; // starting block index to store small bat [_sectMiniFatStart]
|
||||
unsigned _num_sbat; // blocks allocated for small bat [_csectMiniFat]
|
||||
unsigned _mbat_start; // starting block to store meta bat [_sectDifStart]
|
||||
unsigned _num_mbat; // blocks allocated for meta bat [_csectDif]
|
||||
ULONG32 _bb_blocks[109]; // [_sectFat]
|
||||
};
|
||||
|
||||
typedef HeaderT<void> Header;
|
||||
|
||||
// =========== HeaderT ==========
|
||||
|
||||
template<typename _>
|
||||
const unsigned char HeaderT<_>::pole_magic[] = { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 };
|
||||
|
||||
template<typename _>
|
||||
HeaderT<_>::HeaderT()
|
||||
{
|
||||
_b_shift = 9;
|
||||
_s_shift = 6;
|
||||
_num_bat = 0;
|
||||
_dirent_start = 0;
|
||||
_threshold = 4096;
|
||||
_sbat_start = 0;
|
||||
_num_sbat = 0;
|
||||
_mbat_start = 0;
|
||||
_num_mbat = 0;
|
||||
|
||||
unsigned i = 0;
|
||||
for(; i < 8; i++ )
|
||||
_id[i] = pole_magic[i];
|
||||
for( i=0; i<109; i++ )
|
||||
_bb_blocks[i] = AllocTable::Avail;
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
bool HeaderT<_>::valid() const
|
||||
{
|
||||
if( _threshold != 4096 ) return false;
|
||||
if( _num_bat == 0 ) return false; //ok
|
||||
if( (_num_bat > 109) && (_num_bat > ((_num_mbat * 127) + 109))) return false; //ok
|
||||
if( (_num_bat < 109) && (_num_mbat != 0) ) return false; //ok
|
||||
if( _s_shift > _b_shift ) return false;
|
||||
if( _b_shift <= 6 ) return false;
|
||||
if( _b_shift >=31 ) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
bool HeaderT<_>::is_ole() const
|
||||
{
|
||||
for( unsigned i=0; i<8; i++ )
|
||||
if( _id[i] != pole_magic[i] )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
bool HeaderT<_>::load( const unsigned char* buffer, size_t len )
|
||||
{
|
||||
if (len < 0x4C+109 * 4 || !buffer)
|
||||
return false;
|
||||
|
||||
_b_shift = readU16( buffer + 0x1e );
|
||||
_s_shift = readU16( buffer + 0x20 );
|
||||
_num_bat = readU32( buffer + 0x2c );
|
||||
_dirent_start = readU32( buffer + 0x30 );
|
||||
_threshold = readU32( buffer + 0x38 );
|
||||
_sbat_start = readU32( buffer + 0x3c );
|
||||
_num_sbat = readU32( buffer + 0x40 );
|
||||
_mbat_start = readU32( buffer + 0x44 );
|
||||
_num_mbat = readU32( buffer + 0x48 );
|
||||
|
||||
unsigned int i = 0;
|
||||
for( ; i < 8; i++ )
|
||||
_id[i] = buffer[i];
|
||||
for( i=0; i<109; i++ )
|
||||
_bb_blocks[i] = readU32( buffer + 0x4C+i*4 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
bool HeaderT<_>::save( unsigned char* buffer, size_t len )
|
||||
{
|
||||
if (len<0x4C+109*4 || !buffer)
|
||||
return false;
|
||||
|
||||
memset( buffer, 0, 0x4c );
|
||||
memcpy( buffer, pole_magic, 8 ); // ole signature
|
||||
writeU32( buffer + 8, 0 ); // unknown
|
||||
writeU32( buffer + 12, 0 ); // unknown
|
||||
writeU32( buffer + 16, 0 ); // unknown
|
||||
writeU16( buffer + 24, 0x003e ); // revision ?
|
||||
writeU16( buffer + 26, 3 ); // version ?
|
||||
writeU16( buffer + 28, 0xfffe ); // unknown
|
||||
writeU16( buffer + 0x1e, _b_shift );
|
||||
writeU16( buffer + 0x20, _s_shift );
|
||||
writeU32( buffer + 0x2c, _num_bat );
|
||||
writeU32( buffer + 0x30, _dirent_start );
|
||||
writeU32( buffer + 0x38, _threshold );
|
||||
writeU32( buffer + 0x3c, _sbat_start );
|
||||
writeU32( buffer + 0x40, _num_sbat );
|
||||
writeU32( buffer + 0x44, _mbat_start );
|
||||
writeU32( buffer + 0x48, _num_mbat );
|
||||
|
||||
for( unsigned i=0; i<109; i++ )
|
||||
writeU32( buffer + 0x4C+i*4, _bb_blocks[i] );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
template<typename _>
|
||||
void HeaderT<_>::debug() const
|
||||
{
|
||||
std::cout << std::endl;
|
||||
std::cout << "b_shift " << _b_shift << std::endl;
|
||||
std::cout << "s_shift " << _s_shift << std::endl;
|
||||
std::cout << "num_bat " << _num_bat << std::endl;
|
||||
std::cout << "dirent_start " << _dirent_start << std::endl;
|
||||
std::cout << "threshold " << _threshold << std::endl;
|
||||
std::cout << "sbat_start " << _sbat_start << std::endl;
|
||||
std::cout << "num_sbat " << _num_sbat << std::endl;
|
||||
std::cout << "mbat_start " << _mbat_start << std::endl;
|
||||
std::cout << "num_mbat " << _num_mbat << std::endl;
|
||||
|
||||
unsigned s = (_num_bat<=109) ? _num_bat : 109;
|
||||
std::cout << "bat blocks: ";
|
||||
for( unsigned i = 0; i < s; i++ )
|
||||
std::cout << _bb_blocks[i] << " ";
|
||||
std::cout << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
600
Common/DocxFormat/Source/CompoundDocument/detail/storage.hpp
Normal file
600
Common/DocxFormat/Source/CompoundDocument/detail/storage.hpp
Normal file
@ -0,0 +1,600 @@
|
||||
/* POLE - Portable C++ library to access OLE Storage
|
||||
Copyright (C) 2005-2006 Jorge Lodos Vigil
|
||||
Copyright (C) 2002-2005 Ariya Hidayat <ariya@kde.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of the authors nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
|
||||
*/
|
||||
|
||||
// storage header
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
#include <list>
|
||||
#include "header.hpp"
|
||||
#include "dirtree.hpp"
|
||||
|
||||
#include "../../../../../../../DesktopEditor/common/File.h"
|
||||
|
||||
namespace POLE
|
||||
{
|
||||
|
||||
template<typename _>
|
||||
class StreamImplT;
|
||||
|
||||
template<typename _>
|
||||
class StorageIOT
|
||||
{
|
||||
public:
|
||||
enum { Ok, OpenFailed, OpenSmallFatFailed, NotOLE, BadOLE, UnknownError, NewOLE, StupidWorkaroundForBrokenCompiler=255 };
|
||||
|
||||
// Construction/destruction
|
||||
public:
|
||||
StorageIOT( const char* filename, std::ios_base::openmode mode, bool create);
|
||||
StorageIOT( const std::wstring& filename, std::ios_base::openmode mode, bool create);
|
||||
StorageIOT( std::iostream* stream );
|
||||
~StorageIOT();
|
||||
|
||||
// Attributes
|
||||
public:
|
||||
int result() const { return _result; }
|
||||
const Header* header() const { return _header; }
|
||||
const DirEntry* entry(const std::string& path, bool create = false) const { return _dirtree->entry(path, create); }
|
||||
void fullName( const DirEntry* entry, std::string& name) const { _dirtree->fullName( entry->index(), name); }
|
||||
void current_path( std::string& result) const { _dirtree->current_path(result); }
|
||||
const DirEntry* root_entry() const { return _dirtree->root_entry(); }
|
||||
const DirEntry* current_entry() const { return _dirtree->current_entry(); }
|
||||
void listDirectory(std::list<std::string>&) const;
|
||||
ULONG32 small_block_size() const { return (_sbat) ? _sbat->block_size() : 0; }
|
||||
ULONG32 big_block_size() const { return (_bbat) ? _bbat->block_size() : 0; }
|
||||
void listEntries(std::vector<const DirEntry*>& result) const
|
||||
{
|
||||
_dirtree->listDirectory(result);
|
||||
}
|
||||
void listAll(std::vector<const DirEntry*>& result) const
|
||||
{
|
||||
_dirtree->listAll(result);
|
||||
}
|
||||
bool follow_small_block_table( ULONG32 start, std::vector<ULONG32>& chain ) const
|
||||
{
|
||||
return (_sbat) ? _sbat->follow(start, chain) : false;
|
||||
}
|
||||
bool follow_big_block_table( ULONG32 start, std::vector<ULONG32>& chain ) const
|
||||
{
|
||||
return (_bbat) ? _bbat->follow(start, chain) : false;
|
||||
}
|
||||
|
||||
const std::vector<ULONG32>& sb_blocks() const { return _sb_blocks; }
|
||||
|
||||
void get_entry_childrens(size_t index, std::vector<size_t> result) const
|
||||
{
|
||||
_dirtree->children(index, result);
|
||||
}
|
||||
|
||||
void children( size_t index, std::vector<size_t>& result ) const
|
||||
{
|
||||
if (_dirtree)
|
||||
_dirtree->children(index, result);
|
||||
}
|
||||
|
||||
// Operations
|
||||
public:
|
||||
bool create( const char* filename );
|
||||
bool enterDirectory( const std::string& directory ) { return _dirtree->enterDirectory( directory ); }
|
||||
void leaveDirectory() { _dirtree->leaveDirectory(); }
|
||||
std::streamsize loadSmallBlocks( const std::vector<ULONG32>& blocks, unsigned char* buffer, std::streamsize maxlen );
|
||||
std::streamsize loadBigBlocks( const std::vector<ULONG32>& blocks, unsigned char* buffer, std::streamsize maxlen );
|
||||
std::streamsize loadBigBlock(ULONG32 block, unsigned char* buffer, std::streamsize maxlen);
|
||||
std::streamsize saveBlock(ULONG32 block, const unsigned char* buffer, std::streamsize maxlen);
|
||||
bool delete_entry(const std::string& path);
|
||||
bool flush();
|
||||
void notify_dirtree_changed() { m_dtmodified = true; }
|
||||
#ifndef NDEBUG
|
||||
void debug() const;
|
||||
#endif
|
||||
|
||||
|
||||
// Implementation
|
||||
private:
|
||||
void init();
|
||||
bool load();
|
||||
void close();
|
||||
|
||||
std::iostream* _stream;
|
||||
std::fstream* _file;
|
||||
ULONG32 _size; // size of the storage stream
|
||||
int _result; // result of last operation
|
||||
std::vector<ULONG32> _sb_blocks; // blocks for "small" files
|
||||
|
||||
Header* _header; // storage header
|
||||
DirTree* _dirtree; // directory tree
|
||||
AllocTable* _bbat; // allocation table for big blocks
|
||||
AllocTable* _sbat; // allocation table for small blocks
|
||||
bool m_dtmodified;
|
||||
|
||||
// no copy or assign
|
||||
StorageIOT( const StorageIOT<_>& );
|
||||
StorageIOT<_>& operator=( const StorageIOT<_>& );
|
||||
};
|
||||
|
||||
typedef StorageIOT<void> StorageIO;
|
||||
|
||||
// =========== StorageIOT ==========
|
||||
|
||||
template<typename _>
|
||||
StorageIOT<_>::StorageIOT( const char* filename, std::ios_base::openmode mode, bool create)
|
||||
{
|
||||
m_dtmodified = false;
|
||||
init();
|
||||
|
||||
// open the file, check for error
|
||||
_result = OpenFailed;
|
||||
mode |= std::ios_base::in; // we must always read
|
||||
if (create)
|
||||
mode |= std::ios_base::out | std::ios_base::trunc; // make sure the file will be created if needed
|
||||
else
|
||||
mode &= ~std::ios_base::trunc; // make sure the file won't be created
|
||||
std::fstream* file = new std::fstream( filename, std::ios::binary | mode);
|
||||
if( !file)
|
||||
return;
|
||||
if (file->fail())
|
||||
{
|
||||
delete file;
|
||||
return;
|
||||
}
|
||||
_file = file;
|
||||
_stream = file;
|
||||
if (!create)
|
||||
load();
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
StorageIOT<_>::StorageIOT( const std::wstring& filename, std::ios_base::openmode mode, bool create)
|
||||
{
|
||||
#ifdef WIN32
|
||||
m_dtmodified = false;
|
||||
init();
|
||||
|
||||
// open the file, check for error
|
||||
_result = OpenFailed;
|
||||
mode |= std::ios_base::in; // we must always read
|
||||
if (create)
|
||||
mode |= std::ios_base::out | std::ios_base::trunc; // make sure the file will be created if needed
|
||||
else
|
||||
mode &= ~std::ios_base::trunc; // make sure the file won't be created
|
||||
std::fstream* file = new std::fstream( filename.c_str(), std::ios::binary | mode);
|
||||
if( !file)
|
||||
return;
|
||||
if (file->fail())
|
||||
{
|
||||
delete file;
|
||||
return;
|
||||
}
|
||||
_file = file;
|
||||
_stream = file;
|
||||
if (!create)
|
||||
load();
|
||||
#else
|
||||
m_dtmodified = false;
|
||||
init();
|
||||
|
||||
// open the file, check for error
|
||||
_result = OpenFailed;
|
||||
mode |= std::ios_base::in; // we must always read
|
||||
if (create)
|
||||
mode |= std::ios_base::out | std::ios_base::trunc; // make sure the file will be created if needed
|
||||
else
|
||||
mode &= ~std::ios_base::trunc; // make sure the file won't be created
|
||||
|
||||
BYTE* pData = NULL;
|
||||
LONG lDataLen = 0;
|
||||
NSFile::CUtf8Converter::GetUtf8StringFromUnicode(filename.c_str(), (LONG)filename.length(), pData, lDataLen);
|
||||
|
||||
std::fstream* file = new std::fstream( (const char*)pData, std::ios::binary | mode);
|
||||
|
||||
if (NULL != pData)
|
||||
delete [] pData;
|
||||
|
||||
if( !file)
|
||||
return;
|
||||
if (file->fail())
|
||||
{
|
||||
delete file;
|
||||
return;
|
||||
}
|
||||
_file = file;
|
||||
_stream = file;
|
||||
if (!create)
|
||||
load();
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
StorageIOT<_>::StorageIOT( std::iostream* stream )
|
||||
{
|
||||
init();
|
||||
_result = OpenFailed;
|
||||
_stream = stream;
|
||||
load();
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
StorageIOT<_>::~StorageIOT()
|
||||
{
|
||||
flush();
|
||||
close();
|
||||
if (_sbat) delete _sbat;
|
||||
if (_bbat) delete _bbat;
|
||||
delete _dirtree;
|
||||
delete _header;
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
void StorageIOT<_>::init()
|
||||
{
|
||||
_result = NewOLE;
|
||||
_file = NULL;
|
||||
_stream = NULL;
|
||||
|
||||
_header = new Header();
|
||||
_dirtree = new DirTree();
|
||||
_bbat = new AllocTable(1 << _header->b_shift());
|
||||
_sbat = new AllocTable(1 << _header->s_shift());
|
||||
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
bool StorageIOT<_>::load()
|
||||
{
|
||||
if (!_stream) return false;
|
||||
|
||||
// find size of input file
|
||||
_stream->seekg( 0, std::ios::end );
|
||||
_size = _stream->tellg();
|
||||
_stream->seekg( 0 );
|
||||
|
||||
// load header
|
||||
unsigned char buf_header[512];
|
||||
_stream->read( (char*)buf_header, 512 );
|
||||
bool res = _header->load( buf_header, 512 );
|
||||
if (!res)
|
||||
return false;
|
||||
|
||||
// check OLE magic id
|
||||
_result = NotOLE;
|
||||
if (!_header->is_ole())
|
||||
return false;
|
||||
|
||||
// sanity checks
|
||||
_result = BadOLE;
|
||||
if (!_header->valid())
|
||||
return false;
|
||||
|
||||
// important block size
|
||||
_bbat->set_block_size(1 << _header->b_shift());
|
||||
_sbat->set_block_size(1 << _header->s_shift());
|
||||
|
||||
// find blocks allocated to store big bat
|
||||
// the first 109 blocks are in header, the rest in meta bat
|
||||
std::vector<ULONG32> blocks;
|
||||
blocks.resize( _header->num_bat() );
|
||||
for( unsigned i = 0; i < 109; i++ )
|
||||
{
|
||||
if( i >= _header->num_bat() )
|
||||
break;
|
||||
else
|
||||
blocks[i] = _header->bb_blocks()[i];
|
||||
}
|
||||
if( (_header->num_bat() > 109) && (_header->num_mbat() > 0) )
|
||||
{
|
||||
unsigned char* buffer = new unsigned char[ _bbat->block_size() ];
|
||||
if (!buffer)
|
||||
return false;
|
||||
unsigned k = 109;
|
||||
for( unsigned r = 0; r < _header->num_mbat(); r++ )
|
||||
{
|
||||
size_t bytes = loadBigBlock(_header->mbat_start()+r+1, buffer, _bbat->block_size() );
|
||||
if (bytes != _bbat->block_size())
|
||||
break;
|
||||
|
||||
for( unsigned s=0; s < _bbat->block_size(); s+=4 )
|
||||
{
|
||||
if( k >= _header->num_bat() )
|
||||
break;
|
||||
else
|
||||
blocks[k++] = readU32( buffer + s );
|
||||
}
|
||||
}
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
// load big bat
|
||||
std::streamsize buflen = _bbat->block_size()*(std::streamsize)blocks.size();
|
||||
if( buflen > 0 )
|
||||
{
|
||||
unsigned char* buffer = new unsigned char[ buflen ];
|
||||
if (!buffer)
|
||||
return false;
|
||||
loadBigBlocks( blocks, buffer, buflen );
|
||||
bool res = _bbat->load( buffer, buflen );
|
||||
delete[] buffer;
|
||||
if (!res)
|
||||
return false;
|
||||
}
|
||||
|
||||
// load directory tree
|
||||
blocks.clear();
|
||||
if (!_bbat->follow( _header->dirent_start(), blocks ))
|
||||
return false;
|
||||
buflen = _bbat->block_size()*(std::streamsize)blocks.size();
|
||||
unsigned char* buffer = new unsigned char[ buflen ];
|
||||
if (!buffer)
|
||||
return false;
|
||||
loadBigBlocks( blocks, buffer, buflen );
|
||||
if (!_dirtree->load( buffer, buflen ))
|
||||
{
|
||||
delete[] buffer;
|
||||
return false;
|
||||
}
|
||||
unsigned sb_start = readU32( buffer + 0x74 );
|
||||
delete[] buffer;
|
||||
|
||||
_result = OpenSmallFatFailed;
|
||||
// fetch block chain as data for small-files
|
||||
if (!_bbat->follow( sb_start, _sb_blocks ))// small files
|
||||
return false;
|
||||
|
||||
// load small bat
|
||||
blocks.clear();
|
||||
if (!_bbat->follow( _header->sbat_start(), blocks ))
|
||||
return false;
|
||||
buflen = _bbat->block_size()*(std::streamsize)blocks.size();
|
||||
if( buflen > 0 )
|
||||
{
|
||||
buffer = new unsigned char[ buflen ];
|
||||
if (!buffer)
|
||||
return false;
|
||||
loadBigBlocks( blocks, buffer, buflen );
|
||||
bool res = _sbat->load( buffer, buflen );
|
||||
delete[] buffer;
|
||||
if (!res)
|
||||
return false;
|
||||
}
|
||||
|
||||
// for troubleshooting, just enable this block
|
||||
#if 0
|
||||
debug();
|
||||
#endif
|
||||
|
||||
// so far so good
|
||||
_result = Ok;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
bool StorageIOT<_>::create( const char* filename )
|
||||
{
|
||||
// std::cout << "Creating " << filename << std::endl;
|
||||
|
||||
std::fstream* file = new std::fstream(filename, std::ios::out|std::ios::binary);
|
||||
if( !file || file->fail() )
|
||||
{
|
||||
std::cerr << "Can't create " << filename << std::endl;
|
||||
_result = OpenFailed;
|
||||
if (file)
|
||||
delete file;
|
||||
return false;
|
||||
}
|
||||
|
||||
// so far so good
|
||||
_result = Ok;
|
||||
_file = file;
|
||||
_stream = file;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
void StorageIOT<_>::close()
|
||||
{
|
||||
flush();
|
||||
if (_file)
|
||||
{
|
||||
_file->close();
|
||||
delete _file;
|
||||
_file = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
std::streamsize StorageIOT<_>::loadBigBlocks( const std::vector<ULONG32>& blocks, unsigned char* data, std::streamsize maxlen )
|
||||
{
|
||||
// sentinel
|
||||
if( !_stream ) return 0;
|
||||
if( !data ) return 0;
|
||||
if( !_stream->good() ) return 0;
|
||||
if( maxlen == 0 ) return 0;
|
||||
size_t block_num = blocks.size();
|
||||
if( block_num < 1 ) return 0;
|
||||
|
||||
// read block one by one, seems fast enough
|
||||
std::streamsize totalbytes = 0;
|
||||
for( ULONG32 i=0; (i < block_num ) && ( totalbytes < maxlen ); i++ )
|
||||
{
|
||||
ULONG32 block = blocks[i];
|
||||
std::streamsize p = (_bbat->block_size() < (unsigned)(maxlen-totalbytes)) ? _bbat->block_size() : maxlen-totalbytes;
|
||||
std::streamsize bytes = loadBigBlock(block+1, data+totalbytes, p );
|
||||
totalbytes += bytes;
|
||||
}
|
||||
|
||||
return totalbytes;
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
std::streamsize StorageIOT<_>::loadBigBlock( ULONG32 block, unsigned char* data, std::streamsize maxlen )
|
||||
{
|
||||
assert(_stream);
|
||||
assert((unsigned)maxlen <= big_block_size());
|
||||
|
||||
ULONG32 block_pos = block * _bbat->block_size();
|
||||
if (block_pos > _size)
|
||||
return 0;
|
||||
if (block_pos + maxlen > _size)
|
||||
maxlen = _size - block_pos;
|
||||
|
||||
_stream->seekg( block_pos );
|
||||
_stream->read( (char*)data, (std::streamsize)maxlen );
|
||||
|
||||
assert(!_stream->fail());
|
||||
return _stream->gcount();
|
||||
}
|
||||
|
||||
// return number of bytes which has been read
|
||||
template<typename _>
|
||||
std::streamsize StorageIOT<_>::loadSmallBlocks( const std::vector<ULONG32>& blocks, unsigned char* data, std::streamsize maxlen )
|
||||
{
|
||||
// sentinel
|
||||
if( !data ) return 0;
|
||||
if( !_stream || !_stream->good() ) return 0;
|
||||
if( maxlen == 0 ) return 0;
|
||||
size_t block_num = blocks.size();
|
||||
if( block_num < 1 ) return 0;
|
||||
|
||||
// our own local buffer
|
||||
unsigned char* buf = new unsigned char[ _bbat->block_size() ];
|
||||
if (!buf) return 0;
|
||||
|
||||
ULONG32 loaded_bblock = 0;
|
||||
bool bblock_loaded = false;
|
||||
|
||||
// read small block one by one
|
||||
std::streamsize totalbytes = 0;
|
||||
for( ULONG32 i=0; ( i<block_num ) && ( totalbytes<maxlen ); i++ )
|
||||
{
|
||||
// find where the small-block exactly is
|
||||
ULONG32 pos = blocks[i] * _sbat->block_size();
|
||||
ULONG32 bbindex = pos / _bbat->block_size();
|
||||
if( bbindex >= _sb_blocks.size() ) break;
|
||||
|
||||
ULONG32 bblock = _sb_blocks[ bbindex ] + 1;
|
||||
if (bblock != loaded_bblock || !bblock_loaded)
|
||||
{
|
||||
size_t read = loadBigBlock( bblock, buf, _bbat->block_size());
|
||||
if (read != _bbat->block_size())
|
||||
break;
|
||||
bblock_loaded = true;
|
||||
loaded_bblock = bblock;
|
||||
}
|
||||
|
||||
// copy the data
|
||||
ULONG32 offset = pos % _bbat->block_size();
|
||||
std::streamsize p = _sbat->block_size();
|
||||
if (p > maxlen-totalbytes)
|
||||
p = maxlen-totalbytes;
|
||||
if ((unsigned)p > _bbat->block_size()-offset)
|
||||
p = _bbat->block_size()-offset;
|
||||
memcpy( data + totalbytes, buf + offset, p );
|
||||
totalbytes += p;
|
||||
}
|
||||
|
||||
delete[] buf;
|
||||
return totalbytes;
|
||||
}
|
||||
|
||||
// list all files and subdirs in current path
|
||||
template<typename _>
|
||||
void StorageIOT<_>::listDirectory(std::list<std::string>& result) const
|
||||
{
|
||||
std::vector<const DirEntry*> entries;
|
||||
_dirtree->listDirectory(entries);
|
||||
result.resize(entries.size());
|
||||
for( unsigned i = 0; i < entries.size(); i++ )
|
||||
result.push_back( entries[i]->name() );
|
||||
}
|
||||
|
||||
// Write a bigblock
|
||||
template<typename _>
|
||||
std::streamsize StorageIOT<_>::saveBlock(ULONG32 fisical_offset, const unsigned char* data, std::streamsize len)
|
||||
{
|
||||
assert((unsigned)len <= big_block_size());
|
||||
|
||||
_file->seekp(fisical_offset);
|
||||
_file->write((const char*)data, (std::streamsize)len);
|
||||
return len;
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
bool StorageIOT<_>::delete_entry(const std::string& path)
|
||||
{
|
||||
if (!_dirtree || !_dirtree->delete_entry(path))
|
||||
return false;
|
||||
|
||||
m_dtmodified = true;
|
||||
|
||||
// todo: delete blocks
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
bool StorageIOT<_>::flush()
|
||||
{
|
||||
// for troubleshooting, just enable this block
|
||||
#if 0
|
||||
debug();
|
||||
#endif
|
||||
|
||||
if (m_dtmodified && _bbat && _header)
|
||||
{
|
||||
std::vector<ULONG32> blocks;
|
||||
if (!_bbat->follow( _header->dirent_start(), blocks ))
|
||||
return false;
|
||||
size_t bufflen = blocks.size() * _bbat->block_size();
|
||||
unsigned char *buffer = new unsigned char[bufflen];
|
||||
if (!_dirtree->save(buffer, bufflen))
|
||||
return false;
|
||||
for (ULONG32 ndx = 0; ndx < blocks.size(); ++ndx)
|
||||
{
|
||||
ULONG32 fisical_offset = (blocks[ndx] * big_block_size()) + big_block_size();
|
||||
saveBlock(fisical_offset, buffer, big_block_size());
|
||||
buffer += big_block_size();
|
||||
}
|
||||
m_dtmodified = false;
|
||||
}
|
||||
|
||||
return !m_dtmodified;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
template<typename _>
|
||||
void StorageIOT<_>::debug() const
|
||||
{
|
||||
_header->debug();
|
||||
_sbat->debug();
|
||||
_bbat->debug();
|
||||
_dirtree->debug();
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
576
Common/DocxFormat/Source/CompoundDocument/detail/stream.hpp
Normal file
576
Common/DocxFormat/Source/CompoundDocument/detail/stream.hpp
Normal file
@ -0,0 +1,576 @@
|
||||
/* POLE - Portable C++ library to access OLE Storage
|
||||
Copyright (C) 2005-2006 Jorge Lodos Vigil
|
||||
Copyright (C) 2002-2005 Ariya Hidayat <ariya@kde.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of the authors nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
|
||||
*/
|
||||
|
||||
// storage header
|
||||
#pragma once
|
||||
|
||||
#include "storage.hpp"
|
||||
|
||||
namespace POLE
|
||||
{
|
||||
|
||||
template<typename _>
|
||||
class StreamImplT
|
||||
{
|
||||
public:
|
||||
enum {Ok = 0, Eof = 1, Bad = 2, Corrupted = 3};
|
||||
static const std::string null_path;
|
||||
|
||||
// Construction/destruction
|
||||
public:
|
||||
StreamImplT( const StreamImplT<_>& );
|
||||
StreamImplT(StorageIO* io, const DirEntry* e): _entry(e), _io(io) { init(); }
|
||||
StreamImplT(StorageIO* io, const std::string& path): _entry(io->entry(path)), _io(io) { init(); }
|
||||
~StreamImplT() { delete[] _cache_data; }
|
||||
|
||||
// Attributes
|
||||
public:
|
||||
const std::string& path() const { return _entry ? _entry->name() : null_path; }
|
||||
std::streamsize size() const { return (_entry) ? _entry->size() : 0; }
|
||||
std::streampos tellg() const { return _gpos; }
|
||||
std::streampos tellp() const { return _ppos; }
|
||||
bool fail() const { return (_state & Bad) != 0; }
|
||||
bool eof() const { return (_state & Eof) != 0; }
|
||||
|
||||
// Operations
|
||||
public:
|
||||
std::streampos seek(std::streampos pos, std::ios::seekdir origin, std::ios::openmode mode)
|
||||
{
|
||||
if (mode == std::ios::in)
|
||||
{
|
||||
seekg(pos, origin);
|
||||
return tellg();
|
||||
}
|
||||
if (mode == std::ios::out)
|
||||
{
|
||||
seekp(pos, origin);
|
||||
return tellp();
|
||||
}
|
||||
|
||||
// Bad seek
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
void seekg(std::streampos pos, std::ios_base::seekdir origin);
|
||||
void seekp(std::streampos pos, std::ios_base::seekdir origin);
|
||||
|
||||
int getch();
|
||||
std::streamsize read( unsigned char* data, std::streamsize maxlen );
|
||||
std::streamsize write(const unsigned char* data, std::streamsize maxlen);
|
||||
bool reserve(std::streamsize size);
|
||||
bool resize(std::streamsize size, char val);
|
||||
|
||||
// Implementation
|
||||
private:
|
||||
void init();
|
||||
std::streamsize read( std::streampos pos, unsigned char* data, std::streamsize maxlen );
|
||||
void update_cache();
|
||||
|
||||
StorageIO* _io;
|
||||
const DirEntry* _entry;
|
||||
std::vector<ULONG32> _blocks;
|
||||
std::streampos _gpos; // pointer for read
|
||||
std::streampos _ppos; // pointer for write
|
||||
|
||||
// simple cache system to speed-up getch()
|
||||
unsigned char* _cache_data;
|
||||
std::streamsize _cache_size;
|
||||
std::streampos _cache_pos;
|
||||
int _state;
|
||||
|
||||
// no default, copy or assign
|
||||
StreamImplT( );
|
||||
StreamImplT<_>& operator=( const StreamImplT<_>& );
|
||||
};
|
||||
|
||||
typedef StreamImplT<void> StreamImpl;
|
||||
|
||||
// =========== StreamImplT ==========
|
||||
|
||||
template<typename _>
|
||||
const std::string StreamImplT<_>::null_path;
|
||||
|
||||
template<typename _>
|
||||
StreamImplT<_>::StreamImplT( const StreamImplT<_>& stream)
|
||||
{
|
||||
_state = stream._state;
|
||||
_io = stream._io;
|
||||
_entry = stream._entry;
|
||||
_blocks = stream._blocks;
|
||||
_gpos = stream._gpos;
|
||||
_ppos = stream._ppos;
|
||||
|
||||
_cache_size = stream._cache_size;
|
||||
_cache_pos = stream._cache_pos;
|
||||
_cache_data = new unsigned char[4096];
|
||||
for (std::streamsize i = 0; i<_cache_size; i++)
|
||||
_cache_data[i] = stream._cache_data[i];
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
void StreamImplT<_>::init()
|
||||
{
|
||||
_state = StreamImpl::Ok;
|
||||
_gpos = 0;
|
||||
_ppos = 0;
|
||||
// prepare cache
|
||||
_cache_pos = 0;
|
||||
_cache_size = 4096; // optimal ?
|
||||
_cache_data = new unsigned char[_cache_size];
|
||||
|
||||
// sanity check
|
||||
if (!_entry)
|
||||
{
|
||||
_state = StreamImpl::Bad;
|
||||
return;
|
||||
}
|
||||
|
||||
if( _entry->size() >= _io->header()->threshold() )
|
||||
{
|
||||
if (!_io->follow_big_block_table( _entry->start(), _blocks ))
|
||||
_state = StreamImpl::Bad;
|
||||
}
|
||||
else
|
||||
if (!_io->follow_small_block_table( _entry->start(), _blocks ))
|
||||
_state = StreamImpl::Bad;
|
||||
|
||||
//update_cache();
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
void StreamImplT<_>::seekg( std::streampos pos, std::ios_base::seekdir origin)
|
||||
{
|
||||
switch (origin)
|
||||
{
|
||||
case std::ios_base::beg:
|
||||
if ((unsigned)pos > _entry->size())
|
||||
{
|
||||
_state |= StreamImpl::Eof;
|
||||
_gpos = _entry->size();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
_state &= ~StreamImpl::Eof;
|
||||
}
|
||||
_gpos = pos;
|
||||
break;
|
||||
case std::ios_base::cur:
|
||||
if ((unsigned)(_gpos + pos) > _entry->size())
|
||||
{
|
||||
_state |= StreamImpl::Eof;
|
||||
_gpos = _entry->size();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
_state &= ~StreamImpl::Eof;
|
||||
}
|
||||
_gpos += pos;
|
||||
break;
|
||||
case std::ios_base::end:
|
||||
if ((unsigned)pos > _entry->size())
|
||||
{
|
||||
_state |= StreamImpl::Eof;
|
||||
_gpos = 0;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
_state &= ~StreamImpl::Eof;
|
||||
}
|
||||
_gpos = _entry->size() - pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
void StreamImplT<_>::seekp( std::streampos pos, std::ios_base::seekdir origin)
|
||||
{
|
||||
switch (origin)
|
||||
{
|
||||
case std::ios_base::beg:
|
||||
if ((unsigned)pos > _entry->size())
|
||||
{
|
||||
_state |= StreamImpl::Eof;
|
||||
_ppos = _entry->size();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
_state &= ~StreamImpl::Eof;
|
||||
}
|
||||
_ppos = pos;
|
||||
break;
|
||||
case std::ios_base::cur:
|
||||
if ((unsigned)(_ppos + pos) > _entry->size())
|
||||
{
|
||||
_state |= StreamImpl::Eof;
|
||||
_ppos = _entry->size();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
_state &= ~StreamImpl::Eof;
|
||||
}
|
||||
_ppos += pos;
|
||||
break;
|
||||
case std::ios_base::end:
|
||||
if ((unsigned)pos > _entry->size())
|
||||
{
|
||||
_state |= StreamImpl::Eof;
|
||||
_ppos = 0;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
_state &= ~StreamImpl::Eof;
|
||||
}
|
||||
_ppos = _entry->size() - pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
int StreamImplT<_>::getch()
|
||||
{
|
||||
// sanity check
|
||||
if (!_entry)
|
||||
return 0;
|
||||
|
||||
// past end-of-file ?
|
||||
if( _gpos > static_cast<std::streamsize>(_entry->size()) )
|
||||
return -1;
|
||||
|
||||
// need to update cache ?
|
||||
if( !_cache_size || ( _gpos < _cache_pos ) ||
|
||||
( (unsigned)_gpos >= (unsigned)_cache_pos + _cache_size ) )
|
||||
update_cache();
|
||||
|
||||
// something bad if we don't get good cache
|
||||
if( !_cache_size )
|
||||
return -1;
|
||||
|
||||
int data = _cache_data[_gpos - _cache_pos];
|
||||
_gpos += 1;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
std::streamsize StreamImplT<_>::read( std::streampos pos, unsigned char* data, std::streamsize maxlen )
|
||||
{
|
||||
// sanity checks
|
||||
if (!_entry)
|
||||
return 0;
|
||||
if( !data )
|
||||
return 0;
|
||||
if ((maxlen + (unsigned)pos) > _entry->size())
|
||||
{
|
||||
maxlen = _entry->size() - pos;
|
||||
_state |= StreamImpl::Eof;
|
||||
}
|
||||
else
|
||||
{
|
||||
_state &= ~StreamImpl::Eof;
|
||||
}
|
||||
if( maxlen == 0 )
|
||||
return 0;
|
||||
|
||||
std::streamsize totalbytes = 0;
|
||||
std::streamsize max_block_num = (std::streamsize)_blocks.size();
|
||||
|
||||
if ( _entry->size() < _io->header()->threshold() )
|
||||
{
|
||||
// small file
|
||||
std::streamsize index = pos / _io->small_block_size();
|
||||
if( index >= max_block_num )
|
||||
return 0;
|
||||
|
||||
// To read small blocks we have to read at least a big block,
|
||||
// so read as many small blocks as fit in the big block every
|
||||
// time. If we don't do this the same big block may be loaded
|
||||
// several times.
|
||||
|
||||
unsigned char* buf = new unsigned char[ _io->big_block_size() ];
|
||||
if (!buf)
|
||||
return 0;
|
||||
std::streamsize max_blocks_to_read = maxlen / _io->small_block_size();
|
||||
if (maxlen % _io->small_block_size())
|
||||
max_blocks_to_read++;
|
||||
std::streamsize small_blocks_in_big_blocks = _io->big_block_size() / _io->small_block_size();
|
||||
std::vector<ULONG32> blocks;
|
||||
blocks.reserve(small_blocks_in_big_blocks);
|
||||
|
||||
// Read the small blocks that start not at the beginning of the
|
||||
// big block.
|
||||
std::streamsize read_blocks = 0;
|
||||
std::streamsize offset = pos % _io->small_block_size();
|
||||
std::streamsize unaligned_blocks = small_blocks_in_big_blocks - index % small_blocks_in_big_blocks;
|
||||
unaligned_blocks %= small_blocks_in_big_blocks;
|
||||
std::streamsize j = 0;
|
||||
if (unaligned_blocks)
|
||||
{
|
||||
for (; j < unaligned_blocks && j < max_block_num && j < max_blocks_to_read; ++j)
|
||||
if (index+j < max_block_num)
|
||||
blocks.push_back(_blocks[index+j]);
|
||||
else
|
||||
break;
|
||||
index += j;
|
||||
std::streamsize bytes = j * _io->small_block_size();
|
||||
std::streamsize read = _io->loadSmallBlocks( blocks, buf, bytes );
|
||||
if (read != bytes)
|
||||
{
|
||||
memcpy(data, buf + offset, read);
|
||||
delete[] buf;
|
||||
return totalbytes;
|
||||
}
|
||||
read_blocks += j;
|
||||
std::streamsize count = bytes - offset;
|
||||
if(count > maxlen)
|
||||
count = maxlen;
|
||||
memcpy(data, buf + offset, count);
|
||||
totalbytes += count;
|
||||
if (totalbytes == maxlen)
|
||||
{
|
||||
delete[] buf;
|
||||
return totalbytes;
|
||||
}
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
// Read the remaining small blocks. These start at the beginning of a
|
||||
// big block.
|
||||
size_t max_bblocks = max_blocks_to_read / small_blocks_in_big_blocks + 1;
|
||||
for (size_t i = 0; i<max_bblocks && totalbytes < maxlen; ++i)
|
||||
{
|
||||
j = 0;
|
||||
blocks.clear();
|
||||
for (; j < small_blocks_in_big_blocks && j < max_block_num && (j+read_blocks) <= max_blocks_to_read; ++j)
|
||||
if (index+j < max_block_num)
|
||||
blocks.push_back(_blocks[index+j]);
|
||||
else
|
||||
break;
|
||||
index += j;
|
||||
std::streamsize bytes = j * _io->small_block_size();
|
||||
std::streamsize read = _io->loadSmallBlocks( blocks, buf, bytes );
|
||||
read_blocks += j;
|
||||
std::streamsize count = read - offset;
|
||||
if(count > maxlen-totalbytes)
|
||||
count = maxlen-totalbytes;
|
||||
memcpy(data+totalbytes, buf + offset, count);
|
||||
totalbytes += count;
|
||||
offset = 0;
|
||||
if (totalbytes == maxlen)
|
||||
break;
|
||||
}
|
||||
delete[] buf;
|
||||
return totalbytes;
|
||||
}
|
||||
|
||||
// big file
|
||||
std::streamsize index = pos / _io->big_block_size();
|
||||
|
||||
if( index >= max_block_num )
|
||||
return 0;
|
||||
|
||||
unsigned char* buf = new unsigned char[ _io->big_block_size() ];
|
||||
size_t offset = pos % _io->big_block_size();
|
||||
for (; index < max_block_num && totalbytes < maxlen; ++index )
|
||||
{
|
||||
ULONG32 block = _blocks[index];
|
||||
size_t read = _io->loadBigBlock(block+1, buf, _io->big_block_size());
|
||||
if (read != _io->big_block_size())
|
||||
break;
|
||||
std::streamsize count = _io->big_block_size() - offset;
|
||||
if( count > maxlen-totalbytes ) count = maxlen-totalbytes;
|
||||
memcpy( data+totalbytes, buf + offset, count );
|
||||
totalbytes += count;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
delete [] buf;
|
||||
return totalbytes;
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
std::streamsize StreamImplT<_>::read( unsigned char* data, std::streamsize maxlen )
|
||||
{
|
||||
std::streamsize bytes = read( tellg(), data, maxlen );
|
||||
_gpos += bytes;
|
||||
|
||||
if ((unsigned)_gpos == _entry->size())
|
||||
_state |= StreamImpl::Eof;
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
void StreamImplT<_>::update_cache()
|
||||
{
|
||||
// sanity checks
|
||||
if (!_entry)
|
||||
return;
|
||||
if( !_cache_data )
|
||||
return;
|
||||
|
||||
_cache_pos = _gpos - ( _gpos % _cache_size );
|
||||
std::streamsize bytes = _cache_size;
|
||||
if( (unsigned)_cache_pos + bytes > _entry->size() )
|
||||
bytes = _entry->size() - _cache_pos;
|
||||
_cache_size = read( _cache_pos, _cache_data, bytes );
|
||||
}
|
||||
|
||||
/*
|
||||
para escribir:
|
||||
1. El entry de cada stream contiene el bloque en que comienza, hay que cargarlos todos en un vector utilizando el follow de la clase AllocTable.
|
||||
2. Para conocer en que bloque del stream se debe comenzar a escribir, esto se hace dividiendo el offset con respecto al inicio del stream entre el tamaño de cada bloque.
|
||||
3. Para calcular el offset dentro de ese bloque se toma el resto de la division anterior.
|
||||
4. Para conocer el desplazamiento fisico donde hay que escribir en el fichero se suma el offset dentro del bloque y se suma con el offset del bloque en el que se va a escribir, este ltimo se calcula como el (bloque*512)+512.
|
||||
5. Para saber la cantidad de bytes afectados en un bloque dado se resta el tamaño del bloque entre el offset dentro del bloque. Si es menos, entonces todo pertenece a ese bloque, si es mayor, entonces se escriben los bytes desde el desplazamiento inicial hasta el final del bloque y el resto pertenece al bloque adyacente.
|
||||
6. Es necesario incrementar el buffer de datos en la cantidad de bytes copiados y restar de la cantidad total de bytes lo que se copio
|
||||
7. Repetir la operacion con otro bloque si es necesario.
|
||||
*/
|
||||
template<typename _>
|
||||
std::streamsize StreamImplT<_>::write(const unsigned char* data, std::streamsize maxlen)
|
||||
{
|
||||
// Sanity checks
|
||||
if(! _entry)
|
||||
return 0;
|
||||
if(!data)
|
||||
return 0;
|
||||
if((maxlen + (unsigned)_ppos) > _entry->size())
|
||||
{
|
||||
maxlen = _entry->size() - _ppos;
|
||||
_state |= StreamImpl::Eof;
|
||||
}
|
||||
else
|
||||
{
|
||||
_state &= ~StreamImpl::Eof;
|
||||
}
|
||||
if(maxlen == 0)
|
||||
return 0;
|
||||
|
||||
size_t max_block_num = _blocks.size();
|
||||
|
||||
// Amount of written byes
|
||||
std::streamsize written = 0;
|
||||
std::streamsize count = 0;
|
||||
std::streamsize data_len = maxlen;
|
||||
|
||||
if (_entry->size() < _io->header()->threshold())
|
||||
{
|
||||
// small file
|
||||
size_t index = _ppos / _io->small_block_size();
|
||||
if( index >= max_block_num )
|
||||
return 0;
|
||||
|
||||
size_t offset = _ppos % _io->small_block_size();
|
||||
std::vector<ULONG32> _sbroot_entry = _io->sb_blocks();
|
||||
for (; index < max_block_num && count < maxlen; ++index)
|
||||
{
|
||||
// Take the minifat sector index
|
||||
ULONG32 minifat_index = _blocks[index];
|
||||
ULONG32 sbindex_offset = minifat_index % 8;
|
||||
// Calculate the the root entry's big block index
|
||||
ULONG32 position = minifat_index * _io->small_block_size();
|
||||
ULONG32 bbindex = position / _io->big_block_size();
|
||||
// Fisical offset inside the file
|
||||
ULONG32 bbindice = _sbroot_entry[bbindex];
|
||||
ULONG32 fisical_offset = (((bbindice * _io->big_block_size()) + _io->big_block_size()) +
|
||||
(sbindex_offset * _io->small_block_size())) + offset;
|
||||
|
||||
// Amount of bytes that can actually be written
|
||||
std::streamsize canwrite = _io->small_block_size() - offset;
|
||||
if (canwrite > data_len )
|
||||
canwrite = data_len;
|
||||
|
||||
written = _io->saveBlock(fisical_offset, data, canwrite);
|
||||
count += written;
|
||||
if (written < canwrite)
|
||||
{
|
||||
_state |= StreamImpl::Bad;
|
||||
return count;
|
||||
}
|
||||
data += written;
|
||||
data_len -= written;
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// big file
|
||||
// Ordinal of the first block for writing
|
||||
size_t index = _ppos / _io->big_block_size();
|
||||
if(index >= max_block_num)
|
||||
return 0;
|
||||
|
||||
// Offset inside this block
|
||||
size_t offset = _ppos % _io->big_block_size();
|
||||
|
||||
for (; index < max_block_num && count < maxlen; ++index)
|
||||
{
|
||||
// Fisical offset inside the file
|
||||
ULONG32 fisical_offset = ((_blocks[index] * _io->big_block_size()) + _io->big_block_size() + offset);
|
||||
|
||||
// Amount of bytes that can actually be written
|
||||
std::streamsize canwrite = _io->big_block_size() - offset;
|
||||
if (canwrite > data_len )
|
||||
canwrite = data_len;
|
||||
|
||||
written = _io->saveBlock(fisical_offset, data, canwrite);
|
||||
count += written;
|
||||
if (written < canwrite)
|
||||
{
|
||||
_state |= StreamImpl::Bad;
|
||||
return count;
|
||||
}
|
||||
data += written;
|
||||
data_len -= written;
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
bool StreamImplT<_>::reserve(std::streamsize size)
|
||||
{
|
||||
// todo: implement
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename _>
|
||||
bool StreamImplT<_>::resize(std::streamsize size, char val)
|
||||
{
|
||||
// todo: implement
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
64
Common/DocxFormat/Source/CompoundDocument/detail/util.hpp
Normal file
64
Common/DocxFormat/Source/CompoundDocument/detail/util.hpp
Normal file
@ -0,0 +1,64 @@
|
||||
/* POLE - Portable C++ library to access OLE Storage
|
||||
Copyright (C) 2005-2006 Jorge Lodos Vigil
|
||||
Copyright (C) 2002-2005 Ariya Hidayat <ariya@kde.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of the authors nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
|
||||
*/
|
||||
|
||||
// util header
|
||||
#pragma once
|
||||
|
||||
namespace POLE
|
||||
{
|
||||
|
||||
typedef unsigned char ULONG8;
|
||||
typedef unsigned short ULONG16;
|
||||
typedef unsigned long ULONG32;
|
||||
|
||||
inline ULONG32 readU32( const unsigned char* ptr )
|
||||
{
|
||||
return ptr[0]+(ptr[1]<<8)+(ptr[2]<<16)+(ptr[3]<<24);
|
||||
}
|
||||
|
||||
inline void writeU32( unsigned char* ptr, ULONG32 data )
|
||||
{
|
||||
ptr[0] = (unsigned char)(data & 0xff);
|
||||
ptr[1] = (unsigned char)((data >> 8) & 0xff);
|
||||
ptr[2] = (unsigned char)((data >> 16) & 0xff);
|
||||
ptr[3] = (unsigned char)((data >> 24) & 0xff);
|
||||
}
|
||||
|
||||
inline ULONG16 readU16( const unsigned char* ptr )
|
||||
{
|
||||
return ptr[0]+(ptr[1]<<8);
|
||||
}
|
||||
|
||||
inline void writeU16( unsigned char* ptr, ULONG16 data )
|
||||
{
|
||||
ptr[0] = (unsigned char)(data & 0xff);
|
||||
ptr[1] = (unsigned char)((data >> 8) & 0xff);
|
||||
}
|
||||
|
||||
}
|
||||
314
Common/DocxFormat/Source/CompoundDocument/pole.h
Normal file
314
Common/DocxFormat/Source/CompoundDocument/pole.h
Normal file
@ -0,0 +1,314 @@
|
||||
/* POLE - Portable C++ library to access OLE Storage
|
||||
Copyright (C) 2005-2006 Jorge Lodos Vigil
|
||||
Copyright (C) 2002-2005 Ariya Hidayat <ariya@kde.org>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of the authors nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
|
||||
*/
|
||||
|
||||
#ifndef POLE_H
|
||||
#define POLE_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "./detail/stream.hpp"
|
||||
|
||||
namespace POLE
|
||||
{
|
||||
|
||||
class Stream;
|
||||
|
||||
template<typename _>
|
||||
class StorageT
|
||||
{
|
||||
public:
|
||||
enum { Ok, OpenFailed, OpenSmallFatFailed, NotOLE, BadOLE, UnknownError, StupidWorkaroundForBrokenCompiler=255 };
|
||||
|
||||
// Constructs a storage with name filename.
|
||||
StorageT( const char* filename, std::ios_base::openmode mode = std::ios_base::in, bool create = false )
|
||||
{
|
||||
io = new StorageIO( filename, mode, create );
|
||||
}
|
||||
StorageT( const std::wstring& filename, std::ios_base::openmode mode = std::ios_base::in, bool create = false )
|
||||
{
|
||||
io = new StorageIO( filename, mode, create );
|
||||
}
|
||||
|
||||
// Constructs a storage from a stream.
|
||||
StorageT( std::iostream& stream )
|
||||
{
|
||||
io = new StorageIO( &stream );
|
||||
}
|
||||
|
||||
// Destroys the storage.
|
||||
~StorageT()
|
||||
{
|
||||
delete io;
|
||||
std::list<Stream*>::iterator it;
|
||||
for( it = streams.begin(); it != streams.end(); ++it )
|
||||
delete *it;
|
||||
}
|
||||
|
||||
// Attributes
|
||||
public:
|
||||
|
||||
// Returns the error code of last operation.
|
||||
int result() const
|
||||
{
|
||||
return io->result();
|
||||
}
|
||||
|
||||
void fullName( const DirEntry* entry, std::string& name) const
|
||||
{
|
||||
io->fullName( entry, name);
|
||||
}
|
||||
|
||||
// Returns the current path.
|
||||
void current_path( std::string& result) const
|
||||
{
|
||||
io->current_path(result);
|
||||
}
|
||||
|
||||
// Returns the root entry.
|
||||
const DirEntry* root_entry() const
|
||||
{
|
||||
return io->root_entry();
|
||||
}
|
||||
|
||||
// Returns the current entry.
|
||||
const DirEntry* current_entry() const
|
||||
{
|
||||
return io->current_entry();
|
||||
}
|
||||
|
||||
const DirEntry* getEntry(const std::string& name) const
|
||||
{
|
||||
return io->entry( name );
|
||||
}
|
||||
|
||||
void listEntries(std::vector<const DirEntry*>& result) const
|
||||
{
|
||||
io->listEntries(result);
|
||||
}
|
||||
|
||||
void listAll(std::vector<const DirEntry*>& result) const
|
||||
{
|
||||
io->listAll(result);
|
||||
}
|
||||
|
||||
// Operations
|
||||
public:
|
||||
// Changes path to directory. Returns true if no error occurs.
|
||||
bool enterDirectory( const std::string& directory )
|
||||
{
|
||||
return io->enterDirectory( directory );
|
||||
}
|
||||
|
||||
// Goes to one directory up.
|
||||
void leaveDirectory()
|
||||
{
|
||||
io->leaveDirectory();
|
||||
}
|
||||
|
||||
// Finds and returns a stream with the specified name.
|
||||
Stream* stream( const std::string& name, bool reuse = false );
|
||||
|
||||
// If there is a stream using this entry it will be corrupted.
|
||||
// Any existent entry list is not valid anymore
|
||||
bool delete_entry(const std::string& path)
|
||||
{
|
||||
return io->delete_entry(path);
|
||||
}
|
||||
|
||||
bool flush()
|
||||
{
|
||||
return io->flush();
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
void debug() const
|
||||
{
|
||||
io->debug();
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
StorageIO* io;
|
||||
std::list<Stream*> streams;
|
||||
|
||||
// no copy or assign
|
||||
StorageT( const StorageT<_>& );
|
||||
StorageT<_>& operator=( const StorageT<_>& );
|
||||
};
|
||||
|
||||
typedef StorageT<void> Storage;
|
||||
|
||||
class Stream
|
||||
{
|
||||
friend class StorageT<void>;
|
||||
|
||||
public: // Attributes
|
||||
|
||||
// Returns the path for this stream.
|
||||
const std::string& path() const
|
||||
{
|
||||
return impl ? impl->path() : StreamImpl::null_path;
|
||||
}
|
||||
|
||||
// Returns the stream size.
|
||||
std::streamsize size() const
|
||||
{
|
||||
return impl ? impl->size() : 0;
|
||||
}
|
||||
|
||||
// Returns the read pointer.
|
||||
std::streampos tellg() const
|
||||
{
|
||||
return impl ? impl->tellg() : 0;
|
||||
}
|
||||
|
||||
// Returns the write pointer.
|
||||
std::streampos tellp() const
|
||||
{
|
||||
return impl ? impl->tellp() : 0;
|
||||
}
|
||||
|
||||
// Return the Eof state of the stream
|
||||
bool eof() const
|
||||
{
|
||||
return impl ? impl->eof() : true;
|
||||
}
|
||||
|
||||
// Return the fail state of the Stream
|
||||
bool fail() const
|
||||
{
|
||||
return impl ? impl->fail() : true;
|
||||
}
|
||||
|
||||
public: // Operations
|
||||
|
||||
// Sets the read position.
|
||||
std::streampos seek( std::streampos pos, std::ios_base::seekdir origin, std::ios_base::openmode mode )
|
||||
{
|
||||
if( impl ) return impl->seek( pos, origin, mode );
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Sets the read position.
|
||||
void seekg( std::streampos pos, std::ios_base::seekdir origin = std::ios_base::beg )
|
||||
{
|
||||
if( impl ) impl->seekg( pos, origin );
|
||||
}
|
||||
|
||||
// Sets the write position.
|
||||
void seekp( std::streampos pos, std::ios_base::seekdir origin = std::ios_base::beg )
|
||||
{
|
||||
if( impl ) impl->seekp( pos, origin );
|
||||
}
|
||||
|
||||
// Reads a byte.
|
||||
int getch()
|
||||
{
|
||||
return impl ? impl->getch() : 0;
|
||||
}
|
||||
|
||||
// Reads a block of data.
|
||||
std::streamsize read( unsigned char* data, std::streamsize maxlen )
|
||||
{
|
||||
return impl ? impl->read( data, maxlen ) : 0;
|
||||
}
|
||||
|
||||
// Write a block of data
|
||||
std::streamsize write(const unsigned char* data, std::streamsize len)
|
||||
{
|
||||
return impl ? impl->write( data, len ) : 0;
|
||||
}
|
||||
|
||||
// Make the size grow to size. If size is less than current size no
|
||||
// action will be taken.
|
||||
bool reserve(std::streamsize size)
|
||||
{
|
||||
return impl ? impl->reserve( size ) : false;
|
||||
}
|
||||
|
||||
// Make the size exactly size. If size is less than current size the
|
||||
// extra bytes will be truncated. If it is greater the new data will
|
||||
// be filled with val.
|
||||
bool resize(std::streamsize size, char val = 0)
|
||||
{
|
||||
return impl ? impl->resize( size, val ) : false;
|
||||
}
|
||||
|
||||
private:
|
||||
Stream(StreamImpl* i) { impl = i; }
|
||||
~Stream() { delete impl; }
|
||||
|
||||
// no default, copy or assign
|
||||
Stream();
|
||||
Stream( const Stream& );
|
||||
Stream& operator=( const Stream& );
|
||||
|
||||
StreamImpl* impl;
|
||||
};
|
||||
|
||||
// =========== StorageT ==========
|
||||
|
||||
template<typename _>
|
||||
Stream* StorageT<_>::stream( const std::string& name, bool reuse )
|
||||
{
|
||||
// sanity check
|
||||
if( !name.length() ) return (Stream*)0;
|
||||
if( !io ) return (Stream*)0;
|
||||
|
||||
// make absolute if necesary
|
||||
std::string fullName = name;
|
||||
std::string path_;
|
||||
current_path(path_);
|
||||
if( name[0] != '/' ) fullName.insert( 0, path_ + "/" );
|
||||
|
||||
// If a stream for this path already exists return it
|
||||
if (reuse)
|
||||
{
|
||||
std::list<Stream*>::iterator it;
|
||||
for( it = streams.begin(); it != streams.end(); ++it )
|
||||
if ((*it)->path() == name)
|
||||
return *it;
|
||||
}
|
||||
|
||||
const DirEntry* entry = io->entry( name );
|
||||
if( !entry ) return (Stream*)0;
|
||||
|
||||
// We create the StreamImpl here instead of in the constructor to avoid
|
||||
// passing implementation parameters in the constructor.
|
||||
// The created StreamImpl will be deleted in the Stream destructor.
|
||||
StreamImpl* i = new StreamImpl( io, entry );
|
||||
Stream* s = new Stream(i);
|
||||
streams.push_back( s );
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // POLE_H
|
||||
Reference in New Issue
Block a user