void Scene::save(stream::OutputStream<stream::SerializationEndian> &strm) const { PROFILE; strm.write(ENGINE_VERSION_MAJOR); strm.write(ENGINE_VERSION_MINOR); strm.write(ENGINE_VERSION_PATCH); strm.write(entities.size()); for (unsigned i = 0; i < entities.size(); ++i) { entities[i]->save(strm); } }
/** Continuous decompression process. Not all compressor support this (in that case, it's probably emulated or might return false). @param outStream The output stream to write to. @param inStream The input stream to read from. @param amountToProcess The number of decompressed bytes to reach. Set to 0 to process the whole stream. @return true on success, false if not supported or an error occurred on the input stream */ bool BSCLib::decompressStream(Stream::OutputStream & outStream, const Stream::InputStream & inStream, const uint32 amountToProcess) { // We need to first read the number of blocks if (!memBuffer || !outBuffer) return setError(NotEnoughMemory); const size_t minBlockHeaderSize = (sizeof(dataSize) + sizeof(decHeader.recordSize) + sizeof(decHeader.sortingContext) + BSC::HeaderSize); if (memBuffer->total <= outBuffer->total) { // If we were compressing, let's enlarge that resizeBuffer(minBlockHeaderSize); decHeader.curBlock = 0; } uint32 nBlocks = (uint32)dataSize; #define POP(X, S) if (inStream.read(X, (uint64)S) != (uint64)S) return setError(Success); // No more data to read if (dataSize <= 0) { POP(&nBlocks, sizeof(nBlocks)); dataSize = nBlocks; // Crude off estimation memBuffer->empty(); } if (!nBlocks) return setError(BadFormat); // Check if we have enough data in our memory block to answer directly uint64 outSize = amountToProcess ? min((uint64)amountToProcess, outStream.fullSize()) : outStream.fullSize(); if (outSize > 0xFFFFFFFF) outSize = 0xFFFFFFFF; // We can only deal with 4GB at a time // If we reach here, we have not enough data in the memory block (we need to refill it), int64 inPos = 0; do { // Check if we have a valid header if (!decHeader.valid && decHeader.curBlock < nBlocks) { if (memBuffer->available() < minBlockHeaderSize && (memBuffer->refill(inStream, minBlockHeaderSize - memBuffer->available()) == (size_t)-1 || memBuffer->available() < minBlockHeaderSize)) return setError(UnexpectedEOD); // The decode the header #define POPM(X, S) memcpy(X, *memBuffer, S); memBuffer->use(S); #ifndef BreakCompatibility POPM(&inPos, sizeof(inPos)); POPM(&decHeader.recordSize, sizeof(decHeader.recordSize)); POPM(&decHeader.sortingContext, sizeof(decHeader.sortingContext)); #endif // Unsupported features ? if (decHeader.recordSize < 1 || decHeader.sortingContext < 1 || decHeader.sortingContext > 2) return setError(BadFormat); // Figure out the block informations if (opaque->getBlockInfo(*memBuffer, BSC::HeaderSize, decHeader.blockSize, decHeader.dataSize) != BSC::Success) return setError(BadFormat); //memBuffer->empty(); decHeader.valid = true; } // Check if we have decompressed data ready for output stream direct write if (outBuffer->available()) { // Data is ready in the buffer, let's extract it size_t doneSize = min(outBuffer->available(), (size_t)outSize); if (outStream.write(*outBuffer, doneSize) != (uint64)doneSize) return setError(UnexpectedEOD); outBuffer->use(doneSize); if (doneSize == outSize) break; // Success outSize -= doneSize; // If we reach here, then the outBuffer is empty anyway, let's mark as is outBuffer->empty(); // Need to refill a header now continue; } // We need to fetch a complete buffer from the input stream size_t need = decHeader.blockSize - memBuffer->available(); if (memBuffer->refill(inStream, need) != need) { // Could not read enough from the input stream to fill a block. // Let's output the amount we succeed to write from it. if (amountToProcess - outSize > 0) return setError(Success); return setError(UnexpectedEOD); } if (decHeader.dataSize != 0 && decHeader.curBlock < dataSize) { // Now decompress the cruft BSC::Error err = opaque->decompress(*memBuffer, decHeader.blockSize, *outBuffer, decHeader.dataSize); if (err != BSC::Success) return err == BSC::NotEnoughMemory ? setError(NotEnoughMemory) : setError(DataCorrupt); // Depending on the sorting context, we might need to reverse the blocks err = opaque->postProcess(*outBuffer, decHeader.dataSize, decHeader.sortingContext, decHeader.recordSize); if (err != BSC::Success) return err == BSC::NotEnoughMemory ? setError(NotEnoughMemory) : setError(DataCorrupt); outBuffer->setFill(decHeader.dataSize); memBuffer->empty(); // Done with this data buffer decHeader.valid = false; // The block header is now invalid too decHeader.curBlock++; } else break; // No more data to decompress } while (true); #undef POP // Check if we've finished sending the complete decompressed input stream if (decHeader.curBlock == dataSize && outBuffer->available() == 0) { // We can reset the decompression stream if it needs to be re-used decHeader.curBlock = 0; dataSize = 0; } if (outBuffer->available() == 0) outBuffer->empty(); return setError(Success); }
void Handle::save(stream::OutputStream<stream::SerializationEndian> &strm) const { strm.write(id); }