mirror of
https://github.com/Huntereb/Awoo-Installer
synced 2024-11-29 23:20:18 +00:00
192 lines
No EOL
6.8 KiB
C++
Executable file
192 lines
No EOL
6.8 KiB
C++
Executable file
#include "data/buffered_placeholder_writer.hpp"
|
|
|
|
#include <climits>
|
|
#include <math.h>
|
|
#include <algorithm>
|
|
#include <exception>
|
|
#include "error.hpp"
|
|
#include "debug.h"
|
|
|
|
namespace tin::data
|
|
{
|
|
BufferedPlaceholderWriter::BufferedPlaceholderWriter(nx::ncm::ContentStorage* contentStorage, NcmNcaId ncaId, size_t totalDataSize) :
|
|
m_totalDataSize(totalDataSize), m_contentStorage(contentStorage), m_ncaId(ncaId)
|
|
{
|
|
// Though currently the number of segments is fixed, we want them allocated on the heap, not the stack
|
|
m_bufferSegments = std::make_unique<BufferSegment[]>(NUM_BUFFER_SEGMENTS);
|
|
|
|
if (m_bufferSegments == nullptr)
|
|
THROW_FORMAT("Failed to allocated buffer segments!\n");
|
|
|
|
m_currentFreeSegmentPtr = &m_bufferSegments[m_currentFreeSegment];
|
|
m_currentSegmentToWritePtr = &m_bufferSegments[m_currentSegmentToWrite];
|
|
}
|
|
|
|
void BufferedPlaceholderWriter::AppendData(void* source, size_t length)
|
|
{
|
|
if (m_sizeBuffered + length > m_totalDataSize)
|
|
THROW_FORMAT("Cannot append data as it would exceed the expected total.\n");
|
|
|
|
size_t dataSizeRemaining = length;
|
|
u64 sourceOffset = 0;
|
|
|
|
while (dataSizeRemaining > 0)
|
|
{
|
|
size_t bufferSegmentSizeRemaining = BUFFER_SEGMENT_DATA_SIZE - m_currentFreeSegmentPtr->writeOffset;
|
|
|
|
if (m_currentFreeSegmentPtr->isFinalized)
|
|
THROW_FORMAT("Current buffer segment is already finalized!\n");
|
|
|
|
if (dataSizeRemaining < bufferSegmentSizeRemaining)
|
|
{
|
|
memcpy(m_currentFreeSegmentPtr->data + m_currentFreeSegmentPtr->writeOffset, (u8*)source + sourceOffset, dataSizeRemaining);
|
|
sourceOffset += dataSizeRemaining;
|
|
m_currentFreeSegmentPtr->writeOffset += dataSizeRemaining;
|
|
dataSizeRemaining = 0;
|
|
}
|
|
else
|
|
{
|
|
memcpy(m_currentFreeSegmentPtr->data + m_currentFreeSegmentPtr->writeOffset, (u8*)source + sourceOffset, bufferSegmentSizeRemaining);
|
|
dataSizeRemaining -= bufferSegmentSizeRemaining;
|
|
sourceOffset += bufferSegmentSizeRemaining;
|
|
m_currentFreeSegmentPtr->writeOffset += bufferSegmentSizeRemaining;
|
|
m_currentFreeSegmentPtr->isFinalized = true;
|
|
|
|
m_currentFreeSegment = (m_currentFreeSegment + 1) % NUM_BUFFER_SEGMENTS;
|
|
m_currentFreeSegmentPtr = &m_bufferSegments[m_currentFreeSegment];
|
|
}
|
|
}
|
|
|
|
m_sizeBuffered += length;
|
|
|
|
if (m_sizeBuffered == m_totalDataSize)
|
|
{
|
|
m_currentFreeSegmentPtr->isFinalized = true;
|
|
}
|
|
}
|
|
|
|
bool BufferedPlaceholderWriter::CanAppendData(size_t length)
|
|
{
|
|
if (m_sizeBuffered + length > m_totalDataSize)
|
|
return false;
|
|
|
|
if (!this->IsSizeAvailable(length))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void BufferedPlaceholderWriter::WriteSegmentToPlaceholder()
|
|
{
|
|
if (m_sizeWrittenToPlaceholder >= m_totalDataSize)
|
|
THROW_FORMAT("Cannot write segment as end of data has already been reached!\n");
|
|
|
|
if (!m_currentSegmentToWritePtr->isFinalized)
|
|
THROW_FORMAT("Cannot write segment as it hasn't been finalized!\n");
|
|
|
|
// NOTE: The final segment will have leftover data from previous writes, however
|
|
// this will be accounted for by this size
|
|
size_t sizeToWriteToPlaceholder = std::min(m_totalDataSize - m_sizeWrittenToPlaceholder, BUFFER_SEGMENT_DATA_SIZE);
|
|
m_contentStorage->WritePlaceholder(m_ncaId, m_sizeWrittenToPlaceholder, m_currentSegmentToWritePtr->data, sizeToWriteToPlaceholder);
|
|
|
|
m_currentSegmentToWritePtr->isFinalized = false;
|
|
m_currentSegmentToWritePtr->writeOffset = 0;
|
|
m_currentSegmentToWrite = (m_currentSegmentToWrite + 1) % NUM_BUFFER_SEGMENTS;
|
|
m_currentSegmentToWritePtr = &m_bufferSegments[m_currentSegmentToWrite];
|
|
m_sizeWrittenToPlaceholder += sizeToWriteToPlaceholder;
|
|
}
|
|
|
|
bool BufferedPlaceholderWriter::CanWriteSegmentToPlaceholder()
|
|
{
|
|
if (m_sizeWrittenToPlaceholder >= m_totalDataSize)
|
|
return false;
|
|
|
|
if (!m_currentSegmentToWritePtr->isFinalized)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
u32 BufferedPlaceholderWriter::CalcNumSegmentsRequired(size_t size)
|
|
{
|
|
//printf("Size: %lu\n", size);
|
|
|
|
if (m_currentFreeSegmentPtr->isFinalized)
|
|
return INT_MAX;
|
|
|
|
size_t bufferSegmentSizeRemaining = BUFFER_SEGMENT_DATA_SIZE - m_currentFreeSegmentPtr->writeOffset;
|
|
|
|
//printf("Buffer segment size remaining: %lu\n", bufferSegmentSizeRemaining);
|
|
|
|
if (size <= bufferSegmentSizeRemaining) return 1;
|
|
else
|
|
{
|
|
double numSegmentsReq = 1 + (double)(size - bufferSegmentSizeRemaining) / (double)BUFFER_SEGMENT_DATA_SIZE;
|
|
return ceil(numSegmentsReq);
|
|
}
|
|
}
|
|
|
|
bool BufferedPlaceholderWriter::IsSizeAvailable(size_t size)
|
|
{
|
|
u32 numSegmentsRequired = this->CalcNumSegmentsRequired(size);
|
|
|
|
if (numSegmentsRequired > NUM_BUFFER_SEGMENTS)
|
|
return false;
|
|
|
|
for (unsigned int i = 0; i < numSegmentsRequired; i++)
|
|
{
|
|
unsigned int segmentIndex = m_currentFreeSegment + i;
|
|
BufferSegment* bufferSegment = &m_bufferSegments[segmentIndex % NUM_BUFFER_SEGMENTS];
|
|
|
|
if (bufferSegment->isFinalized)
|
|
return false;
|
|
|
|
if (i != 0 && bufferSegment->writeOffset != 0)
|
|
THROW_FORMAT("Unexpected non-zero write offset at segment %u (%lu)\n", segmentIndex, bufferSegment->writeOffset);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool BufferedPlaceholderWriter::IsBufferDataComplete()
|
|
{
|
|
if (m_sizeBuffered > m_totalDataSize)
|
|
THROW_FORMAT("Size buffered cannot exceed total data size!\n");
|
|
|
|
return m_sizeBuffered == m_totalDataSize;
|
|
}
|
|
|
|
bool BufferedPlaceholderWriter::IsPlaceholderComplete()
|
|
{
|
|
if (m_sizeWrittenToPlaceholder > m_totalDataSize)
|
|
THROW_FORMAT("Size written to placeholder cannot exceed total data size!\n");
|
|
|
|
return m_sizeWrittenToPlaceholder == m_totalDataSize;
|
|
}
|
|
|
|
size_t BufferedPlaceholderWriter::GetTotalDataSize()
|
|
{
|
|
return m_totalDataSize;
|
|
}
|
|
|
|
size_t BufferedPlaceholderWriter::GetSizeBuffered()
|
|
{
|
|
return m_sizeBuffered;
|
|
}
|
|
|
|
size_t BufferedPlaceholderWriter::GetSizeWrittenToPlaceholder()
|
|
{
|
|
return m_sizeWrittenToPlaceholder;
|
|
}
|
|
|
|
void BufferedPlaceholderWriter::DebugPrintBuffers()
|
|
{
|
|
printf("BufferedPlaceholderWriter Buffers: \n");
|
|
|
|
for (int i = 0; i < NUM_BUFFER_SEGMENTS; i++)
|
|
{
|
|
printf("Buffer %u:\n", i);
|
|
printBytes(nxlinkout, m_bufferSegments[i].data, BUFFER_SEGMENT_DATA_SIZE, true);
|
|
}
|
|
}
|
|
} |