bgfx/3rdparty/openctm/lib/stream.c
2012-10-07 20:41:18 -07:00

512 lines
16 KiB
C

//-----------------------------------------------------------------------------
// Product: OpenCTM
// File: stream.c
// Description: Stream I/O functions.
//-----------------------------------------------------------------------------
// Copyright (c) 2009-2010 Marcus Geelnard
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//-----------------------------------------------------------------------------
#include <stdlib.h>
#include <string.h>
#include <LzmaLib.h>
#include "openctm.h"
#include "internal.h"
#ifdef __DEBUG_
#include <stdio.h>
#endif
//-----------------------------------------------------------------------------
// _ctmStreamRead() - Read data from a stream.
//-----------------------------------------------------------------------------
CTMuint _ctmStreamRead(_CTMcontext * self, void * aBuf, CTMuint aCount)
{
if(!self->mUserData || !self->mReadFn)
return 0;
return self->mReadFn(aBuf, aCount, self->mUserData);
}
//-----------------------------------------------------------------------------
// _ctmStreamWrite() - Write data to a stream.
//-----------------------------------------------------------------------------
CTMuint _ctmStreamWrite(_CTMcontext * self, void * aBuf, CTMuint aCount)
{
if(!self->mUserData || !self->mWriteFn)
return 0;
return self->mWriteFn(aBuf, aCount, self->mUserData);
}
//-----------------------------------------------------------------------------
// _ctmStreamReadUINT() - Read an unsigned integer from a stream in a machine
// endian independent manner (for portability).
//-----------------------------------------------------------------------------
CTMuint _ctmStreamReadUINT(_CTMcontext * self)
{
unsigned char buf[4];
_ctmStreamRead(self, (void *) buf, 4);
return ((CTMuint) buf[0]) |
(((CTMuint) buf[1]) << 8) |
(((CTMuint) buf[2]) << 16) |
(((CTMuint) buf[3]) << 24);
}
//-----------------------------------------------------------------------------
// _ctmStreamWriteUINT() - Write an unsigned integer to a stream in a machine
// endian independent manner (for portability).
//-----------------------------------------------------------------------------
void _ctmStreamWriteUINT(_CTMcontext * self, CTMuint aValue)
{
unsigned char buf[4];
buf[0] = aValue & 0x000000ff;
buf[1] = (aValue >> 8) & 0x000000ff;
buf[2] = (aValue >> 16) & 0x000000ff;
buf[3] = (aValue >> 24) & 0x000000ff;
_ctmStreamWrite(self, (void *) buf, 4);
}
//-----------------------------------------------------------------------------
// _ctmStreamReadFLOAT() - Read a floating point value from a stream in a
// machine endian independent manner (for portability).
//-----------------------------------------------------------------------------
CTMfloat _ctmStreamReadFLOAT(_CTMcontext * self)
{
union {
CTMfloat f;
CTMuint i;
} u;
u.i = _ctmStreamReadUINT(self);
return u.f;
}
//-----------------------------------------------------------------------------
// _ctmStreamWriteFLOAT() - Write a floating point value to a stream in a
// machine endian independent manner (for portability).
//-----------------------------------------------------------------------------
void _ctmStreamWriteFLOAT(_CTMcontext * self, CTMfloat aValue)
{
union {
CTMfloat f;
CTMuint i;
} u;
u.f = aValue;
_ctmStreamWriteUINT(self, u.i);
}
//-----------------------------------------------------------------------------
// _ctmStreamReadSTRING() - Read a string value from a stream. The format of
// the string in the stream is: an unsigned integer (string length) followed by
// the string (without null termination).
//-----------------------------------------------------------------------------
void _ctmStreamReadSTRING(_CTMcontext * self, char ** aValue)
{
CTMuint len;
// Clear the old string
if(*aValue)
{
free(*aValue);
*aValue = (char *) 0;
}
// Get string length
len = _ctmStreamReadUINT(self);
// Read string
if(len > 0)
{
*aValue = (char *) malloc(len + 1);
if(*aValue)
{
_ctmStreamRead(self, (void *) *aValue, len);
(*aValue)[len] = 0;
}
}
}
//-----------------------------------------------------------------------------
// _ctmStreamWriteSTRING() - Write a string value to a stream. The format of
// the string in the stream is: an unsigned integer (string length) followed by
// the string (without null termination).
//-----------------------------------------------------------------------------
void _ctmStreamWriteSTRING(_CTMcontext * self, const char * aValue)
{
CTMuint len;
// Get string length
if(aValue)
len = strlen(aValue);
else
len = 0;
// Write string length
_ctmStreamWriteUINT(self, len);
// Write string
if(len > 0)
_ctmStreamWrite(self, (void *) aValue, len);
}
//-----------------------------------------------------------------------------
// _ctmStreamReadPackedInts() - Read an compressed binary integer data array
// from a stream, and uncompress it.
//-----------------------------------------------------------------------------
int _ctmStreamReadPackedInts(_CTMcontext * self, CTMint * aData,
CTMuint aCount, CTMuint aSize, CTMint aSignedInts)
{
size_t packedSize, unpackedSize;
CTMuint i, k, x;
CTMint value;
unsigned char * packed, * tmp;
unsigned char props[5];
int lzmaRes;
// Read packed data size from the stream
packedSize = (size_t) _ctmStreamReadUINT(self);
// Read LZMA compression props from the stream
_ctmStreamRead(self, (void *) props, 5);
// Allocate memory and read the packed data from the stream
packed = (unsigned char *) malloc(packedSize);
if(!packed)
{
self->mError = CTM_OUT_OF_MEMORY;
return CTM_FALSE;
}
_ctmStreamRead(self, (void *) packed, packedSize);
// Allocate memory for interleaved array
tmp = (unsigned char *) malloc(aCount * aSize * 4);
if(!tmp)
{
free(packed);
self->mError = CTM_OUT_OF_MEMORY;
return CTM_FALSE;
}
// Uncompress
unpackedSize = aCount * aSize * 4;
lzmaRes = LzmaUncompress(tmp, &unpackedSize, packed,
&packedSize, props, 5);
// Free the packed array
free(packed);
// Error?
if((lzmaRes != SZ_OK) || (unpackedSize != aCount * aSize * 4))
{
self->mError = CTM_LZMA_ERROR;
free(tmp);
return CTM_FALSE;
}
// Convert interleaved array to integers
for(i = 0; i < aCount; ++ i)
{
for(k = 0; k < aSize; ++ k)
{
value = (CTMint) tmp[i + k * aCount + 3 * aCount * aSize] |
(((CTMint) tmp[i + k * aCount + 2 * aCount * aSize]) << 8) |
(((CTMint) tmp[i + k * aCount + aCount * aSize]) << 16) |
(((CTMint) tmp[i + k * aCount]) << 24);
// Convert signed magnitude to two's complement?
if(aSignedInts)
{
x = (CTMuint) value;
value = (x & 1) ? -(CTMint)((x + 1) >> 1) : (CTMint)(x >> 1);
}
aData[i * aSize + k] = value;
}
}
// Free the interleaved array
free(tmp);
return CTM_TRUE;
}
//-----------------------------------------------------------------------------
// _ctmStreamWritePackedInts() - Compress a binary integer data array, and
// write it to a stream.
//-----------------------------------------------------------------------------
int _ctmStreamWritePackedInts(_CTMcontext * self, CTMint * aData,
CTMuint aCount, CTMuint aSize, CTMint aSignedInts)
{
int lzmaRes, lzmaAlgo;
CTMuint i, k;
CTMint value;
size_t bufSize, outPropsSize;
unsigned char * packed, outProps[5], *tmp;
#ifdef __DEBUG_
CTMuint negCount = 0;
#endif
// Allocate memory for interleaved array
tmp = (unsigned char *) malloc(aCount * aSize * 4);
if(!tmp)
{
self->mError = CTM_OUT_OF_MEMORY;
return CTM_FALSE;
}
// Convert integers to an interleaved array
for(i = 0; i < aCount; ++ i)
{
for(k = 0; k < aSize; ++ k)
{
value = aData[i * aSize + k];
// Convert two's complement to signed magnitude?
if(aSignedInts)
value = value < 0 ? -1 - (value << 1) : value << 1;
#ifdef __DEBUG_
else if(value < 0)
++ negCount;
#endif
tmp[i + k * aCount + 3 * aCount * aSize] = value & 0x000000ff;
tmp[i + k * aCount + 2 * aCount * aSize] = (value >> 8) & 0x000000ff;
tmp[i + k * aCount + aCount * aSize] = (value >> 16) & 0x000000ff;
tmp[i + k * aCount] = (value >> 24) & 0x000000ff;
}
}
// Allocate memory for the packed data
bufSize = 1000 + aCount * aSize * 4;
packed = (unsigned char *) malloc(bufSize);
if(!packed)
{
free(tmp);
self->mError = CTM_OUT_OF_MEMORY;
return CTM_FALSE;
}
// Call LZMA to compress
outPropsSize = 5;
lzmaAlgo = (self->mCompressionLevel < 1 ? 0 : 1);
lzmaRes = LzmaCompress(packed,
&bufSize,
(const unsigned char *) tmp,
aCount * aSize * 4,
outProps,
&outPropsSize,
self->mCompressionLevel, // Level (0-9)
0, -1, -1, -1, -1, -1, // Default values (set by level)
lzmaAlgo // Algorithm (0 = fast, 1 = normal)
);
// Free temporary array
free(tmp);
// Error?
if(lzmaRes != SZ_OK)
{
self->mError = CTM_LZMA_ERROR;
free(packed);
return CTM_FALSE;
}
#ifdef __DEBUG_
printf("%d->%d bytes (%d negative words)\n", aCount * aSize * 4, (int) bufSize, negCount);
#endif
// Write packed data size to the stream
_ctmStreamWriteUINT(self, (CTMuint) bufSize);
// Write LZMA compression props to the stream
_ctmStreamWrite(self, (void *) outProps, 5);
// Write the packed data to the stream
_ctmStreamWrite(self, (void *) packed, (CTMuint) bufSize);
// Free the packed data
free(packed);
return CTM_TRUE;
}
//-----------------------------------------------------------------------------
// _ctmStreamReadPackedFloats() - Read an compressed binary float data array
// from a stream, and uncompress it.
//-----------------------------------------------------------------------------
int _ctmStreamReadPackedFloats(_CTMcontext * self, CTMfloat * aData,
CTMuint aCount, CTMuint aSize)
{
CTMuint i, k;
size_t packedSize, unpackedSize;
union {
CTMfloat f;
CTMint i;
} value;
unsigned char * packed, * tmp;
unsigned char props[5];
int lzmaRes;
// Read packed data size from the stream
packedSize = (size_t) _ctmStreamReadUINT(self);
// Read LZMA compression props from the stream
_ctmStreamRead(self, (void *) props, 5);
// Allocate memory and read the packed data from the stream
packed = (unsigned char *) malloc(packedSize);
if(!packed)
{
self->mError = CTM_OUT_OF_MEMORY;
return CTM_FALSE;
}
_ctmStreamRead(self, (void *) packed, packedSize);
// Allocate memory for interleaved array
tmp = (unsigned char *) malloc(aCount * aSize * 4);
if(!tmp)
{
free(packed);
self->mError = CTM_OUT_OF_MEMORY;
return CTM_FALSE;
}
// Uncompress
unpackedSize = aCount * aSize * 4;
lzmaRes = LzmaUncompress(tmp, &unpackedSize, packed,
&packedSize, props, 5);
// Free the packed array
free(packed);
// Error?
if((lzmaRes != SZ_OK) || (unpackedSize != aCount * aSize * 4))
{
self->mError = CTM_LZMA_ERROR;
free(tmp);
return CTM_FALSE;
}
// Convert interleaved array to floats
for(i = 0; i < aCount; ++ i)
{
for(k = 0; k < aSize; ++ k)
{
value.i = (CTMint) tmp[i + k * aCount + 3 * aCount * aSize] |
(((CTMint) tmp[i + k * aCount + 2 * aCount * aSize]) << 8) |
(((CTMint) tmp[i + k * aCount + aCount * aSize]) << 16) |
(((CTMint) tmp[i + k * aCount]) << 24);
aData[i * aSize + k] = value.f;
}
}
// Free the interleaved array
free(tmp);
return CTM_TRUE;
}
//-----------------------------------------------------------------------------
// _ctmStreamWritePackedFloats() - Compress a binary float data array, and
// write it to a stream.
//-----------------------------------------------------------------------------
int _ctmStreamWritePackedFloats(_CTMcontext * self, CTMfloat * aData,
CTMuint aCount, CTMuint aSize)
{
int lzmaRes, lzmaAlgo;
CTMuint i, k;
union {
CTMfloat f;
CTMint i;
} value;
size_t bufSize, outPropsSize;
unsigned char * packed, outProps[5], *tmp;
// Allocate memory for interleaved array
tmp = (unsigned char *) malloc(aCount * aSize * 4);
if(!tmp)
{
self->mError = CTM_OUT_OF_MEMORY;
return CTM_FALSE;
}
// Convert floats to an interleaved array
for(i = 0; i < aCount; ++ i)
{
for(k = 0; k < aSize; ++ k)
{
value.f = aData[i * aSize + k];
tmp[i + k * aCount + 3 * aCount * aSize] = value.i & 0x000000ff;
tmp[i + k * aCount + 2 * aCount * aSize] = (value.i >> 8) & 0x000000ff;
tmp[i + k * aCount + aCount * aSize] = (value.i >> 16) & 0x000000ff;
tmp[i + k * aCount] = (value.i >> 24) & 0x000000ff;
}
}
// Allocate memory for the packed data
bufSize = 1000 + aCount * aSize * 4;
packed = (unsigned char *) malloc(bufSize);
if(!packed)
{
free(tmp);
self->mError = CTM_OUT_OF_MEMORY;
return CTM_FALSE;
}
// Call LZMA to compress
outPropsSize = 5;
lzmaAlgo = (self->mCompressionLevel < 1 ? 0 : 1);
lzmaRes = LzmaCompress(packed,
&bufSize,
(const unsigned char *) tmp,
aCount * aSize * 4,
outProps,
&outPropsSize,
self->mCompressionLevel, // Level (0-9)
0, -1, -1, -1, -1, -1, // Default values (set by level)
lzmaAlgo // Algorithm (0 = fast, 1 = normal)
);
// Free temporary array
free(tmp);
// Error?
if(lzmaRes != SZ_OK)
{
self->mError = CTM_LZMA_ERROR;
free(packed);
return CTM_FALSE;
}
#ifdef __DEBUG_
printf("%d->%d bytes\n", aCount * aSize * 4, (int) bufSize);
#endif
// Write packed data size to the stream
_ctmStreamWriteUINT(self, (CTMuint) bufSize);
// Write LZMA compression props to the stream
_ctmStreamWrite(self, (void *) outProps, 5);
// Write the packed data to the stream
_ctmStreamWrite(self, (void *) packed, (CTMuint) bufSize);
// Free the packed data
free(packed);
return CTM_TRUE;
}