Files
core/ASCOfficeXlsFile2/source/XlsFormat/Binary/CFStreamCacheReader.cpp
Elen.Subbotina cf9d55e913 XlsFile2 bug 13912
git-svn-id: svn://fileserver/activex/AVS/Sources/TeamlabOffice/trunk/ServerComponents@63941 954022d7-b5bf-4e40-9824-e11837661b57
2016-05-21 00:21:15 +03:00

232 lines
6.4 KiB
C++

#include "CFStreamCacheReader.h"
#include "CFRecord.h"
#include "CFStream.h"
#include <Logic/Biff_records/BOF.h>
//#include <Exception/RequestedRecordNotFound.h>
namespace XLS
{;
CFStreamCacheReader::CFStreamCacheReader(CFStreamPtr stream, GlobalWorkbookInfoPtr global_info)
: stream_(stream),
global_info_(global_info)
{
skippable_records_names.push_back("StartBlock");
skippable_records_names.push_back("EndBlock");
skippable_records_names.push_back("ChartFrtInfo");
//skippable_records_names.push_back("TextPropsStream");
//skippable_records_names.push_back("ShapePropsStream");
}
CFStreamCacheReader::~CFStreamCacheReader()
{
}
// Reads the next CFRecord from the CFStream and if its type is not the desired one, caches it for the next call
CFRecordPtr CFStreamCacheReader::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<CFRecordPtr>::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(!stream_->isEOF())
{
records_cache.push_back(CFRecordPtr(new CFRecord(stream_, 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();
}
// Check if the next read record would be of desired type
const bool CFStreamCacheReader::checkNextRecord(const CFRecordType::TypeId desirable_type, const size_t num_records_to_check)
{
readFromStream(num_records_to_check);
// if we would get what was requested
// ANY_TYPE is checked just to make the fake read from stream and get an error if the stream is ended
for(std::list<CFRecordPtr>::const_iterator it = records_cache.begin(), itEnd = records_cache.end(); it != itEnd; ++it)
{
size_t type = (*it)->getTypeId();
if(desirable_type == (*it)->getTypeId() || desirable_type == CFRecordType::ANY_TYPE)
{
return true;
}
}
return false;
}
// Make sure the internal buffer has concrete number of records. Returns number of records read
const size_t CFStreamCacheReader::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 && ((stream_) && (!stream_->isEOF())))
{
records_cache.push_back(CFRecordPtr(new CFRecord(stream_, 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 CFStreamCacheReader::checkAndAppendContinueData()
{
if(!records_cache.size())
{
return;
}
for(std::list<CFRecordPtr>::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(!stream_->isEOF())
{
records_cache.push_back(CFRecordPtr(new CFRecord(stream_, global_info_)));
}
it = good;
++it; // Now it may became end(), checked in 'for'
}
}
}
const bool CFStreamCacheReader::isEOF() const
{
if (stream_ == NULL) return true;
return !records_cache.size() && stream_->isEOF();
}
// Skip the specified number of unsigned chars without processing
void CFStreamCacheReader::skipNunBytes(const size_t n)
{
if (stream_)
{
stream_->seekFromCurForward(n);
}
}
// Seek to the next substream (Read all records till EOF then skip EOF)
// Doesn't generate EndOfStreamReached if the stream is the last one
const bool CFStreamCacheReader::SeekToEOF()
{
while(readFromStream(1))
{
if(rt_EOF == records_cache.front()->getTypeId())
{
// records_cache.pop_front(); // Skip EOF
break;
}
records_cache.pop_front(); // Skip non-EOF
}
return true;
}
// Extract the next record from the stream leaving it in the cache for future read.
// Always call resetPointerToBegin for the extracted CFRecord after using it
CFRecordPtr CFStreamCacheReader::touchTheNextRecord()
{
if(readFromStream(1))// make sure something is in cache
{
return records_cache.front();
}
return CFRecordPtr();
}
// Check the next record type
const CFRecordType::TypeId CFStreamCacheReader::getNextRecordType()
{
if(isEOF())
{
return rt_NONE;
}
readFromStream(1); // I don't check the result of readFromStream() because it was done implicitly in isEOF()
return records_cache.front()->getTypeId();
}
} // namespace XLS