📄 basicexcel.cpp
字号:
int maxProperties = properties_.size();
// Change Root Entry start block
if (!properties_.empty())
{
int count = 0;
for (int j=0; j<maxIndices; ++j)
{
if (properties_[0]->startBlock_ > indices[j] &&
properties_[0]->startBlock_ != -2) ++count;
}
properties_[0]->startBlock_ -= count;
}
{for (int i=1; i<maxProperties; ++i)
{
if (properties_[i]->size_ >= 4096)
{
// Change individual properties start block if their size is more than 4096
int count = 0;
for (int j=0; j<maxIndices; ++j)
{
if (properties_[i]->startBlock_ > indices[j] &&
properties_[i]->startBlock_ != -2) ++count;
}
properties_[i]->startBlock_ -= count;
}
}}
}
void CompoundFile::SplitPath(const wchar_t* path,
wchar_t*& parentpath,
wchar_t*& propertyname)
// PURPOSE: Get a path's parent path and its name.
// EXPLAIN: E.g. path = "\\Abc\\def\\ghi => parentpath = "\\Abc\\def", propertyname = "ghi".
// REQUIRE: Calling function is responsible for deleting the memory created for
// REQUIRE: parentpath and propertyname.
{
int pathLength = wcslen(path);
int npos;
for (npos=pathLength-1; npos>0; --npos)
{
if (path[npos] == L'\\') break;
}
if (npos != 0)
{
// Get parent path if available
parentpath = new wchar_t[npos+1];
//copy (path, path+npos, parentpath);
wmemcpy(parentpath, path, npos);
parentpath[npos] = 0;
++npos;
}
// Get property name (ignore initial "\" if present)
if (npos==0 && pathLength > 0 && path[0] == L'\\')
++npos;
propertyname = new wchar_t[pathLength-npos+1];
//copy (path+npos, path+pathLength, propertyname);
wmemcpy(propertyname, path+npos, pathLength - npos);
propertyname[pathLength-npos] = 0;
}
/*********************** Inaccessible Header Functions ***************************/
bool CompoundFile::LoadHeader()
// PURPOSE: Load header information for compound file.
// PROMISE: Return true if file header contain magic number, false if otherwise.
{
file_.Read(0, &*(block_.begin()));
header_.Read(&*(block_.begin()));
// Check magic number to see if it is a compound file
if (header_.fileType_ != 0xE11AB1A1E011CFD0LL) return false;
block_.resize(header_.bigBlockSize_); // Resize buffer block
file_.SetBlockSize(header_.bigBlockSize_); // Resize block array block size
return true;
}
void CompoundFile::SaveHeader()
// PURPOSE: Save header information for compound file.
{
header_.Write(&*(block_.begin()));
file_.Write(0, &*(block_.begin()));
}
/*********************** Inaccessible BAT Functions ***************************/
void CompoundFile::LoadBAT()
// PURPOSE: Load all block allocation table information for compound file.
{
// Read BAT indices
{for (int i=0; i<header_.BATCount_; ++i)
{
// Load blocksIndices_
blocksIndices_.resize(blocksIndices_.size()+128, -1);
file_.Read(header_.BATArray_[i]+1, &*(block_.begin()));
for (int j=0; j<128; ++j)
{
LittleEndian::Read(&*(block_.begin()), blocksIndices_[j+i*128], j*4, 4);
}
}}
// Read XBAT indices
{for (int i=0; i<header_.XBATCount_; ++i)
{
blocksIndices_.resize(blocksIndices_.size()+128, -1);
file_.Read(header_.XBATStart_+i+1, &*(block_.begin()));
for (int j=0; j<128; ++j)
{
LittleEndian::Read(&*(block_.begin()), blocksIndices_[j+((i+109)*128)], j*4, 4);
}
}}
// Read SBAT indices
{for (int i=0; i<header_.SBATCount_; ++i)
{
sblocksIndices_.resize(sblocksIndices_.size()+128, -1);
file_.Read(header_.SBATStart_+i+1, &*(block_.begin()));
for (int j=0; j<128; ++j)
{
LittleEndian::Read(&*(block_.begin()), sblocksIndices_[j+i*128], j*4, 4);
}
}}
}
void CompoundFile::SaveBAT()
// PURPOSE: Save all block allocation table information for compound file.
{
// Write BAT indices
{for (int i=0; i<header_.BATCount_; ++i)
{
for (int j=0; j<128; ++j)
{
LittleEndian::Write(&*(block_.begin()), blocksIndices_[j+i*128], j*4, 4);
}
file_.Write(header_.BATArray_[i]+1, &*(block_.begin()));
}}
// Write XBAT indices
{for (int i=0; i<header_.XBATCount_; ++i)
{
for (int j=0; j<128; ++j)
{
LittleEndian::Write(&*(block_.begin()), blocksIndices_[j+((i+109)*128)], j*4, 4);
}
file_.Write(header_.XBATStart_+i+1, &*(block_.begin()));
}}
// Write SBAT indices
{for (int i=0; i<header_.SBATCount_; ++i)
{
for (int j=0; j<128; ++j)
{
LittleEndian::Write(&*(block_.begin()), sblocksIndices_[j+i*128], j*4, 4);
}
file_.Write(header_.SBATStart_+i+1, &*(block_.begin()));
}}
}
int CompoundFile::DataSize(int startIndex, bool isBig)
// PURPOSE: Gets the total size occupied by a property, starting from startIndex.
// EXPLAIN: isBig is true if property uses big blocks, false if it uses small blocks.
// PROMISE: Returns the total size occupied by the property which is the total
// PROMISE: number of blocks occupied multiply by the block size.
{
vector<int> indices;
if (isBig)
{
GetBlockIndices(startIndex, indices, true);
return indices.size()*header_.bigBlockSize_;
}
else
{
GetBlockIndices(startIndex, indices, false);
return indices.size()*header_.smallBlockSize_;
}
}
int CompoundFile::ReadData(int startIndex, char* data, bool isBig)
// PURPOSE: Read a property's data, starting from startIndex.
// REQUIRE: data must be large enough to receive the property's data
// REQUIRE: The required data size can be obtained by using DataSize().
// EXPLAIN: isBig is true if property uses big blocks, false if it uses small blocks.
// PROMISE: Returns the total size occupied by the property which is the total
// PROMISE: number of blocks occupied multiply by the block size.
{
vector<int> indices;
if (isBig)
{
GetBlockIndices(startIndex, indices, true);
int maxIndices = indices.size();
for (int i=0; i<maxIndices; ++i)
{
file_.Read(indices[i]+1, data+i*header_.bigBlockSize_);
}
return maxIndices*header_.bigBlockSize_;
}
else
{
GetBlockIndices(startIndex, indices, false);
int minIndex = *min_element(indices.begin(), indices.end());
int maxIndex = *max_element(indices.begin(), indices.end());
int smallBlocksPerBigBlock = header_.bigBlockSize_ / header_.smallBlockSize_;
int minBlock = minIndex / smallBlocksPerBigBlock;
int maxBlock = maxIndex / smallBlocksPerBigBlock +
(maxIndex % smallBlocksPerBigBlock ? 1 : 0);
int totalBlocks = maxBlock - minBlock;
char* buffer = new char[DataSize(properties_[0]->startBlock_, true)];
ReadData(properties_[0]->startBlock_, buffer, true);
int maxIndices = indices.size();
for (int i=0; i<maxIndices; ++i)
{
int start = (indices[i] - minBlock*smallBlocksPerBigBlock)*header_.smallBlockSize_;
/*copy (buffer+start,
buffer+start+header_.smallBlockSize_,
data+i*header_.smallBlockSize_);*/
memcpy(data+i*header_.smallBlockSize_, buffer+start, header_.smallBlockSize_);
}
delete[] buffer;
return maxIndices*header_.smallBlockSize_;
}
}
int CompoundFile::WriteData(const char* data, int size, int startIndex, bool isBig)
// PURPOSE: Write data to a property, starting from startIndex.
// EXPLAIN: startIndex can be -2 if property initially has no data.
// EXPLAIN: isBig is true if property uses big blocks, false if it uses small blocks.
// PROMISE: The file's original data will be replaced by the new data.
// PROMISE: Returns the startIndex of new data for the property.
{
if (isBig)
{
if (size==0 && startIndex==-2) return startIndex;
// Get present indices
vector<int> indices;
GetBlockIndices(startIndex, indices, true);
int maxPresentBlocks = indices.size();
// Calculate how many blocks does the data need
int extraSize = size % header_.bigBlockSize_;
int maxNewBlocks = size / header_.bigBlockSize_ + (extraSize ? 1 : 0);
// Readjust indices and remove blocks if new data size is smaller than original
int extraBlocks = maxPresentBlocks - maxNewBlocks;
if (extraBlocks > 0)
{
// Place new end marker
if (maxNewBlocks != 0) blocksIndices_[indices[maxNewBlocks]-1] = -2;
else startIndex = -2;
// Get indices of blocks to delete
vector<int> indicesToRemove(extraBlocks);
copy (indices.begin()+maxNewBlocks, indices.end(), indicesToRemove.begin());
indices.erase(indices.begin()+maxNewBlocks, indices.end());
// Remove extra blocks and readjust indices
FreeBlocks(indicesToRemove, true);
}
// Write blocks into available space
int remainingFullBlocks = size / header_.bigBlockSize_;
int curIndex=0;
if (maxPresentBlocks != 0)
{
for (; remainingFullBlocks && curIndex<maxPresentBlocks;
--remainingFullBlocks, ++curIndex)
{
file_.Write(indices[curIndex]+1, data+curIndex*header_.bigBlockSize_);
}
}
// Check if all blocks have been written
int index;
if (indices.empty()) index = 0;
else if (curIndex == 0) index = indices[0];
else index = (startIndex != -2) ? indices[curIndex-1] : 0;
if (remainingFullBlocks != 0)
{
// Require extra blocks to write data (i.e. new data is larger than original data
do
{
int newIndex = GetFreeBlockIndex(true); // Get new free block to write data
if (startIndex == -2) startIndex = newIndex; // Get start index
else LinkBlocks(index, newIndex, true); // Link last index to new index
file_.Write(newIndex+1, data+curIndex*header_.bigBlockSize_);
++curIndex;
index = newIndex;
} while (--remainingFullBlocks);
}
if (extraSize != 0)
{
int newIndex;
if (curIndex >= maxPresentBlocks)
{
// No more free blocks to write extra block data
newIndex = GetFreeBlockIndex(true); // Get new free block to write data
if (startIndex == -2) startIndex = newIndex;
else LinkBlocks(index, newIndex,true);
}
else newIndex = indices[curIndex];
// Write extra block after increasing its size to the minimum block size
vector<char> tempdata(header_.bigBlockSize_, 0);
copy (data+curIndex*header_.bigBlockSize_, data+curIndex*header_.bigBlockSize_+extraSize, tempdata.begin());
file_.Write(newIndex+1, &*(tempdata.begin()));
}
return startIndex;
}
else
{
if (size==0 && startIndex==-2) return startIndex;
if (size != 0 && properties_[0]->startBlock_ == -2)
{
int newIndex = GetFreeBlockIndex(true);
fill (block_.begin(), block_.end(), 0);
file_.Insert(newIndex, &*(block_.begin()));
IncreaseLocationReferences(vector<int>(1, newIndex));
properties_[0]->startBlock_ = newIndex;
properties_[0]->size_ = header_.bigBlockSize_;
}
// Get present indices
vector<int> indices;
GetBlockIndices(startIndex, indices, false);
int maxPresentBlocks = indices.size();
// Calculate how many blocks does the data need
int extraSize = size % header_.smallBlockSize_;
int maxNewBlocks = size / header_.smallBlockSize_ + (extraSize ? 1 : 0);
vector<char> smallBlocksData;
int extraBlocks = maxPresentBlocks - maxNewBlocks;
if (extraBlocks > 0)
{
// Readjust indices and remove blocks
// Place new end marker
if (maxNewBlocks != 0) sblocksIndices_[indices[maxNewBlocks]-1] = -2;
else startIndex = -2;
// Get indices of blocks to delete
vector<int> indicesToRemove(extraBlocks);
copy (indices.begin()+maxNewBlocks, indices.end(), indicesToRemove.begin());
indices.erase(indices.begin()+maxNewBlocks, indices.end());
// Remove extra blocks and readjust indices
FreeBlocks(indicesToRemove, false);
}
else if (extraBlocks < 0)
{
int maxBlocks = properties_[0]->size_ / header_.bigBlockSize_ +
(properties_[0]->size_ % header_.bigBlockSize_ ? 1 : 0);
int actualSize = maxBlocks * header_.bigBlockSize_;
smallBlocksData.resize(actualSize);
ReadData(properties_[0]->startBlock_, &*(smallBlocksData.begin()), true);
smallBlocksData.resize(properties_[0]->size_);
// Readjust indices and add blocks
int newBlocksNeeded = -extraBlocks;
int index = maxPresentBlocks - 1;
for (int i=0; i<newBlocksNeeded; ++i)
{
int newIndex = GetFreeBlockIndex(false); // Get new free block to write data
if (startIndex == -2) startIndex = newIndex; // Get start index
else LinkBlocks(index, newIndex, false); // Link last index to new index
smallBlocksData.insert(smallBlocksData.begin()+newIndex,
header_.smallBlockSize_, 0);
index = newIndex;
}
properties_[0]->size_ = newBlocksNeeded * header_.smallBlockSize_;
}
if (smallBlocksData.empty())
{
int maxBlocks = properties_[0]->size_ / header_.bigBlockSize_ +
(properties_[0]->size_ % header_.bigBlockSize_ ? 1 : 0);
int actualSize = maxBlocks * header_.bigBlockSize_;
smallBlocksData.resize(actualSize);
ReadData(properties_[0]->startBlock_, &*(smallBlocksData.begin()), true);
smallBlocksData.resize(properties_[0]->size_);
}
// Write blocks
GetBlockIndices(startIndex, indices, false);
int fullBlocks = size / header_.smallBlockSize_;
for (int i=0; i<fullBlocks; ++i)
{
copy (data+i*header_.smallBlockSize_,
data+i*header_.smallBlockSize_+header_.smallBlockSize_,
smallBlocksData.begin()+indices[i]*header_.smallBlockSize_);
}
if (extraSize != 0)
{
copy (data+fullBlocks*header_.smallBlockSize_,
data+fullBlocks*header_.smallBlockSize_+extraSize,
smallBlocksData.begin()+indices[fullBlocks]*header_.smallBlockSize_);
}
WriteData(&*(smallBlocksData.begin()), properties_[0]->size_,
properties_[0]->startBlock_, true);
return startIndex;
}
}
void CompoundFile::GetBlockIndices(int startIndex, vector<int>& indices, bool isBig)
// PURPOSE: Get the indices of blocks where data are stored, starting from startIndex.
// EXPLAIN: isBig is true if property uses big blocks, false if it uses small blocks.
{
indices.clear();
if (isBig)
{
for (int i=startIndex; i!=-2; i=blocksIndices_[i]) indices.push_back(i);
}
else
{
for (int i=startIndex; i!=-2; i=sblocksIndices_[i]) indices.push_back(i);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -