📄 basicexcel.cpp
字号:
int CompoundFile::GetFreeBlockIndex(bool isBig)
// PURPOSE: Get the index of a new block where data can be stored.
// EXPLAIN: isBig is true if property uses big blocks, false if it uses small blocks.
// PROMISE: It does not physically create a new block in the compound file.
// PROMISE: It only adjust BAT arrays and indices or SBAT arrays and indices so that
// PROMISE: it gives the index of a new block where data can be inserted.
{
int index;
if (isBig)
{
// Find first free location
index = distance(blocksIndices_.begin(),
find(blocksIndices_.begin(),
blocksIndices_.end(), -1));
if (index == blocksIndices_.size())
{
ExpandBATArray(true);
index = distance(blocksIndices_.begin(),
find(blocksIndices_.begin(),
blocksIndices_.end(), -1));
}
blocksIndices_[index] = -2;
}
else
{
// Find first free location
index = distance(sblocksIndices_.begin(),
find(sblocksIndices_.begin(),
sblocksIndices_.end(), -1));
if (index == sblocksIndices_.size())
{
ExpandBATArray(false);
index = distance(sblocksIndices_.begin(),
find(sblocksIndices_.begin(),
sblocksIndices_.end(), -1));
}
sblocksIndices_[index] = -2;
}
return index;
}
void CompoundFile::ExpandBATArray(bool isBig)
// PURPOSE: Create a new block of BAT or SBAT indices.
// EXPLAIN: isBig is true if property uses big blocks, false if it uses small blocks.
{
int newIndex;
fill (block_.begin(), block_.end(), -1);
if (isBig)
{
int BATindex = distance(&header_.BATArray_[0],
find(header_.BATArray_,
header_.BATArray_+109, -1));
if (BATindex < 109)
{
// Set new BAT index location
newIndex = blocksIndices_.size(); // New index location
file_.Insert(newIndex+1, &*(block_.begin()));
IncreaseLocationReferences(vector<int>(1, newIndex));
// Update BAT array
header_.BATArray_[BATindex] = newIndex;
++header_.BATCount_;
}
else
{
// No free BAT indices. Increment using XBAT
// Set new XBAT index location
if (header_.XBATCount_ != 0)
{
newIndex = header_.XBATStart_ + header_.XBATCount_;
file_.Insert(newIndex, &*(block_.begin()));
IncreaseLocationReferences(vector<int>(1, newIndex));
}
else
{
newIndex = blocksIndices_.size();
file_.Insert(newIndex, &*(block_.begin()));
IncreaseLocationReferences(vector<int>(1, newIndex));
header_.XBATStart_ = newIndex;
}
++header_.XBATCount_;
}
blocksIndices_.insert(blocksIndices_.begin()+newIndex, -3);
blocksIndices_.resize(blocksIndices_.size()+127, -1);
}
else
{
// Set new SBAT index location
if (header_.SBATCount_ != 0)
{
newIndex = header_.SBATStart_ + header_.SBATCount_;
file_.Insert(newIndex, &*(block_.begin()));
IncreaseLocationReferences(vector<int>(1, newIndex));
}
else
{
newIndex = GetFreeBlockIndex(true);
file_.Insert(newIndex, &*(block_.begin()));
IncreaseLocationReferences(vector<int>(1, newIndex));
header_.SBATStart_ = newIndex;
}
++header_.SBATCount_;
sblocksIndices_.resize(sblocksIndices_.size()+128, -1);
}
}
void CompoundFile::LinkBlocks(int from, int to, bool isBig)
// PURPOSE: Link one BAT index to another.
// EXPLAIN: isBig is true if property uses big blocks, false if it uses small blocks.
{
if (isBig) blocksIndices_[from] = to;
else sblocksIndices_[from] = to;
}
void CompoundFile::FreeBlocks(vector<int>& indices, bool isBig)
// PURPOSE: Delete blocks of data from compound file.
// EXPLAIN: indices contains indices to blocks of data to be deleted.
// EXPLAIN: isBig is true if property uses big blocks, false if it uses small blocks.
{
if (isBig)
{
// Decrease all location references before deleting blocks from file.
DecreaseLocationReferences(indices);
int maxIndices = indices.size();
{for (int i=0; i<maxIndices; ++i) ++indices[i];} // Increase by 1 because Block index 1 corresponds to index 0 here
file_.Erase(indices);
// Shrink BAT indices if necessary
vector<int> indicesToRemove;
while (distance(find(blocksIndices_.begin(),
blocksIndices_.end(),-1),
blocksIndices_.end()) >= 128)
{
blocksIndices_.resize(blocksIndices_.size()-128);
if (header_.XBATCount_ != 0)
{
// Shrink XBAT first
--header_.XBATCount_;
indicesToRemove.push_back(header_.XBATStart_+header_.XBATCount_+1); // Add 1 because Block index 1 corresponds to index 0 here
if (header_.XBATCount_ == 0) header_.XBATStart_ = -2;
}
else
{
// No XBAT, delete last occupied BAT array element
int BATindex = distance(&header_.BATArray_[0],
find(header_.BATArray_,
header_.BATArray_+109, -1));
if (BATindex != 109)
{
--header_.BATCount_;
indicesToRemove.push_back(header_.BATArray_[BATindex-1]+1); // Add 1 because Block index 1 corresponds to index 0 here
header_.BATArray_[BATindex-1] = -1;
}
}
}
// Erase extra BAT indices if present
if (!indicesToRemove.empty()) file_.Erase(indicesToRemove);
}
else
{
// Erase block
int maxIndices = indices.size();
int maxBlocks = properties_[0]->size_ / header_.bigBlockSize_ +
(properties_[0]->size_ % header_.bigBlockSize_ ? 1 : 0);
int size = maxBlocks * header_.bigBlockSize_;
char* data = new char[size];
ReadData(properties_[0]->startBlock_, data, true);
int maxSmallBlocks = properties_[0]->size_ / header_.smallBlockSize_;
char* newdata = new char[properties_[0]->size_-maxIndices*header_.smallBlockSize_];
{for (int i=0, j=0; i<maxSmallBlocks; ++i)
{
if (find(indices.begin(), indices.end(), i) == indices.end())
{
/*copy (data+i*header_.smallBlockSize_,
data+i*header_.smallBlockSize_+header_.smallBlockSize_,
newdata+j*header_.smallBlockSize_);*/
memcpy( newdata+j*header_.smallBlockSize_,
data+i*header_.smallBlockSize_,
header_.smallBlockSize_);
++j;
}
}}
properties_[0]->startBlock_ = WriteData(newdata, properties_[0]->size_-maxIndices*header_.smallBlockSize_,
properties_[0]->startBlock_, true);
properties_[0]->size_ -= maxIndices*header_.smallBlockSize_;
delete[] data;
delete[] newdata;
// Change SBAT indices
int maxSBATindices = sblocksIndices_.size();
{for (int i=0; i<maxIndices; ++i)
{
for (int j=0; j<maxSBATindices; ++j)
{
if (j == indices[i]) continue;
if (sblocksIndices_[j] == indices[i]) sblocksIndices_[j] = sblocksIndices_[indices[i]];
if (sblocksIndices_[j] > indices[i] &&
sblocksIndices_[j] != -1 &&
sblocksIndices_[j] != -2) --sblocksIndices_[j];
}
}}
sort (indices.begin(), indices.end(), greater<int>());
{for (int i=0; i<maxIndices; ++i)
{
sblocksIndices_.erase(sblocksIndices_.begin()+indices[i]);
sblocksIndices_.push_back(-1);
}}
vector<int> indicesToRemove;
while (distance(find(sblocksIndices_.begin(),
sblocksIndices_.end(),-1),
sblocksIndices_.end()) >= 128)
{
// Shrink SBAT indices if necessary
sblocksIndices_.resize(sblocksIndices_.size()-128);
--header_.SBATCount_;
indicesToRemove.push_back(header_.SBATStart_+header_.SBATCount_);
if (header_.SBATCount_ == 0) header_.SBATStart_ = -2;
}
FreeBlocks(indicesToRemove, true);
}
}
/*********************** Inaccessible Properties Functions ***************************/
void CompoundFile::LoadProperties()
// PURPOSE: Load properties information for compound file.
{
// Read properties' data from compound file.
int propertiesSize = DataSize(header_.propertiesStart_, true);
char* buffer = new char[propertiesSize];
ReadData(header_.propertiesStart_, buffer, true);
// Split properties' data into individual property.
int maxPropertiesBlock = propertiesSize / header_.bigBlockSize_;
int propertiesPerBlock = header_.bigBlockSize_ / 128;
int maxProperties = maxPropertiesBlock * propertiesPerBlock;
int maxBlocks = maxProperties / propertiesPerBlock +
(maxProperties % propertiesPerBlock ? 1 : 0);
for (int i=0; i<maxBlocks; ++i)
{
for (int j=0; j<4; ++j)
{
// Read individual property
Property* property = new Property;
property->Read(buffer+i*512+j*128);
if (wcslen(property->name_) == 0)
{
delete property;
break;
}
properties_.push_back(property);
}
}
delete[] buffer;
// Generate property trees
propertyTrees_->parent_ = 0;
propertyTrees_->self_ = properties_[0];
propertyTrees_->index_ = 0;
InsertPropertyTree(propertyTrees_,
properties_[properties_[0]->childProp_],
properties_[0]->childProp_);
}
void CompoundFile::SaveProperties()
// PURPOSE: Save properties information for compound file.
{
// Calculate total size required by properties
int maxProperties = properties_.size();
int propertiesPerBlock = header_.bigBlockSize_ / 128;
int maxBlocks = maxProperties / propertiesPerBlock +
(maxProperties % propertiesPerBlock ? 1 : 0);
int propertiesSize = maxBlocks*header_.bigBlockSize_;
char* buffer = new char[propertiesSize];
{for (int i=0; i<propertiesSize; ++i) buffer[i] = 0;}
{for (int i=0; i<maxProperties; ++i)
{
// Save individual property
properties_[i]->Write(buffer+i*128);
}}
// Write properties' data to compound file.
WriteData(buffer, propertiesSize, header_.propertiesStart_, true);
delete[] buffer;
}
int CompoundFile::MakeProperty(const wchar_t* path, CompoundFile::Property* property)
// PURPOSE: Create a new property in the compound file.
// EXPLAIN: path is the full path name for the property.
// EXPLAIN: property contains information on the type of property to be created.
{
wchar_t* parentpath = 0;
wchar_t* propertyname = 0;
// Change to the specified directory. If specified directory is not present,
// create it.
if (wcslen(path) != 0)
{
if (path[0] == L'\\') currentDirectory_ = propertyTrees_;
}
SplitPath(path, parentpath, propertyname);
if (propertyname != 0)
{
if (parentpath != 0)
{
if (ChangeDirectory(parentpath) != SUCCESS)
{
int ret = MakeDirectory(parentpath);
if (ret != SUCCESS)
{
delete[] parentpath;
delete[] propertyname;
return ret;
}
else ChangeDirectory(parentpath);
}
delete[] parentpath;
}
// Insert property into specified directory
int propertynameLength = wcslen(propertyname);
if (propertynameLength >= 32)
{
delete[] propertyname;
return NAME_TOO_LONG;
}
wcscpy(property->name_, propertyname);
delete[] propertyname;
property->nameSize_ = propertynameLength*2+2;
if (FindProperty(currentDirectory_, property->name_) == 0)
{
// Find location to insert property
int maxProperties = properties_.size();
int index;
for (index=1; index<maxProperties; ++index)
{
if (*(properties_[index]) > *property) break;
}
if (index != maxProperties)
{
// Change references for all properties affected by the new property
IncreasePropertyReferences(propertyTrees_, index);
}
properties_.insert(properties_.begin()+index, property);
InsertPropertyTree(currentDirectory_, property, index);
return SUCCESS;
}
else return DUPLICATE_PROPERTY;
}
else
{
if (parentpath != 0) delete[] parentpath;
return INVALID_PATH;
}
}
CompoundFile::PropertyTree* CompoundFile::FindProperty(int index)
// PURPOSE: Find property in the compound file, given the index of the property.
// PROMISE: Returns a pointer to the property tree of the property if property
// PROMISE: is present, 0 if otherwise.
{
if (previousDirectories_.empty()) previousDirectories_.push_back(propertyTrees_);
PropertyTree* currentTree = previousDirectories_.back();
if (currentTree->index_ != index)
{
int maxChildren = currentTree->children_.size();
for (int i=0; i<maxChildren; ++i)
{
previousDirectories_.push_back(currentTree->children_[i]);
PropertyTree* child = FindProperty(index);
if (child != 0)
{
previousDirectories_.pop_back();
return child;
}
}
}
else
{
previousDirectories_.pop_back();
return currentTree;
}
previousDirectories_.pop_back();
return 0;
}
CompoundFile::PropertyTree* CompoundFile::FindProperty(const wchar_t* path)
// PURPOSE: Find property in the compound file, given the path of the property.
// PROMISE: Returns a pointer to the property tree of the property if property
// PROMISE: is present, 0 if otherwise.
{
previousDirectories_.push_back(currentDirectory_);
// Change to specified directory
wchar_t* parentpath = 0;
wchar_t* filename = 0;
if (wcslen(path) != 0)
{
if (path[0] == L'\\') currentDirectory_ = propertyTrees_;
}
SplitPath(path, parentpath, filename);
if (parentpath != 0)
{
int ret = ChangeDirectory(parentpath);
delete[] parentpath;
if (ret != SUCCESS)
{
// Cannot change to specified directory
if (filename != 0) delete[] filen
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -