size_t DiskCachingFileLoaderCache::SaveIntoCache(FileLoader *backend, s64 pos, size_t bytes, void *data, FileLoader::Flags flags) { lock_guard guard(lock_); if (!f_) { // Just to keep things working. return backend->ReadAt(pos, bytes, data, flags); } s64 cacheStartPos = pos / blockSize_; s64 cacheEndPos = (pos + bytes - 1) / blockSize_; size_t readSize = 0; size_t offset = (size_t)(pos - (cacheStartPos * (u64)blockSize_)); u8 *p = (u8 *)data; size_t blocksToRead = 0; for (s64 i = cacheStartPos; i <= cacheEndPos; ++i) { auto &info = index_[i]; if (info.block != INVALID_BLOCK) { break; } ++blocksToRead; if (blocksToRead >= MAX_BLOCKS_PER_READ) { break; } } if (!MakeCacheSpaceFor(blocksToRead) || blocksToRead == 0) { return 0; } if (blocksToRead == 1) { auto &info = index_[cacheStartPos]; u8 *buf = new u8[blockSize_]; size_t readBytes = backend->ReadAt(cacheStartPos * (u64)blockSize_, blockSize_, buf, flags); // Check if it was written while we were busy. Might happen if we thread. if (info.block == INVALID_BLOCK && readBytes != 0) { info.block = AllocateBlock((u32)cacheStartPos); WriteBlockData(info, buf); WriteIndexData((u32)cacheStartPos, info); } size_t toRead = std::min(bytes - readSize, (size_t)blockSize_ - offset); memcpy(p + readSize, buf + offset, toRead); readSize += toRead; delete [] buf; } else { u8 *wholeRead = new u8[blocksToRead * blockSize_]; size_t readBytes = backend->ReadAt(cacheStartPos * (u64)blockSize_, blocksToRead * blockSize_, wholeRead, flags); for (size_t i = 0; i < blocksToRead; ++i) { auto &info = index_[cacheStartPos + i]; // Check if it was written while we were busy. Might happen if we thread. if (info.block == INVALID_BLOCK && readBytes != 0) { info.block = AllocateBlock((u32)cacheStartPos + (u32)i); WriteBlockData(info, wholeRead + (i * blockSize_)); // TODO: Doing each index together would probably be better. WriteIndexData((u32)cacheStartPos + (u32)i, info); } size_t toRead = std::min(bytes - readSize, (size_t)blockSize_ - offset); memcpy(p + readSize, wholeRead + (i * blockSize_) + offset, toRead); readSize += toRead; } delete[] wholeRead; } cacheSize_ += blocksToRead; ++generation_; if (generation_ == std::numeric_limits<u16>::max()) { RebalanceGenerations(); } return readSize; }
HRESULT CCoder::CodeReal(ISequentialInStream *anInStream, ISequentialOutStream *anOutStream, const UINT64 *anInSize) { if (!m_Created) { RETURN_IF_NOT_S_OK(Create()); m_Created = true; } UINT64 aNowPos = 0; m_FinderPos = 0; RETURN_IF_NOT_S_OK(m_MatchFinder.Init(anInStream)); m_OutStream.Init(anOutStream); m_ReverseOutStream.Init(&m_OutStream); InitStructures(); while(true) { int aCurrentPassIndex = 0; bool aNoMoreBytes; while (true) { while(true) { aNoMoreBytes = (m_AdditionalOffset == 0 && m_MatchFinder.GetNumAvailableBytes() == 0); if (((m_CurrentBlockUncompressedSize >= kBlockUncompressedSizeThreshold || m_ValueIndex >= kValueBlockSize) && (m_OptimumEndIndex == m_OptimumCurrentIndex)) || aNoMoreBytes) break; UINT32 aPos; UINT32 aLen = GetOptimal(aPos); if (aLen >= kMatchMinLen) { UINT32 aNewLen = aLen - kMatchMinLen; m_Values[m_ValueIndex].Flag = kFlagLenPos; m_Values[m_ValueIndex].Len = BYTE(aNewLen); UINT32 aLenSlot = g_LenSlots[aNewLen]; m_MainCoder.AddSymbol(kMatchNumber + aLenSlot); m_Values[m_ValueIndex].Pos = UINT16(aPos); UINT32 aPosSlot = GetPosSlot(aPos); m_DistCoder.AddSymbol(aPosSlot); } else if (aLen == 1) { BYTE aByte = m_MatchFinder.GetIndexByte(0 - m_AdditionalOffset); aLen = 1; m_MainCoder.AddSymbol(aByte); m_Values[m_ValueIndex].Flag = kFlagImm; m_Values[m_ValueIndex].Imm = aByte; } else throw E_INTERNAL_ERROR; m_ValueIndex++; m_AdditionalOffset -= aLen; aNowPos += aLen; m_CurrentBlockUncompressedSize += aLen; } aCurrentPassIndex++; bool aWriteMode = (aCurrentPassIndex == m_NumPasses); WriteBlockData(aWriteMode, aNoMoreBytes); if (aWriteMode) break; aNowPos = m_BlockStartPostion; m_AdditionalOffset = UINT32(m_FinderPos - m_BlockStartPostion); m_CurrentBlockUncompressedSize = 0; } m_BlockStartPostion += m_CurrentBlockUncompressedSize; m_CurrentBlockUncompressedSize = 0; if (aNoMoreBytes) break; } return m_OutStream.Flush(); }