Files
core/Common/cfcpp/streamview.cpp
Alexander Trofimov 76ee07f61c [copyright] Update copyright header
Co-authored-by: Alexander Trofimov <alexander.trofimov@onlyoffice.com>
Co-committed-by: Alexander Trofimov <alexander.trofimov@onlyoffice.com>
2026-05-14 08:23:56 +00:00

286 lines
7.9 KiB
C++

/*
* Copyright (C) Ascensio System SIA, 2009-2026
*
* 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, together with the
* additional terms provided in the LICENSE file.
*
* 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: https://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA by email at info@onlyoffice.com
* or by postal mail at 20A-6 Ernesta Birznieka-Upisha Street, Riga,
* LV-1050, Latvia, European Union.
*
* The interactive user interfaces in modified versions of the Program
* are required to display Appropriate Legal Notices in accordance with
* Section 5 of the GNU AGPL version 3.
*
* No trademark rights are granted under this License.
*
* All non-code elements of the Product, including illustrations,
* icon sets, and technical writing content, are licensed under the
* Creative Commons Attribution-ShareAlike 4.0 International License:
* https://creativecommons.org/licenses/by-sa/4.0/legalcode
*
* This license applies only to such non-code elements and does not
* modify or replace the licensing terms applicable to the Program's
* source code, which remains licensed under the GNU Affero General
* Public License v3.
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
#include "streamview.h"
#include "cfexception.h"
#include <cmath>
#include <algorithm>
using namespace CFCPP;
StreamView::StreamView(const SVector<Sector> &sectorChain, _INT32 sectorSize, Stream stream)
: sectorSize(sectorSize),
sectorChain(sectorChain),
stream(stream)
{
if (sectorChain == nullptr)
throw CFException("Sector Chain cannot be null");
if (sectorSize <= 0)
throw CFException("Sector size must be greater than zero");
}
StreamView::StreamView(const SVector<Sector> &sectorChain, _INT32 sectorSize, _INT64 length,
SList<Sector> &availableSectors, Stream stream, bool isFatStream) :
StreamView(sectorChain, sectorSize, stream)
{
this->isFatStream = isFatStream;
adjustLength(length, availableSectors);
}
_INT64 StreamView::tell()
{
return position;
}
void StreamView::write(const char *buffer, _INT64 count)
{
_INT32 byteWritten = 0;
_INT32 roundByteWritten = 0;
_INT32 offset = 0;
if ((position + count) > length)
adjustLength((position + count));
if (sectorChain.empty() == false)
{
_INT32 sectorOffset = (int)(position / (_INT64)sectorSize);
_INT32 sectorShift = (int)(position % sectorSize);
roundByteWritten = (int)(std::min)((_INT64)sectorSize - (position % (_INT64)sectorSize), count);
if (sectorOffset < (int)sectorChain.size())
{
char* dst = reinterpret_cast<char*>(sectorChain[sectorOffset]->GetData().data());
std::copy(buffer+offset, buffer+offset+roundByteWritten, dst + sectorShift);
sectorChain[sectorOffset]->dirtyFlag = true;
}
byteWritten += roundByteWritten;
offset += roundByteWritten;
sectorOffset++;
while (byteWritten < (count - sectorSize))
{
roundByteWritten = sectorSize;
char* dst = reinterpret_cast<char*>(sectorChain[sectorOffset]->GetData().data());
std::copy(buffer+offset, buffer+offset+roundByteWritten, dst);
sectorChain[sectorOffset]->dirtyFlag = true;
byteWritten += roundByteWritten;
offset += roundByteWritten;
sectorOffset++;
}
roundByteWritten = count - byteWritten;
if (roundByteWritten != 0)
{
char* dst = reinterpret_cast<char*>(sectorChain[sectorOffset]->GetData().data());
std::copy(buffer+offset, buffer+offset+roundByteWritten, dst);
sectorChain[sectorOffset]->dirtyFlag = true;
}
position += count;
}
}
void StreamView::close()
{
if (std::dynamic_pointer_cast<std::iostream>(stream) != nullptr)
stream->close();
}
bool StreamView::isError()
{
if (std::dynamic_pointer_cast<std::iostream>(stream) == nullptr) return true;
if ((std::dynamic_pointer_cast<std::iostream>(stream))->bad()) return true;
if ((std::dynamic_pointer_cast<std::iostream>(stream))->fail()) return true;
return false;
}
_INT64 StreamView::read(char *buffer, _INT64 len)
{
_INT32 nRead = 0;
_INT32 nToRead = 0;
_INT32 offset = 0;
if (sectorChain.empty() == false && sectorChain.size() > 0)
{
_INT32 sectorIndex = (int)(position / (_INT64)sectorSize);
nToRead = (std::min)((_INT64)sectorChain[0]->GetData().size() - ((_INT64)position % sectorSize), len);
if (sectorIndex < (int)sectorChain.size())
{
char* src = reinterpret_cast<char*>(sectorChain[sectorIndex]->GetData().data() + (int)(position % sectorSize));
char* dst = buffer + offset;
std::copy(src, src + nToRead, dst);
}
nRead += nToRead;
sectorIndex++;
while (nRead < (len - sectorSize))
{
nToRead = sectorSize;
char* src = reinterpret_cast<char*>(sectorChain[sectorIndex]->GetData().data());
char* dst = buffer + offset + nToRead;
std::copy(src, src + nToRead, dst);
nRead += nToRead;
sectorIndex++;
}
nToRead = len - nRead;
if (nToRead != 0)
{
if (sectorIndex > (int)sectorChain.size()) throw CFCorruptedFileException("The file is probably corrupted.");
char* src = reinterpret_cast<char*>(sectorChain[sectorIndex]->GetData().data());
char* dst = buffer + offset + nRead;
std::copy(src, src + nToRead, dst);
nRead += nToRead;
}
position += nRead;
return nRead;
}
return 0;
}
_INT64 StreamView::seek(_INT64 offset, std::ios_base::seekdir mode)
{
switch (mode)
{
case std::ios_base::beg:
position = offset;
break;
case std::ios_base::cur:
position += offset;
break;
case std::ios_base::end:
default:
position = length - offset;
}
adjustLength(position);
return position;
}
void StreamView::SetLength(_INT64 value)
{
adjustLength(value);
}
_INT32 StreamView::ReadInt32()
{
read(reinterpret_cast<char*>(&buf), 4);
return buf;
}
void StreamView::WriteInt32(_INT32 val)
{
buf = ((val & 0xFF) << 24) | ((val & 0x00FF) << 16) | ((val & 0x0000FF) << 8) | (val & 0x000000FF);
write(reinterpret_cast<char*>(&buf), 4);
}
void StreamView::adjustLength(_INT64 value)
{
SList<Sector> q;
adjustLength(value, q);
}
void StreamView::adjustLength(_INT64 value, SList<Sector> &availableSectors)
{
this->length = value;
_INT64 delta = value - ((_INT64)this->sectorChain.size() * (_INT64)sectorSize);
if (delta > 0)
{
_INT32 numberSector = (int)std::ceil(((double)delta / sectorSize));
while (numberSector > 0)
{
std::shared_ptr<Sector> newSector;
if (availableSectors.empty() || availableSectors.size() == 0)
{
newSector.reset(new Sector(sectorSize, stream));
if (sectorSize == Sector::MINISECTOR_SIZE)
newSector->type = SectorType::Mini;
}
else
{
newSector = availableSectors.dequeue();
}
if (isFatStream)
{
newSector->InitFATData();
}
sectorChain.push_back(newSector);
numberSector--;
}
}
}
_INT64 StreamView::getPosition() const
{
return position;
}
_INT64 StreamView::getLength() const
{
return length;
}
SVector<Sector> &StreamView::BaseSectorChain()
{
return sectorChain;
}