Files
core/Common/cfcpp/compoundfile.h

158 lines
5.7 KiB
C++

#pragma once
#include "sectorcollection.h"
#include "cfstorage.h"
#include "slist.h"
#include <unordered_set>
#include "RBTree/rbtree.h"
#include "idirectoryentry.h"
#include <mutex>
#include "header.h"
namespace CFCPP
{
class DirectoryEntry;
enum CFSConfiguration
{
Default = 1,
SectorRecycle = 2,
EraseFreeSectors = 4,
NoValidationException = 8,
LeaveOpen = 16
};
enum CFSUpdateMode
{
/// ReadOnly update mode prevents overwriting
/// of the opened file.
/// Data changes are allowed but they have to be
/// persisted on a different file when required
ReadOnly,
/// Update mode allows subsequent data changing operations
/// to be persisted directly on the opened file or stream
/// method when required. Warning: this option may cause existing data loss if misused.
Update
};
class CompoundFile
{
public:
CompoundFile(const std::wstring &fileName, CFSUpdateMode updateMode, CFSConfiguration configParameters = Default);
CompoundFile(CFSVersion cfsVersion, CFSConfiguration configFlags);
CompoundFile(const std::wstring &fileName);
CompoundFile(Stream stream);
CompoundFile();
void Commit(bool releaseMemory = false);
inline bool HasSourceStream() {return sourceStream != nullptr;}
void Close();
static std::shared_ptr<RedBlackTree::RBTree> CreateNewTree();
std::shared_ptr<RedBlackTree::RBTree> GetChildrenTree(int sid);
std::shared_ptr<CFStorage> RootStorage();
bool IsClosed()const;
SVector<IDirectoryEntry> &GetDirectories();
void ResetDirectoryEntry(int sid);
void InvalidateDirectoryEntry(int sid);
void FreeAssociatedData(int sid);
void FreeData(CFStream* stream);
void WriteData(std::shared_ptr<CFItem> cfItem, const std::vector<BYTE>& buffer, std::streamsize position, int offset, int count);
void WriteData(std::shared_ptr<CFItem> cfItem, std::streamsize position, const std::vector<BYTE>& buffer);
void WriteData(std::shared_ptr<CFItem> cfItem, const std::vector<BYTE>& buffer);
void AppendData(std::shared_ptr<CFItem> cfItem, const std::vector<BYTE>& buffer);
void SetStreamLength(std::shared_ptr<CFItem> cfItem, std::streamsize length);
SList<Sector> FindFreeSectors(SectorType sType);
std::vector<BYTE> GetData(const CFStream *cFStream);
int ReadData(CFStream* cFStream, std::streamsize position, std::vector<BYTE>& buffer, int count);
int ReadData(CFStream* cFStream, std::streamsize position, std::vector<BYTE>& buffer, int offset, int count);
std::vector<BYTE> GetDataBySID(int sid);
GUID getGuidBySID(int sid);
GUID getGuidForStream(int sid);
void Save(std::wstring wFileName);
void Save(Stream stream);
protected:
int GetSectorSize();
void Dispose(bool disposing);
private:
void CheckForLockSector();
void OnSizeLimitReached();
void LoadFile(std::wstring fileName);
void SetFileName(std::wstring fileName);
void LoadStream(Stream stream);
void Load(Stream stream);
SVector<Sector> GetFatSectorChain();
SVector<Sector> GetDifatSectorChain();
SVector<Sector> GetNormalSectorChain(int secID);
SVector<Sector> GetMiniSectorChain(int secID);
SVector<Sector> GetSectorChain(int secID, SectorType chainType);
void EnsureUniqueSectorIndex(int nextSecID, std::unordered_set<int> &processedSectors);
void CommitDirectory();
void Close(bool closeStream);
std::shared_ptr<IDirectoryEntry> RootEntry();
SVector<IDirectoryEntry> FindDirectoryEntries(std::wstring entryName);
std::shared_ptr<RedBlackTree::RBTree> DoLoadChildrenTrusted(std::shared_ptr<IDirectoryEntry> de);
void DoLoadChildren(std::shared_ptr<RedBlackTree::RBTree> bst, std::shared_ptr<IDirectoryEntry> de);
void NullifyChildNodes(std::shared_ptr<IDirectoryEntry> de);
void LoadSiblings(std::shared_ptr<RedBlackTree::RBTree> bst, std::shared_ptr<IDirectoryEntry> de);
void DoLoadSiblings(std::shared_ptr<RedBlackTree::RBTree> bst, std::shared_ptr<IDirectoryEntry> de);
bool ValidateSibling(int sid);
void LoadDirectories();
void FreeMiniChain(SVector<Sector>& sectorChain, bool zeroSector);
void FreeMiniChain(SVector<Sector>& sectorChain, int nth_sector_to_remove, bool zeroSector);
void FreeChain(SVector<Sector>& sectorChain, int nth_sector_to_remove, bool zeroSector);
void FreeChain(SVector<Sector>& sectorChain, bool zeroSector);
void AllocateSectorChain(SVector<Sector>& sectorChain);
void AllocateFATSectorChain(SVector<Sector>& sectorChain);
void AllocateDIFATSectorChain(SVector<Sector>& FATsectorChain);
void AllocateMiniSectorChain(SVector<Sector>& sectorChain);
void PersistMiniStreamToStream(const SVector<Sector>& miniSectorChain);
static int LowSaturation(int i);
void SetSectorChain(SVector<Sector> sectorChain);
CFSVersion getVersion() const;
public:
CFSConfiguration configuration = Default;
std::unique_ptr<Header> header;
Stream sourceStream;
private:
const int HEADER_DIFAT_ENTRIES_COUNT = 109;
int DIFAT_SECTOR_FAT_ENTRIES_COUNT = 127;
int FAT_SECTOR_ENTRIES_COUNT = 128;
const int SIZE_OF_SID = 4;
bool sectorRecycle = false;
bool eraseFreeSectors = false;
static constexpr int FLUSHING_QUEUE_SIZE = 6000;
static constexpr int FLUSHING_BUFFER_MAX_SIZE = 1024 * 1024 * 16;
SectorCollection sectors;
std::fstream stream;
std::string fileName;
std::shared_ptr<CFStorage> rootStorage;
bool closeStream = true;
bool _transactionLockAdded = false;
int _lockSectorId = -1;
bool _transactionLockAllocated = false;
bool validationExceptionEnabled = true;
bool _disposed = false;
CFSUpdateMode updateMode;
SVector<IDirectoryEntry> directoryEntries;
std::list<int> levelSIDs;
std::mutex lockObject;
};
}