Commit d6dc3779 authored by Sergey.Konovalov's avatar Sergey.Konovalov Committed by Alexander Trofimov

MathEquation переведен на одинаковое с doc,ppt,xls файлыми POLE. некоторые файлы сделаны utf8.

git-svn-id: svn://fileserver/activex/AVS/Sources/TeamlabOffice/trunk/ServerComponents@64422 954022d7-b5bf-4e40-9824-e11837661b57
parent 271372e5
...@@ -481,8 +481,6 @@ Common/DocxFormat/Mac/DocxFormatLib.xcodeproj/project.xcworkspace/xcuserdata/ale ...@@ -481,8 +481,6 @@ Common/DocxFormat/Mac/DocxFormatLib.xcodeproj/project.xcworkspace/xcuserdata/ale
Common/DocxFormat/Mac/DocxFormatLib.xcodeproj/xcuserdata svnc_tsvn_003alogminsize=5 Common/DocxFormat/Mac/DocxFormatLib.xcodeproj/xcuserdata svnc_tsvn_003alogminsize=5
Common/DocxFormat/Mac/DocxFormatLib.xcodeproj/xcuserdata/alexey.musinov.xcuserdatad svnc_tsvn_003alogminsize=5 Common/DocxFormat/Mac/DocxFormatLib.xcodeproj/xcuserdata/alexey.musinov.xcuserdatad svnc_tsvn_003alogminsize=5
Common/DocxFormat/Mac/DocxFormatLib.xcodeproj/xcuserdata/alexey.musinov.xcuserdatad/xcschemes svnc_tsvn_003alogminsize=5 Common/DocxFormat/Mac/DocxFormatLib.xcodeproj/xcuserdata/alexey.musinov.xcuserdatad/xcschemes svnc_tsvn_003alogminsize=5
Common/DocxFormat/Source/CompoundDocument svnc_tsvn_003alogminsize=5
Common/DocxFormat/Source/CompoundDocument/detail svnc_tsvn_003alogminsize=5
Common/DocxFormat/Source/DocxFormat/Diagram svnc_tsvn_003alogminsize=5 Common/DocxFormat/Source/DocxFormat/Diagram svnc_tsvn_003alogminsize=5
Common/DocxFormat/Source/MathEquation svnc_tsvn_003alogminsize=5 Common/DocxFormat/Source/MathEquation svnc_tsvn_003alogminsize=5
Common/DocxFormat/Source/MathEquation/Examples svnc_tsvn_003alogminsize=5 Common/DocxFormat/Source/MathEquation/Examples svnc_tsvn_003alogminsize=5
...@@ -304,13 +304,6 @@ HEADERS += docxformatlib.h \ ...@@ -304,13 +304,6 @@ HEADERS += docxformatlib.h \
../Source/XML/XmlSimple.h \ ../Source/XML/XmlSimple.h \
../Source/XML/xmlutils.h \ ../Source/XML/xmlutils.h \
../Source/Base/ASCString.h \ ../Source/Base/ASCString.h \
../Source/CompoundDocument/detail/alloctable.hpp \
../Source/CompoundDocument/detail/dirtree.hpp \
../Source/CompoundDocument/detail/header.hpp \
../Source/CompoundDocument/detail/storage.hpp \
../Source/CompoundDocument/detail/stream.hpp \
../Source/CompoundDocument/detail/util.hpp \
../Source/CompoundDocument/pole.h \
../Source/DocxFormat/Drawing/DrawingShapeElements.h \ ../Source/DocxFormat/Drawing/DrawingShapeElements.h \
../Source/DocxFormat/Drawing/DrawingText.h \ ../Source/DocxFormat/Drawing/DrawingText.h \
../Source/DocxFormat/Drawing/DrawingTextProperties.h \ ../Source/DocxFormat/Drawing/DrawingTextProperties.h \
......
/* 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 POLE2
{
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
/* 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"
#include <cstring>
namespace POLE2
{
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);
}
}
}
/* 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"
#include <cstring>
namespace POLE2
{
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
}
/* 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 <cstring>
#include "../../../../../DesktopEditor/common/File.h"
namespace POLE2
{
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
{
std::vector<ULONG32> result_ulong;
result_ulong.assign (result.begin(), result.end());
_dirtree->children(index, result_ulong);
}
void children( size_t index, std::vector<size_t>& result ) const
{
if (_dirtree)
{
std::vector<ULONG32> result_ulong;
result_ulong.assign (result.begin(), result.end());
_dirtree->children(index, result_ulong);
}
}
// 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)
{
#if defined(_WIN32) || defined (_WIN64)
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
}
/* 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 POLE2
{
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;
}
}
/* 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 POLE2
{
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);
}
}
/* 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 POLE2_H
#define POLE2_H
#pragma once
#include "./detail/stream.hpp"
namespace POLE2
{
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() : std::streampos();
}
// Returns the write pointer.
std::streampos tellp() const
{
return impl ? impl->tellp() : std::streampos();
}
// 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::seekdir origin = std::ios_base::beg, std::ios::openmode mode = std::ios::in)
{
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
#ifndef _MATHEQUATION_LESTREAM #ifndef _MATHEQUATION_LESTREAM
#define _MATHEQUATION_LESTREAM #define _MATHEQUATION_LESTREAM
#include "../CompoundDocument/pole.h" #include "../Base/Base.h"
#include "Types.h" #include "Types.h"
namespace MathEquation namespace MathEquation
...@@ -16,9 +16,7 @@ public : ...@@ -16,9 +16,7 @@ public :
if (NULL == pStream) if (NULL == pStream)
return; return;
pStream->seek(0, std::ios_base::end); unsigned int unFileSize = pStream->size();
unsigned int unFileSize = (unsigned int)pStream->tellg();
pStream->seek(0);
pBuffer = new BYTE[unFileSize]; pBuffer = new BYTE[unFileSize];
if (!pBuffer) if (!pBuffer)
......
#include "MathEquation.h" #include "MathEquation.h"
#include "OutputDev.h" #include "OutputDev.h"
using namespace MathEquation; using namespace MathEquation;
...@@ -12,18 +12,24 @@ using namespace MathEquation; ...@@ -12,18 +12,24 @@ using namespace MathEquation;
void CEquationReader::InitSizes() void CEquationReader::InitSizes()
{ {
// ( , , .. ) //todo обработать open(true/false)
m_oStorage.open(false, false);
// Выставляем размеры текста по умолчанию (если они изменены, тогда ничего не поделаешь, т.к. это не сохраняется в самом файле)
aSizeTable[0] = 12; aSizeTable[0] = 12;
aSizeTable[1] = 7; aSizeTable[1] = 7;
aSizeTable[2] = 5; aSizeTable[2] = 5;
aSizeTable[3] = 18; aSizeTable[3] = 18;
aSizeTable[4] = 12; aSizeTable[4] = 12;
} }
void CEquationReader::SetOutputDev(IOutputDev *pOutput)
{
pOutputDev = pOutput;
InitFonts();
}
void CEquationReader::InitFonts() void CEquationReader::InitFonts()
{ {
// MathEquation . // Стандартные шрифты для MathEquation со стандартными настройками стилей.
// ( , , .. ) // (если они изменены, тогда ничего не поделаешь, т.к. это не сохраняется в самом файле)
if (pOutputDev) if (pOutputDev)
{ {
...@@ -31,14 +37,14 @@ void CEquationReader::InitFonts() ...@@ -31,14 +37,14 @@ void CEquationReader::InitFonts()
{ {
switch(i) switch(i)
{ {
case 1: pOutputDev->AddFont(i + 128, "Times New Roman", false, false); break; // case 1: pOutputDev->AddFont(i + 128, "Times New Roman", false, false); break; // текст
case 2: pOutputDev->AddFont(i + 128, "Times New Roman", false, false); break; // case 2: pOutputDev->AddFont(i + 128, "Times New Roman", false, false); break; // функция
case 3: pOutputDev->AddFont(i + 128, "Times New Roman", false, true); break; // case 3: pOutputDev->AddFont(i + 128, "Times New Roman", false, true); break; // переменная
case 4: pOutputDev->AddFont(i + 128, "Symbol", false, true); break; // . case 4: pOutputDev->AddFont(i + 128, "Symbol", false, true); break; // ст. греческие
case 5: pOutputDev->AddFont(i + 128, "Symbol", false, false); break; // . case 5: pOutputDev->AddFont(i + 128, "Symbol", false, false); break; // пр. греческие
case 6: pOutputDev->AddFont(i + 128, "Symbol", false, false); break; // case 6: pOutputDev->AddFont(i + 128, "Symbol", false, false); break; // символ
case 7: pOutputDev->AddFont(i + 128, "Times New Roman", true, false); break; // - case 7: pOutputDev->AddFont(i + 128, "Times New Roman", true, false); break; // матрица-вектор
case 8: pOutputDev->AddFont(i + 128, "Times New Roman", false, false); break; // case 8: pOutputDev->AddFont(i + 128, "Times New Roman", false, false); break; // числа
} }
} }
} }
...@@ -46,7 +52,10 @@ void CEquationReader::InitFonts() ...@@ -46,7 +52,10 @@ void CEquationReader::InitFonts()
int CEquationReader::Parse() int CEquationReader::Parse()
{ {
pS = new CLEStream<Stream>(m_oStorage.stream("Equation Native")); //если смотреть реализацию, то pStm можно удалить после конструтора CLEStream,
//но если не смотреть реализацию,то правильно удалить pStm после pS
pStm = new POLE::Stream( &m_oStorage, "Equation Native");
pS = new CLEStream<Stream>(pStm);
if (!pS->IsValid()) if (!pS->IsValid())
return 0; return 0;
...@@ -210,12 +219,12 @@ int CEquationReader::HandleChar(uint8_t nTag) ...@@ -210,12 +219,12 @@ int CEquationReader::HandleChar(uint8_t nTag)
if (nChar < 0x20) if (nChar < 0x20)
return nRet; return nRet;
pOutputDev->BeginChar(nChar, nTypeFace, IsSpecialChar(nChar)); pOutputDev->BeginChar(nChar, nTypeFace, IsSpecialChar(nChar));
if (xfEMBELL(nTag)) if (xfEMBELL(nTag))
{ {
nRet = HandleRecords(); nRet = HandleRecords();
} }
pOutputDev->EndChar(); pOutputDev->EndChar();
return nRet; return nRet;
...@@ -662,7 +671,7 @@ void CEquationReader::HandleSetSize(MTOKENS eType) ...@@ -662,7 +671,7 @@ void CEquationReader::HandleSetSize(MTOKENS eType)
} }
case 100: case 100:
{ {
// TODO: // TODO: Проверить эту ветку
*pS >> nTemp; *pS >> nTemp;
nSize = nTemp; nSize = nTemp;
...@@ -672,7 +681,7 @@ void CEquationReader::HandleSetSize(MTOKENS eType) ...@@ -672,7 +681,7 @@ void CEquationReader::HandleSetSize(MTOKENS eType)
} }
default: default:
{ {
// TODO: // TODO: Проверить эту ветку
nSize = nTemp; nSize = nTemp;
*pS >> nTemp; *pS >> nTemp;
uint16_t nTempSize = nTemp - 128; uint16_t nTempSize = nTemp - 128;
...@@ -734,4 +743,4 @@ bool CEquationReader::IsSpecialChar(Unicode_t nChar) ...@@ -734,4 +743,4 @@ bool CEquationReader::IsSpecialChar(Unicode_t nChar)
} }
return false; return false;
} }
\ No newline at end of file
#ifndef _MATH_EQUATION_READER_H #ifndef _MATH_EQUATION_READER_H
#define _MATH_EQUATION_READER_H #define _MATH_EQUATION_READER_H
#include "../CompoundDocument/pole.h" #include "../../../3dParty/pole/pole.h"
#include "Types.h" #include "Types.h"
#include "LEStream.h" #include "LEStream.h"
#include "String.h" #include "String.h"
#include "OutputDev.h" #include "OutputDev.h"
using namespace POLE2; using namespace POLE;
namespace MathEquation namespace MathEquation
...@@ -16,7 +16,7 @@ namespace MathEquation ...@@ -16,7 +16,7 @@ namespace MathEquation
{ {
public: public:
CEquationReader(const wchar_t* wsFilePath) : m_oStorage(wsFilePath), pS(NULL), nHAlign(0), nVAlign(0) CEquationReader(const wchar_t* wsFilePath) : m_oStorage(wsFilePath), pStm(NULL), pS(NULL), nHAlign(0), nVAlign(0)
{ {
InitSizes(); InitSizes();
} }
...@@ -25,13 +25,11 @@ namespace MathEquation ...@@ -25,13 +25,11 @@ namespace MathEquation
{ {
if (NULL != pS) if (NULL != pS)
delete pS; delete pS;
if (NULL != pStm)
delete pStm;
} }
void SetOutputDev(IOutputDev *pOutput) void SetOutputDev(IOutputDev *pOutput);
{
pOutputDev = pOutput;
InitFonts();
}
int Parse(); int Parse();
...@@ -49,11 +47,11 @@ namespace MathEquation ...@@ -49,11 +47,11 @@ namespace MathEquation
RULER = 0x07, RULER = 0x07,
FONT = 0x08, FONT = 0x08,
SIZE_CUSTOM = 0x09, SIZE_CUSTOM = 0x09,
SIZE_REGULAR = 0x0a, // SIZE_REGULAR = 0x0a, // обычный
SIZE_BIGSCRIPT = 0x0b, // SIZE_BIGSCRIPT = 0x0b, // крунпый индекс
SIZE_SMALLSCRIT = 0x0c, // SIZE_SMALLSCRIT = 0x0c, // мелкий индекс
SIZE_BIGSYMBOL = 0x0d, // SIZE_BIGSYMBOL = 0x0d, // большой символ
SIZE_SMALLSYMBOL = 0x0e // SIZE_SMALLSYMBOL = 0x0e // мелкий символ
}; };
private: private:
...@@ -107,6 +105,7 @@ namespace MathEquation ...@@ -107,6 +105,7 @@ namespace MathEquation
Storage m_oStorage; Storage m_oStorage;
Stream *pStm;
CLEStream<Stream> *pS; CLEStream<Stream> *pS;
IOutputDev* pOutputDev; IOutputDev* pOutputDev;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment