diff options
Diffstat (limited to 'dep/g3dlite/source/BinaryOutput.cpp')
-rw-r--r-- | dep/g3dlite/source/BinaryOutput.cpp | 109 |
1 files changed, 62 insertions, 47 deletions
diff --git a/dep/g3dlite/source/BinaryOutput.cpp b/dep/g3dlite/source/BinaryOutput.cpp index 81fa9822206..b174751c8c3 100644 --- a/dep/g3dlite/source/BinaryOutput.cpp +++ b/dep/g3dlite/source/BinaryOutput.cpp @@ -2,7 +2,7 @@ @file BinaryOutput.cpp @author Morgan McGuire, http://graphics.cs.williams.edu - Copyright 2002-2010, Morgan McGuire, All rights reserved. + Copyright 2002-2011, Morgan McGuire, All rights reserved. @created 2002-02-20 @edited 2010-03-17 @@ -22,10 +22,6 @@ # include <errno.h> #endif -#ifdef __CYGWIN__ -# include <errno.h> -#endif - // Largest memory buffer that the system will use for writing to // disk. After this (or if the system runs out of memory) // chunks of the file will be dumped to disk. @@ -121,10 +117,11 @@ void BinaryOutput::reallocBuffer(size_t bytes, size_t oldBufferLen) { uint8* newBuffer = NULL; if ((m_filename == "<memory>") || (newBufferLen < MAX_BINARYOUTPUT_BUFFER_SIZE)) { - // We're either writing to memory (in which case we *have* to try and allocate) - // or we've been asked to allocate a reasonable size buffer. + // We're either writing to memory (in which case we *have* to + // try and allocate) or we've been asked to allocate a + // reasonable size buffer. - //debugPrintf(" realloc(%d)\n", newBufferLen); + // debugPrintf(" realloc(%d)\n", newBufferLen); newBuffer = (uint8*)System::realloc(m_buffer, newBufferLen); if (newBuffer != NULL) { m_maxBufferLen = newBufferLen; @@ -134,9 +131,11 @@ void BinaryOutput::reallocBuffer(size_t bytes, size_t oldBufferLen) { if ((newBuffer == NULL) && (bytes > 0)) { // Realloc failed; we're probably out of memory. Back out // the entire call and try to dump some data to disk. + alwaysAssertM(m_filename != "<memory>", "Realloc failed while writing to memory."); m_bufferLen = oldBufferLen; reserveBytesWhenOutOfMemory(bytes); } else { + // Realloc succeeded m_buffer = newBuffer; debugAssert(isValidHeapPointer(m_buffer)); } @@ -152,7 +151,7 @@ void BinaryOutput::reserveBytesWhenOutOfMemory(size_t bytes) { // Dump the contents to disk. In order to enable seeking backwards, // we keep the last 10 MB in memory. - int writeBytes = m_bufferLen - 10 * 1024 * 1024; + size_t writeBytes = m_bufferLen - 10 * 1024 * 1024; if (writeBytes < m_bufferLen / 3) { // We're going to write less than 1/3 of the file; @@ -164,11 +163,12 @@ void BinaryOutput::reserveBytesWhenOutOfMemory(size_t bytes) { //debugPrintf("Writing %d bytes to disk\n", writeBytes); const char* mode = (m_alreadyWritten > 0) ? "ab" : "wb"; + alwaysAssertM(m_filename != "<memory>", "Writing memory file"); FILE* file = FileSystem::fopen(m_filename.c_str(), mode); debugAssert(file); size_t count = fwrite(m_buffer, 1, writeBytes, file); - debugAssert((int)count == writeBytes); (void)count; + debugAssert(count == writeBytes); (void)count; fclose(file); file = NULL; @@ -181,7 +181,7 @@ void BinaryOutput::reserveBytesWhenOutOfMemory(size_t bytes) { debugAssert(m_bufferLen < m_maxBufferLen); debugAssert(m_bufferLen >= 0); debugAssert(m_pos >= 0); - debugAssert(m_pos <= m_bufferLen); + debugAssert(m_pos <= (int64)m_bufferLen); // Shift the unwritten data back appropriately in the buffer. debugAssert(isValidHeapPointer(m_buffer)); @@ -273,45 +273,49 @@ bool BinaryOutput::ok() const { } -void BinaryOutput::compress() { +void BinaryOutput::compress(int level) { if (m_alreadyWritten > 0) { throw "Cannot compress huge files (part of this file has already been written to disk)."; } + debugAssertM(! m_committed, "Cannot compress after committing."); + alwaysAssertM(m_bufferLen < 0xFFFFFFFF, "Compress only works for 32-bit files."); + + // This is the worst-case size, as mandated by zlib + unsigned long compressedSize = iCeil(m_bufferLen * 1.001) + 12; + + // Save the old buffer and reallocate to the worst-case size + const uint8* src = m_buffer; + const uint32 srcSize = (uint32)m_bufferLen; + + // add space for the 4-byte header + m_maxBufferLen = compressedSize + 4; + m_buffer = (uint8*)System::malloc(m_maxBufferLen); + + // Write the header containing the old buffer size, which is needed for decompression + { + const uint8* convert = (const uint8*)&srcSize; + if (m_swapBytes) { + m_buffer[0] = convert[3]; + m_buffer[1] = convert[2]; + m_buffer[2] = convert[1]; + m_buffer[3] = convert[0]; + } else { + m_buffer[0] = convert[0]; + m_buffer[1] = convert[1]; + m_buffer[2] = convert[2]; + m_buffer[3] = convert[3]; + } + } - // Old buffer size - int L = m_bufferLen; - uint8* convert = (uint8*)&L; - - // Zlib requires the output buffer to be this big - unsigned long newSize = iCeil(m_bufferLen * 1.01) + 12; - uint8* temp = (uint8*)System::malloc(newSize); - int result = compress2(temp, &newSize, m_buffer, m_bufferLen, 9); + // Compress and write after the header + int result = compress2(m_buffer + 4, &compressedSize, src, srcSize, iClamp(level, 0, 9)); debugAssert(result == Z_OK); (void)result; - - // Write the header - if (m_swapBytes) { - m_buffer[0] = convert[3]; - m_buffer[1] = convert[2]; - m_buffer[2] = convert[1]; - m_buffer[3] = convert[0]; - } else { - m_buffer[0] = convert[0]; - m_buffer[1] = convert[1]; - m_buffer[2] = convert[2]; - m_buffer[3] = convert[3]; - } - - // Write the data - if ((int64)newSize + 4 > (int64)m_maxBufferLen) { - m_maxBufferLen = newSize + 4; - m_buffer = (uint8*)System::realloc(m_buffer, m_maxBufferLen); - } - m_bufferLen = newSize + 4; - System::memcpy(m_buffer + 4, temp, newSize); + m_bufferLen = compressedSize + 4; m_pos = m_bufferLen; - System::free(temp); + // Free the old data + System::free((void*)src); } @@ -320,6 +324,10 @@ void BinaryOutput::commit(bool flush) { m_committed = true; debugAssertM(m_beginEndBits == 0, "Missing endBits before commit"); + if (m_filename == "<memory>") { + return; + } + // Make sure the directory exists. std::string root, base, ext, path; Array<std::string> pathArray; @@ -332,6 +340,7 @@ void BinaryOutput::commit(bool flush) { const char* mode = (m_alreadyWritten > 0) ? "ab" : "wb"; + alwaysAssertM(m_filename != "<memory>", "Writing to memory file"); FILE* file = FileSystem::fopen(m_filename.c_str(), mode); if (! file) { @@ -345,7 +354,7 @@ void BinaryOutput::commit(bool flush) { if (m_buffer != NULL) { m_alreadyWritten += m_bufferLen; - int success = fwrite(m_buffer, m_bufferLen, 1, file); + size_t success = fwrite(m_buffer, m_bufferLen, 1, file); (void)success; debugAssertM(success == 1, std::string("Could not write to '") + m_filename + "'"); } @@ -427,7 +436,7 @@ void BinaryOutput::writeUInt64(uint64 u) { void BinaryOutput::writeString(const char* s) { // +1 is because strlen doesn't count the null - int len = strlen(s) + 1; + size_t len = strlen(s) + 1; debugAssert(m_beginEndBits == 0); reserveBytes(len); @@ -438,7 +447,7 @@ void BinaryOutput::writeString(const char* s) { void BinaryOutput::writeStringEven(const char* s) { // +1 is because strlen doesn't count the null - int len = strlen(s) + 1; + size_t len = strlen(s) + 1; reserveBytes(len); System::memcpy(m_buffer + m_pos, s, len); @@ -452,8 +461,14 @@ void BinaryOutput::writeStringEven(const char* s) { void BinaryOutput::writeString32(const char* s) { - writeUInt32(strlen(s) + 1); - writeString(s); + // Write the NULL and count it + size_t len = strlen(s) + 1; + writeUInt32((uint32)len); + + debugAssert(m_beginEndBits == 0); + reserveBytes(len); + System::memcpy(m_buffer + m_pos, s, len); + m_pos += len; } |