Files
DocumentServer-v-9.2.0/core/Common/cfcpp/directoryentry.cpp
Yajbir Singh f1b860b25c
Some checks failed
check / markdownlint (push) Has been cancelled
check / spellchecker (push) Has been cancelled
updated
2025-12-11 19:03:17 +05:30

369 lines
10 KiB
C++

/*
* (c) Copyright Ascensio System SIA 2010-2023
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
* street, Riga, Latvia, EU, LV-1050.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
#include "directoryentry.h"
#include <sstream>
#include "cfexception.h"
#include "streamrw.h"
#include <stdexcept>
#include <ctime>
using namespace CFCPP;
DirectoryEntry::DirectoryEntry(std::wstring name, StgType stgType, SVector<IDirectoryEntry> &dirRepository) :
dirRepository(dirRepository)
{
this->stgType = stgType;
if (stgType == StgType::StgStorage)
{
creationDate = 10000000ULL * std::time(NULL) + 116444736000000000ULL;
startSetc = ZERO;
}
if (stgType == StgType::StgInvalid)
{
startSetc = ZERO;
}
if (name.size())
{
DirectoryEntry::SetEntryName(name);
}
}
DirectoryEntry::DirectoryEntry(std::wstring name, StgType stgType) :
dirRepository(emptyDir)
{
this->stgType = stgType;
if (stgType == StgType::StgStorage)
{
// file timestamp
creationDate = 10000000ULL * std::time(NULL) + 116444736000000000ULL;
startSetc = ZERO;
}
if (stgType == StgType::StgInvalid)
{
startSetc = ZERO;
}
if (name.size())
{
DirectoryEntry::SetEntryName(name);
}
}
_INT32 DirectoryEntry::getSid() const
{
return sid;
}
void DirectoryEntry::setSid(_INT32 newSid)
{
sid = newSid;
}
std::wstring DirectoryEntry::GetEntryName() const
{
if (entryName[0] != '\0' && nameLength > 0)
{
wchar_t name[32];
for (_INT32 i = 0; i < 32; i++)
{
name[i] = entryName[2*i] + (entryName[2*i+1] << 8);
}
return std::wstring (name, name + nameLength/2 - 1);
}
else
return L"";
}
void DirectoryEntry::SetEntryName(const std::wstring &entryName)
{
if (entryName.empty())
{
std::fill(this->entryName, this->entryName+64, '\0');
this->nameLength = 0;
}
else
{
if (
entryName.find(L"\\") != std::wstring::npos ||
entryName.find(L"/") != std::wstring::npos ||
entryName.find(L":") != std::wstring::npos ||
entryName.find(L"!") != std::wstring::npos
) throw CFException("Invalid character in entry: the characters '\\', '/', ':','!' cannot be used in entry name");
if (entryName.length() > 31)
throw CFException("Entry name MUST NOT exceed 31 characters");
std::fill(this->entryName, this->entryName + 64, 0);
for (size_t i = 0; i < entryName.size(); i++)
{
wchar_t sym = entryName[i];
this->entryName[i*2+0] = sym % 256;
this->entryName[i*2+1] = sym / 256;
}
this->nameLength = (_UINT16)entryName.size() * 2 + 2;
}
}
_INT32 DirectoryEntry::GetHashCode() const
{
return (int)fnv_hash(entryName, nameLength);
}
void DirectoryEntry::Write(Stream stream) const
{
StreamRW rw(stream);
rw.WriteArray(entryName, sizeof (entryName));
rw.Write(nameLength);
rw.Write((BYTE)stgType);
rw.Write((BYTE)stgColor);
rw.Write(leftSibling);
rw.Write(rightSibling);
rw.Write(child);
rw.WriteArray(reinterpret_cast<const char*>(&storageCLSID), sizeof (storageCLSID));
rw.Write(stateBits);
rw.WriteArray(reinterpret_cast<const char*>(&creationDate), sizeof (creationDate));
rw.WriteArray(reinterpret_cast<const char*>(&modifyDate), sizeof (modifyDate));
rw.Write(startSetc);
rw.Write(size);
rw.Close();
}
void DirectoryEntry::Read(Stream stream, CFSVersion ver)
{
StreamRW rw(stream);
rw.ReadArray(entryName, 64);
nameLength = rw.Read<decltype(nameLength)>();
stgType = (StgType)rw.Read<BYTE>();
stgColor = (StgColor)rw.Read<BYTE>();
leftSibling = rw.Read<decltype(leftSibling)>();
rightSibling = rw.Read<decltype(rightSibling)>();
child = rw.Read<decltype(child)>();
if (stgType == StgType::StgInvalid)
{
leftSibling = NOSTREAM;
rightSibling = NOSTREAM;
child = NOSTREAM;
}
rw.ReadArray(reinterpret_cast<char*>(&storageCLSID), 16);
stateBits = rw.Read<decltype (stateBits)>();
rw.ReadArray(reinterpret_cast<char*>(&creationDate), 8);
rw.ReadArray(reinterpret_cast<char*>(&modifyDate), 8);
startSetc = rw.Read<decltype (startSetc)>();
if (ver == CFSVersion::Ver_3)
{
size = rw.Read<_INT32> ();
rw.Read<_INT32>();
}
else
{
size = rw.Read<decltype (size)>();
}
}
std::wstring DirectoryEntry::ToString() const
{
std::wstringstream wss;
wss << Name() << L" [" << sid << L"]" << (stgType == StgType::StgStream ? L"Stream" : L"Storage");
return wss.str();
}
RedBlackTree::PIRBNode DirectoryEntry::getLeft() const
{
if (leftSibling == NOSTREAM)
return {};
return dirRepository[leftSibling];
}
RedBlackTree::PIRBNode DirectoryEntry::getRight() const
{
if (rightSibling == DirectoryEntry::NOSTREAM)
return {};
return dirRepository[rightSibling];
}
void DirectoryEntry::setLeft(RedBlackTree::PIRBNode pNode)
{
leftSibling = pNode != nullptr ? std::static_pointer_cast<IDirectoryEntry>(pNode)->getSid() : DirectoryEntry::NOSTREAM;
if (leftSibling != DirectoryEntry::NOSTREAM)
dirRepository[leftSibling]->setParent(shared_from_this());
}
void DirectoryEntry::setRight(RedBlackTree::PIRBNode pNode)
{
rightSibling = pNode != nullptr ? std::static_pointer_cast<IDirectoryEntry>(pNode)->getSid() : DirectoryEntry::NOSTREAM;
if (rightSibling != DirectoryEntry::NOSTREAM)
dirRepository[rightSibling]->setParent(shared_from_this());
}
RedBlackTree::PIRBNode DirectoryEntry::Sibling() const
{
if (shared_from_this() == getParent()->getLeft())
return getParent()->getRight();
else
return getParent()->getLeft();
}
RedBlackTree::PIRBNode DirectoryEntry::Uncle() const
{
return parent.use_count() != 0 ? getParent()->Sibling() : RedBlackTree::PIRBNode();
}
void DirectoryEntry::AssignValueTo(RedBlackTree::PIRBNode other)
{
auto d = std::dynamic_pointer_cast<DirectoryEntry>(other);
if (d == nullptr)
return;
d->SetEntryName(this->GetEntryName());
d->creationDate = creationDate;
d->modifyDate = modifyDate;
d->size = this->size;
d->startSetc = this->startSetc;
d->stateBits = this->stateBits;
d->stgType = this->stgType;
d->storageCLSID = this->storageCLSID;
d->child = this->child;
}
_INT32 DirectoryEntry::CompareTo(const RedBlackTree::PIRBNode &other) const
{
IDirectoryEntry* otherDir = dynamic_cast<IDirectoryEntry*>(other.get());
if (otherDir == nullptr)
throw CFException("Invalid casting: compared object does not implement IDirectorEntry interface");
if (this->getNameLength() > otherDir->getNameLength())
{
return THIS_IS_GREATER;
}
else if (this->getNameLength() < otherDir->getNameLength())
{
return OTHER_IS_GREATER;
}
else
{
std::wstring thisName = GetEntryName();
std::wstring otherName = otherDir->GetEntryName();
for (_INT32 z = 0; z < (int)thisName.size(); z++)
{
char thisChar = toupper(thisName[z]);
char otherChar = toupper(otherName[z]);
if (thisChar > otherChar)
return THIS_IS_GREATER;
else if (thisChar < otherChar)
return OTHER_IS_GREATER;
}
return 0;
}
}
_UINT64 DirectoryEntry::fnv_hash(const char *buffer, _INT64 lenght)
{
_UINT64 h = 2166136261;
_INT64 i;
for (i = 0; i < lenght; i++)
h = (h * 16777619) ^ buffer[i];
return h;
}
std::shared_ptr<IDirectoryEntry> DirectoryEntry::New(std::wstring name, StgType stgType, SVector<IDirectoryEntry>& dirRepository)
{
std::shared_ptr<IDirectoryEntry> de;
if (dirRepository)
{
de.reset(new DirectoryEntry(name, stgType, dirRepository));
dirRepository.push_back(de);
de->setSid(dirRepository.size() - 1);
}
else
throw std::invalid_argument("dirRepository Directory repository cannot be null in New() method");
return de;
}
std::shared_ptr<IDirectoryEntry> DirectoryEntry::TryNew(std::wstring name, StgType stgType, SVector<IDirectoryEntry>& dirRepository)
{
std::shared_ptr<DirectoryEntry> de(new DirectoryEntry(name, stgType, dirRepository));
if (de != nullptr)
{
for (_INT32 i = 0; i < (int)dirRepository.size(); i++)
{
if (dirRepository[i]->getStgType() == StgType::StgInvalid)
{
dirRepository[i] = de;
de->sid = i;
return de;
}
}
}
dirRepository.push_back(de);
de->sid = dirRepository.size() - 1;
return de;
}
std::shared_ptr<IDirectoryEntry> DirectoryEntry::Mock(std::wstring name, StgType stgType)
{
auto de = std::shared_ptr<IDirectoryEntry>(new DirectoryEntry(name, stgType));
return de;
}