/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuBaseStream.cpp Date: 2022-2-14 Author: Reece ***/ #include #include "AuCompression.hpp" #include "AuIngestableReadBase.hpp" #include "AuBaseStream.hpp" // now required for *.inl #include "AuIngestableReadBase.inl" #include "AuBaseStream.hpp" #if defined(AURORA_COMPILER_CLANG) // warning: non-void function does not return a value in all control paths [-Wreturn-type] #pragma clang diagnostic ignored "-Wreturn-type" // one of my no returns is broken :( #endif namespace Aurora::Compression { AuStreamReadWrittenPair_t BaseStream::ReadEx(const AuMemoryViewWrite &/*optional/nullable*/destination, bool bIngestUntilEOS) { AU_LOCK_GUARD(this->_spinlock); AuUInt32 dwRead {}, dwBytesWritten {}; if (!destination.length && !destination.ptr) { return {0, this->pOutputBuffer_->RemainingBytes()}; } if (bIngestUntilEOS) { while (this->pOutputBuffer_->RemainingBytes() < destination.length) { auto toRead = destination.length ? AuUInt32(destination.length - this->pOutputBuffer_->RemainingBytes()) : 10 * 1024; // TODO: I was trying to get out of stream memory to explode less with real code. bIngestUntilEOS users are usually lazy decompressors // This was just to give a chance to yield, because theres no API to process after end of write condition; we always ended up failing. // ... // I think this rate limiter can be removed. Something else was the primary factor. toRead = AuMin(toRead, 1024 * 10); auto realPair = Ingest_s(toRead); dwRead += realPair.first; if (realPair.second == 0) { //if (!this->pOutputBuffer_->RemainingBytes(true)) //{ // return {}; //} break; } } } dwBytesWritten = this->pOutputBuffer_->Read(destination.ptr, destination.length, destination.ptr == nullptr); return { dwRead, dwBytesWritten }; } AuUInt32 BaseStream::GetAvailableProcessedBytes() { AU_LOCK_GUARD(this->_spinlock); return this->pOutputBuffer_->RemainingBytes(true); } AuUInt32 BaseStream::Read(const AuMemoryViewWrite & /*opt*/ destination) { AU_LOCK_GUARD(this->_spinlock); if (!destination.length && !destination.ptr) { return this->pOutputBuffer_->RemainingBytes(); } return this->pOutputBuffer_->Read(destination.ptr, destination.length, destination.ptr == nullptr); } bool BaseStream::GoBackByProcessedN(AuUInt32 dwOffset) { AU_LOCK_GUARD(this->_spinlock); return this->pOutputBuffer_->ReaderTryGoBack(dwOffset); } bool BaseStream::GoForwardByProcessedN(AuUInt32 dwOffset) { AU_LOCK_GUARD(this->_spinlock); if (!dwOffset) { return true; } return this->pOutputBuffer_->ReaderTryGoForward(dwOffset); } AuStreamReadWrittenPair_t BaseStream::Ingest(AuUInt32 dwBytesFromUnprocessedInputSource) { AU_LOCK_GUARD(this->_spinlock); if (!dwBytesFromUnprocessedInputSource) { return {}; } return Ingest_s(dwBytesFromUnprocessedInputSource); } bool BaseStream::IsValid() { return this->uBufferSize_ ? (this->pOutputBuffer_ && this->pOutputBuffer_->IsValid()) : true; } AuSPtr BaseStream::GetBuffer() { return this->pOutputBuffer_; } void BaseStream::SetBuffer(const AuSPtr &pBuffer) { if (!pBuffer) { this->pOutputBuffer_ = AuUnsafeRaiiToShared(&this->_outbufferOwned); } else { this->pOutputBuffer_ = pBuffer; } } AuSPtr BaseStream::GetWeakBuffer() { return AuTryLockMemoryType(this->wpInBuffer_); } void BaseStream::SetWeakBuffer(const AuSPtr &pBuffer) { this->wpInBuffer_ = pBuffer; } void BaseStream::InitByDesc(CompressInfo &info) { } void BaseStream::InitByDesc(DecompressInfo &info) { } bool BaseStream::Write(const void *pDest, AuUInt32 dwLength) { if (this->pOutputBufferInterface_) { AuUInt uWritten {}; AuIO::WriteAll(this->pOutputBufferInterface_.get(), AuMemoryViewStreamRead(AuMemoryViewRead((char *)pDest, dwLength), uWritten)); return uWritten == dwLength; } return this->pOutputBuffer_->Write(AuReinterpretCast(pDest), dwLength) == dwLength; } bool BaseStream::Write2(const void *pDest, AuUInt32 dwLength) { if (this->pOutputBuffer_) { if (this->pOutputBuffer_->CanWrite(dwLength)) { this->pOutputBuffer_->writePtr += dwLength; return true; } SysUnreachable(); } else { return this->Write(pDest, dwLength) == dwLength; } } AuPair BaseStream::GetDOutPair() { if (this->pOutputBuffer_) { auto view = this->pOutputBuffer_->GetNextLinearWrite(); return AuMakePair((char *)view.ptr, view.length); } else { return AuMakePair((char *)this->internalOutBuffer_, this->internalOutLength_); } } AuUInt32 BaseStream::GetInternalBufferSize() { return this->pOutputBuffer_->allocSize; } AuOptional BaseStream::GetLastError() { return this->optLastError_; } AuOptional BaseStream::GetLastErrorString() { return this->optLastErrorString_; } void BaseStream::SetLastError(int i, const AuString &str) { this->optLastError_ = i; this->optLastErrorString_ = str; SysPushErrorMalformedData("Compression Error: {} {}", i, str); } void BaseStream::SetLastError(int i) { this->optLastError_ = i; SysPushErrorMalformedData("Compression Error: {}", i); } bool BaseStream::Flush() { return false; } bool BaseStream::Finish() { return false; } IO::IStreamReader *BaseStream::ToStreamReader() { return &this->reader_; } IO::ISeekingReader *BaseStream::ToSeekingStreamReader() { return &this->reader2_; } }