Example #1
0
	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);
		}
	}
Example #2
0
    /** 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);
    }
Example #3
0
    bool BSCLib::compressStream(Stream::OutputStream & outStream, const Stream::InputStream & inStream, const uint32 amountToProcess, const bool lastCall)
    {
        if (!memBuffer || !outBuffer) return setError(NotEnoughMemory);
        // If we were decompressing, let's change that
        if (decHeader.valid) { resizeBuffer(); decHeader.valid = false; }
        // Detect end of buffer
        // Try to be smart, else try to read as much as possible
        uint64 inSize = amountToProcess ? min((uint64)amountToProcess, inStream.fullSize()) : inStream.fullSize();
        if (inSize == 0)
        {
            if (!dataSize && !memBuffer->available()) return true;
            // Need to process the remaining block, if any
            if (!processBlock(outStream)) return false;
            // End of stream, let's rewind and write the header
            if (outStream.setPosition(0))
            {
                uint32 nBlocks = (uint32)((dataSize + getBufferSize() - 1) / getBufferSize());
                PUSH(&nBlocks, sizeof(nBlocks));
                dataSize = 0;
                headerWritten = false;
            }
            return true;
        }

        // Check if we need to write the number of blocks now (or not)
        if (!headerWritten)
        {
            // Safety first
            if (dataSize == 0 && !outStream.setPosition(outStream.currentPosition()))
            {
                // If you don't provide the input size and the output stream can not be rewind to save
                // the header in the end, then it'll not work.
                Assert(dataSize == 0 && outStream.setPosition(outStream.currentPosition()));
                return false;
            }

            uint32 nBlocks = (uint32)((-dataSize + getBufferSize() - 1) / getBufferSize()); //blockSize > 0 ? (uint32)((inSize + blockSize - 1) / blockSize) : 0;
            PUSH(&nBlocks, sizeof(nBlocks));
            dataSize = 0;
            headerWritten = true;
        }

        // Check if we can cache the data to avoid small compression block
        if (!lastCall && memBuffer->canFit(inSize))
        {   // Accumulate the input stream
            return memBuffer->refill(inStream, inSize) == inSize;
        }

        while ((int64)inSize > 0)
        {
            // Read as much as possible to the memory buffer, and save that
            size_t readSize = memBuffer->available();
            if (!memBuffer->full())
            {
                readSize = memBuffer->refill(inStream, inSize);
                inSize -= (uint64)readSize;
            }
            if (memBuffer->available() >= getBufferSize() || lastCall)
            {
                if (!processBlock(outStream)) return false;
            }
        }
        return setError(Success);
    }
Example #4
0
	void Handle::save(stream::OutputStream<stream::SerializationEndian> &strm) const
	{
		strm.write(id);
	}