diff --git a/ASCOfficeXlsFile2/source/XlsFormat/Binary/CFRecord.cpp b/ASCOfficeXlsFile2/source/XlsFormat/Binary/CFRecord.cpp index 6721b96518..e4ad55a121 100644 --- a/ASCOfficeXlsFile2/source/XlsFormat/Binary/CFRecord.cpp +++ b/ASCOfficeXlsFile2/source/XlsFormat/Binary/CFRecord.cpp @@ -82,7 +82,30 @@ CFRecord::CFRecord(CFStreamPtr stream, GlobalWorkbookInfoPtr global_info) } } } - +// Create a record and read its data from the data stream +CFRecord::CFRecord(NSFile::CFileBinary &file, GlobalWorkbookInfoPtr global_info) +: rdPtr(0), // seek to the start + global_info_(global_info) +{ + if (file.GetFilePosition() + 4 < file.GetFileSize()) + { + unsigned short size_short; + DWORD size_read = 0; + + file.ReadFile((BYTE*)&type_id_, 2, size_read); + file.ReadFile((BYTE*)&size_short, 2, size_read); + + file_ptr += 4; + + if (file.GetFilePosition() + size_short < file.GetFileSize()) + { + size_ = size_short; + data_ = new char[size_]; + + file.ReadFile((BYTE*)data_, size_, size_read); + } + } +} // Create an empty record CFRecord::CFRecord(CFRecordType::TypeId type_id, GlobalWorkbookInfoPtr global_info) @@ -95,53 +118,25 @@ CFRecord::CFRecord(CFRecordType::TypeId type_id, GlobalWorkbookInfoPtr global_in { } - -void CFRecord::save(CFStreamPtr stream) -{ - file_ptr = static_cast(stream->getStreamPointer()); // Assume that files have size < 4Gb - *stream << type_id_; - unsigned short size_short = static_cast(size_); - *stream << size_short; - if(data_) - { - stream->writeAndApplyDelayedItems(data_, size_, receiver_items, source_items); - } - rdPtr = 0; // seek to the start -} - - -void CFRecord::commitData() -{ - if(!data_) - { - if(size_ > MAX_RECORD_SIZE) - { - throw;// EXCEPT::RT::WrongBiffRecord("Too much data written to CFRecord.", getTypeString()); - } - data_ = new char[size_]; - memcpy(data_, intData, size_); - } -} - - CFRecord::~CFRecord() { - delete[] data_; + if (data_) + { + delete[] data_; + } + data_ = NULL; } - const CFRecordType::TypeId CFRecord::getTypeId() const { return type_id_; } - const CFRecordType::TypeString& CFRecord::getTypeString() const { return CFRecordType::getStringById(type_id_); } - // File Pointer to the start of the record in file const unsigned int CFRecord::getStreamPointer() const { @@ -274,22 +269,6 @@ bool CFRecord::checkFitRead(const size_t size) const return true; } - -const bool CFRecord::checkFitWriteSafe(const size_t size) const -{ - return (size_ + size <= MAX_RECORD_SIZE); -} - - -void CFRecord::checkFitWrite(const size_t size) const -{ - if(!checkFitWriteSafe(size)) - { - throw;// EXCEPT::RT::WrongBiffRecord("Some of the stored data doesn't fit the intermediate buffer.", getTypeString()); - } -} - - void CFRecord::skipNunBytes(const size_t n) { //ASSERT(data_); // This throws if we use skipNunBytes instead of reserveNunBytes @@ -310,13 +289,6 @@ void CFRecord::RollRdPtrBack(const size_t n) rdPtr -= n; } - -void CFRecord::reserveNunBytes(const size_t n) -{ - reserveNunBytes(n, static_cast(0)); -} - - void CFRecord::resetPointerToBegin() { rdPtr = 0; @@ -328,67 +300,6 @@ CFRecord& CFRecord::operator>>(bool& val) throw;// EXCEPT::LE::WrongAPIUsage("This function may only be called by mistake.", __FUNCTION__); } - - -void CFRecord::registerDelayedDataReceiver(CFStream::DELAYED_DATA_SAVER fn, const size_t n, const CFRecordType::TypeId receiver_id) -{ - //ASSERT(!data_); // This throws if used after Commit or while reading of binary - CFStream::ReceiverItem item; - item.fn = fn; - item.data_place = size_ + sizeof(unsigned short)/*size_short*/ + sizeof(CFRecordType::TypeId); // set offset relative to record beginning. - item.data_size = n; - item.receiver_id = rt_NONE == receiver_id ? getTypeId() : receiver_id; - receiver_items.push_back(item); - reserveNunBytes(n); -} - - -void CFRecord::registerDelayedDataSource(const unsigned int data, const CFRecordType::TypeId receiver_id) -{ - //ASSERT(!data_); // This throws if used after Commit or while reading of binary - CFStream::SourceItem item; - item.data = data; - item.is_file_ptr = false; - item.receiver_id = receiver_id; - item.source_id = getTypeId(); - source_items.push_back(item); -} - - -void CFRecord::registerDelayedFilePointerSource(const CFRecordType::TypeId receiver_id) -{ - //ASSERT(!data_); // This throws if used after Commit or while reading of binary - CFStream::SourceItem item; - item.data = 0; - item.is_file_ptr = true; - item.receiver_id = receiver_id; - item.source_id = getTypeId(); - source_items.push_back(item); -} - - -void CFRecord::registerDelayedFilePointerAndOffsetSource(const unsigned int offset, const CFRecordType::TypeId receiver_id) -{ - //ASSERT(!data_); // This throws if used after Commit or while reading of binary - CFStream::SourceItem item; - item.data = offset; - item.is_file_ptr = true; - item.receiver_id = receiver_id; - item.source_id = getTypeId(); - source_items.push_back(item); -} - - -void CFRecord::storeLongData(const char* buf, const size_t size) -{ - checkFitWrite(size); - - if (getMaxRecordSize() - size_ >= size) - { - memcpy(&intData[size_], buf, size); - size_ += size; - } -} #if !defined(_WIN32) && !defined(_WIN64) CFRecord& operator>>(CFRecord & record, std::string & str) { diff --git a/ASCOfficeXlsFile2/source/XlsFormat/Binary/CFRecord.h b/ASCOfficeXlsFile2/source/XlsFormat/Binary/CFRecord.h index 30b2175905..ae3785b64e 100644 --- a/ASCOfficeXlsFile2/source/XlsFormat/Binary/CFRecord.h +++ b/ASCOfficeXlsFile2/source/XlsFormat/Binary/CFRecord.h @@ -39,7 +39,7 @@ #include "../../Common/common.h" #include "../Auxiliary/HelpFunc.h" #include "../../../../ASCOfficeDocFile/DocDocxConverter/OfficeDrawing/Record.h" - +#include "../../../../DesktopEditor/common/File.h" namespace XLS { @@ -47,12 +47,11 @@ class CFRecord { public: CFRecord(CFStreamPtr stream, GlobalWorkbookInfoPtr global_info); // Create a record an read its data from the stream + CFRecord(NSFile::CFileBinary &file, GlobalWorkbookInfoPtr global_info); // Create a record an read its data from the data stream CFRecord(CFRecordType::TypeId type_id, GlobalWorkbookInfoPtr global_info); // Create an empty record + ~CFRecord(); - void save(CFStreamPtr stream); - void commitData(); - const CFRecordType::TypeId getTypeId() const; const CFRecordType::TypeString& getTypeString() const; @@ -73,35 +72,10 @@ public: // Generates an exception bool checkFitRead(const size_t size) const; // Checks whether the specified number of unsigned chars fits in max size of the buffer - // Doesn't generate an exception - const bool checkFitWriteSafe(const size_t size) const; - // Checks whether the specified number of unsigned chars fits in max size of the buffer // Generates an exception - void checkFitWrite(const size_t size) const; void skipNunBytes(const size_t n); // Skip the specified number of unsigned chars without reading void RollRdPtrBack(const size_t n); // Move read pointer back to reread some data void resetPointerToBegin(); - void reserveNunBytes(const size_t n); // Skip the specified number of unsigned chars filled them in with zeros - template - void reserveNunBytes(const size_t n, const DataType fill_data) // Skip the specified number of unsigned chars filled them in with specified data - { - checkFitWrite(n); - size_t odd_size = n / sizeof(DataType) * sizeof(DataType); - for(size_t offset = 0; offset < odd_size; offset += sizeof(DataType)) - { - reinterpret_cast(&intData[size_ + offset])[0] = fill_data; - } - for(size_t i = 0; i < n % sizeof(DataType); ++i) - { - intData[size_ + odd_size + i] = 0; - } - size_ += n; - - } - void registerDelayedDataReceiver(CFStream::DELAYED_DATA_SAVER fn, const size_t n, const CFRecordType::TypeId receiver_id = rt_NONE); - void registerDelayedDataSource(const unsigned int data, const CFRecordType::TypeId receiver_id); - void registerDelayedFilePointerSource(const CFRecordType::TypeId receiver_id); - void registerDelayedFilePointerAndOffsetSource(const unsigned int offset, const CFRecordType::TypeId receiver_id); template const T* getCurData() const @@ -130,15 +104,6 @@ public: bool loadAnyData(wchar_t & val); - template - void storeAnyData(const T& val) - { - checkFitWrite(sizeof(T)); - *reinterpret_cast(&intData[size_]) = val; - size_ += sizeof(T); - } - void storeLongData(const char* buf, const size_t size); - GlobalWorkbookInfoPtr getGlobalWorkbookInfo() { return global_info_; } CFRecord& operator>>(unsigned char& val) { loadAnyData(val); return *this; } diff --git a/ASCOfficeXlsFile2/source/XlsFormat/Binary/CFStreamCacheReader.cpp b/ASCOfficeXlsFile2/source/XlsFormat/Binary/CFStreamCacheReader.cpp index 26f7477a3d..16b6800ede 100644 --- a/ASCOfficeXlsFile2/source/XlsFormat/Binary/CFStreamCacheReader.cpp +++ b/ASCOfficeXlsFile2/source/XlsFormat/Binary/CFStreamCacheReader.cpp @@ -257,11 +257,152 @@ void CFStreamCacheReader::checkAndAppendContinueData() } } -const bool CFStreamCacheReader::isEOF() const +bool CFStreamCacheReader::isEOF() { if (stream_ == NULL) return true; return !records_cache.size() && stream_->isEOF(); } + +//--------------------------------------------------------------------------------------------------------- +FileStreamCacheReader::FileStreamCacheReader(const std::wstring &file_name, GlobalWorkbookInfoPtr global_info) +: StreamCacheReader(global_info) +{ + if (file_.OpenFile(file_name)) + { + } +} +FileStreamCacheReader::~FileStreamCacheReader() +{ + file_.CloseFile(); +} +// Skip the specified number of unsigned chars without processing +void FileStreamCacheReader::skipNunBytes(const size_t n) +{ + file_.SeekFile( file_.GetFilePosition() + n ); +} +// Reads the next CFRecord from the CFStream and if its type is not the desired one, caches it for the next call +CFRecordPtr FileStreamCacheReader::getNextRecord(const CFRecordType::TypeId desirable_type, const bool gen_except) +{ + CFRecordType::TypeId what_we_actually_read = rt_NONE; + + while(readFromStream(1)) + { + CFRecordType::TypeString rec_name = records_cache.front()->getTypeString(); + + //Log::warning(rec_name); + + if (desirable_type == rt_MsoDrawingGroup) // объединяем rt_MsoDrawingGroup + rt_Continue в один блок + { + if (checkNextRecord(desirable_type, 1)) + { + readFromStream(2); + + for(std::list::iterator good = records_cache.begin(), it = ++records_cache.begin(); + it != records_cache.end(); ++it, ++good) + { + while ((it != records_cache.end()) && (desirable_type == (*it)->getTypeId())) + { + (*good)->appendRawData(*it); + records_cache.erase(it); + if (file_.GetFilePosition() < file_.GetFileSize()) + { + records_cache.push_back(CFRecordPtr(new CFRecord(file_, global_info_))); + } + it = good; + ++it; + } + } + } + } + + if(0 == rec_name.length()) + { + Log::warning(L"The extracted record has obsoleted or unknown type(0x" + STR::int2hex_wstr(records_cache.front()->getTypeId(), sizeof(CFRecordType::TypeId)) + L")"); + records_cache.pop_front(); + continue; + } + if(skippable_records_names.end() != std::find(skippable_records_names.begin(), skippable_records_names.end(), rec_name)) + { + //Log::warning("The extracted record has been skipped (" + rec_name + ")"); + records_cache.pop_front(); + continue; + } + break; + } + + if(0 != records_cache.size()) + { + what_we_actually_read = records_cache.front()->getTypeId(); + + // if we get what was requested + if(desirable_type == what_we_actually_read || desirable_type == CFRecordType::ANY_TYPE) + { + CFRecordPtr ret = records_cache.front(); + records_cache.pop_front(); + return ret; + } + } + + if(gen_except) + { + // теги разные + std::string inType = XLS::CFRecordType::getStringById(desirable_type); + std::string outType = CFRecordType::getStringById(what_we_actually_read); + + Log::warning("The extracted record is not of requested type.\nRequested: \"" + + XLS::CFRecordType::getStringById(desirable_type) + "\" Extracted: \"" + CFRecordType::getStringById(what_we_actually_read) + "\""); + } + return CFRecordPtr(); +} +// Make sure the internal buffer has concrete number of records. Returns number of records read +const size_t FileStreamCacheReader::readFromStream(const size_t num_of_records_min_necessary) +{ + const size_t current_records_num = records_cache.size(); + if (current_records_num >= num_of_records_min_necessary) + { + return current_records_num; + } + + while (records_cache.size() < num_of_records_min_necessary && file_.GetFilePosition() < file_.GetFileSize()) + { + records_cache.push_back(CFRecordPtr(new CFRecord(file_, global_info_))); + } + + checkAndAppendContinueData(); + return records_cache.size(); +} + +// Checks whether the next record is Continue and append its data to the real record if so +void FileStreamCacheReader::checkAndAppendContinueData() +{ + if (!records_cache.size()) + { + return; + } + + for (std::list::iterator good = records_cache.begin(), it = ++records_cache.begin(); + it != records_cache.end(); ++it, ++good) + { + size_t typeRecord = (*it)->getTypeId(); + while (it != records_cache.end() && (rt_Continue == (*it)->getTypeId()) ) + { + (*good)->appendRawData(*it); + records_cache.erase(it); // now 'it' is invalid + if (file_.GetFilePosition() < file_.GetFileSize()) + { + records_cache.push_back(CFRecordPtr(new CFRecord(file_, global_info_))); + } + it = good; + ++it; // Now it may became end(), checked in 'for' + } + } +} + +bool FileStreamCacheReader::isEOF() +{ + return !records_cache.size() && (file_.GetFilePosition() >= file_.GetFileSize()); +} + } // namespace XLS diff --git a/ASCOfficeXlsFile2/source/XlsFormat/Binary/CFStreamCacheReader.h b/ASCOfficeXlsFile2/source/XlsFormat/Binary/CFStreamCacheReader.h index 790275e844..fcaa258479 100644 --- a/ASCOfficeXlsFile2/source/XlsFormat/Binary/CFStreamCacheReader.h +++ b/ASCOfficeXlsFile2/source/XlsFormat/Binary/CFStreamCacheReader.h @@ -60,7 +60,7 @@ public: // Checks whether the next record is Continue and append its data to the real record if so virtual void checkAndAppendContinueData() = 0; - virtual const bool isEOF() const = 0; + virtual bool isEOF() = 0; // Skip the specified number of unsigned chars without processing virtual void skipNunBytes(const size_t n) = 0; @@ -93,9 +93,24 @@ public: virtual CFRecordPtr getNextRecord(const CFRecordType::TypeId desirable_type, const bool gen_except = false); virtual void skipNunBytes(const size_t n); virtual void checkAndAppendContinueData(); - virtual const bool isEOF() const; + virtual bool isEOF(); private: virtual const size_t readFromStream(const size_t num_of_records_min_necessary); CFStreamPtr stream_; }; + +class FileStreamCacheReader : public StreamCacheReader +{ +public: + FileStreamCacheReader(const std::wstring &file_name, const GlobalWorkbookInfoPtr global_info); + virtual ~FileStreamCacheReader(); + + virtual CFRecordPtr getNextRecord(const CFRecordType::TypeId desirable_type, const bool gen_except = false); + virtual void skipNunBytes(const size_t n); + virtual void checkAndAppendContinueData(); + virtual bool isEOF(); +private: + virtual const size_t readFromStream(const size_t num_of_records_min_necessary); + NSFile::CFileBinary file_; +}; } // namespace XLS diff --git a/ASCOfficeXlsFile2/source/XlsXlsxConverter/XlsConverter.cpp b/ASCOfficeXlsFile2/source/XlsXlsxConverter/XlsConverter.cpp index 04b4f9a602..0484651075 100644 --- a/ASCOfficeXlsFile2/source/XlsXlsxConverter/XlsConverter.cpp +++ b/ASCOfficeXlsFile2/source/XlsXlsxConverter/XlsConverter.cpp @@ -136,12 +136,31 @@ XlsConverter::XlsConverter(const std::wstring & xlsFileName, const std::wstring is_encrypted = false; output_document = new oox::package::xlsx_document(); + _UINT16 workbook_code_page = XLS::WorkbookStreamObject::DefaultCodePage; + try { xls_file = boost::shared_ptr(new XLS::CompoundFile(xlsFileName, XLS::CompoundFile::cf_ReadMode)); if (xls_file->isError()) { + xls_global_info = boost::shared_ptr(new XLS::GlobalWorkbookInfo(workbook_code_page, this)); + XLS::StreamCacheReaderPtr file_reader(new XLS::FileStreamCacheReader(xlsFileName, xls_global_info)); + + xls_document = boost::shared_ptr(new XLS::WorkbookStreamObject(workbook_code_page)); + + XLS::BinReaderProcessor proc(file_reader, xls_document.get() , true); + //proc.mandatory(*xls_document.get()); + + XLS::WorksheetSubstream worksheet_substream(1); + if (proc.mandatory(worksheet_substream)) + { + bool WorksheetSubstream_found = true; + + //m_arWorksheetSubstream.push_back(elements_.back()); elements_.pop_back(); + } + + return; } @@ -151,7 +170,6 @@ XlsConverter::XlsConverter(const std::wstring & xlsFileName, const std::wstring summary = xls_file->getNamedStream(L"SummaryInformation"); doc_summary = xls_file->getNamedStream(L"DocumentSummaryInformation"); - _UINT16 workbook_code_page = XLS::WorkbookStreamObject::DefaultCodePage; if(summary) { OLEPS::SummaryInformation summary_info(summary);