goat3d
diff libs/openctm/stream.c @ 14:188c697b3b49
- added a document describing the goat3d file format chunk hierarchy
- started an alternative XML-based file format
- added the openctm library
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 26 Sep 2013 04:47:05 +0300 |
parents | |
children | 21319e71117f |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/openctm/stream.c Thu Sep 26 04:47:05 2013 +0300 1.3 @@ -0,0 +1,512 @@ 1.4 +//----------------------------------------------------------------------------- 1.5 +// Product: OpenCTM 1.6 +// File: stream.c 1.7 +// Description: Stream I/O functions. 1.8 +//----------------------------------------------------------------------------- 1.9 +// Copyright (c) 2009-2010 Marcus Geelnard 1.10 +// 1.11 +// This software is provided 'as-is', without any express or implied 1.12 +// warranty. In no event will the authors be held liable for any damages 1.13 +// arising from the use of this software. 1.14 +// 1.15 +// Permission is granted to anyone to use this software for any purpose, 1.16 +// including commercial applications, and to alter it and redistribute it 1.17 +// freely, subject to the following restrictions: 1.18 +// 1.19 +// 1. The origin of this software must not be misrepresented; you must not 1.20 +// claim that you wrote the original software. If you use this software 1.21 +// in a product, an acknowledgment in the product documentation would be 1.22 +// appreciated but is not required. 1.23 +// 1.24 +// 2. Altered source versions must be plainly marked as such, and must not 1.25 +// be misrepresented as being the original software. 1.26 +// 1.27 +// 3. This notice may not be removed or altered from any source 1.28 +// distribution. 1.29 +//----------------------------------------------------------------------------- 1.30 + 1.31 +#include <stdlib.h> 1.32 +#include <string.h> 1.33 +#include <LzmaLib.h> 1.34 +#include "openctm.h" 1.35 +#include "internal.h" 1.36 + 1.37 +#ifdef __DEBUG_ 1.38 +#include <stdio.h> 1.39 +#endif 1.40 + 1.41 +//----------------------------------------------------------------------------- 1.42 +// _ctmStreamRead() - Read data from a stream. 1.43 +//----------------------------------------------------------------------------- 1.44 +CTMuint _ctmStreamRead(_CTMcontext * self, void * aBuf, CTMuint aCount) 1.45 +{ 1.46 + if(!self->mUserData || !self->mReadFn) 1.47 + return 0; 1.48 + 1.49 + return self->mReadFn(aBuf, aCount, self->mUserData); 1.50 +} 1.51 + 1.52 +//----------------------------------------------------------------------------- 1.53 +// _ctmStreamWrite() - Write data to a stream. 1.54 +//----------------------------------------------------------------------------- 1.55 +CTMuint _ctmStreamWrite(_CTMcontext * self, void * aBuf, CTMuint aCount) 1.56 +{ 1.57 + if(!self->mUserData || !self->mWriteFn) 1.58 + return 0; 1.59 + 1.60 + return self->mWriteFn(aBuf, aCount, self->mUserData); 1.61 +} 1.62 + 1.63 +//----------------------------------------------------------------------------- 1.64 +// _ctmStreamReadUINT() - Read an unsigned integer from a stream in a machine 1.65 +// endian independent manner (for portability). 1.66 +//----------------------------------------------------------------------------- 1.67 +CTMuint _ctmStreamReadUINT(_CTMcontext * self) 1.68 +{ 1.69 + unsigned char buf[4]; 1.70 + _ctmStreamRead(self, (void *) buf, 4); 1.71 + return ((CTMuint) buf[0]) | 1.72 + (((CTMuint) buf[1]) << 8) | 1.73 + (((CTMuint) buf[2]) << 16) | 1.74 + (((CTMuint) buf[3]) << 24); 1.75 +} 1.76 + 1.77 +//----------------------------------------------------------------------------- 1.78 +// _ctmStreamWriteUINT() - Write an unsigned integer to a stream in a machine 1.79 +// endian independent manner (for portability). 1.80 +//----------------------------------------------------------------------------- 1.81 +void _ctmStreamWriteUINT(_CTMcontext * self, CTMuint aValue) 1.82 +{ 1.83 + unsigned char buf[4]; 1.84 + buf[0] = aValue & 0x000000ff; 1.85 + buf[1] = (aValue >> 8) & 0x000000ff; 1.86 + buf[2] = (aValue >> 16) & 0x000000ff; 1.87 + buf[3] = (aValue >> 24) & 0x000000ff; 1.88 + _ctmStreamWrite(self, (void *) buf, 4); 1.89 +} 1.90 + 1.91 +//----------------------------------------------------------------------------- 1.92 +// _ctmStreamReadFLOAT() - Read a floating point value from a stream in a 1.93 +// machine endian independent manner (for portability). 1.94 +//----------------------------------------------------------------------------- 1.95 +CTMfloat _ctmStreamReadFLOAT(_CTMcontext * self) 1.96 +{ 1.97 + union { 1.98 + CTMfloat f; 1.99 + CTMuint i; 1.100 + } u; 1.101 + u.i = _ctmStreamReadUINT(self); 1.102 + return u.f; 1.103 +} 1.104 + 1.105 +//----------------------------------------------------------------------------- 1.106 +// _ctmStreamWriteFLOAT() - Write a floating point value to a stream in a 1.107 +// machine endian independent manner (for portability). 1.108 +//----------------------------------------------------------------------------- 1.109 +void _ctmStreamWriteFLOAT(_CTMcontext * self, CTMfloat aValue) 1.110 +{ 1.111 + union { 1.112 + CTMfloat f; 1.113 + CTMuint i; 1.114 + } u; 1.115 + u.f = aValue; 1.116 + _ctmStreamWriteUINT(self, u.i); 1.117 +} 1.118 + 1.119 +//----------------------------------------------------------------------------- 1.120 +// _ctmStreamReadSTRING() - Read a string value from a stream. The format of 1.121 +// the string in the stream is: an unsigned integer (string length) followed by 1.122 +// the string (without null termination). 1.123 +//----------------------------------------------------------------------------- 1.124 +void _ctmStreamReadSTRING(_CTMcontext * self, char ** aValue) 1.125 +{ 1.126 + CTMuint len; 1.127 + 1.128 + // Clear the old string 1.129 + if(*aValue) 1.130 + { 1.131 + free(*aValue); 1.132 + *aValue = (char *) 0; 1.133 + } 1.134 + 1.135 + // Get string length 1.136 + len = _ctmStreamReadUINT(self); 1.137 + 1.138 + // Read string 1.139 + if(len > 0) 1.140 + { 1.141 + *aValue = (char *) malloc(len + 1); 1.142 + if(*aValue) 1.143 + { 1.144 + _ctmStreamRead(self, (void *) *aValue, len); 1.145 + (*aValue)[len] = 0; 1.146 + } 1.147 + } 1.148 +} 1.149 + 1.150 +//----------------------------------------------------------------------------- 1.151 +// _ctmStreamWriteSTRING() - Write a string value to a stream. The format of 1.152 +// the string in the stream is: an unsigned integer (string length) followed by 1.153 +// the string (without null termination). 1.154 +//----------------------------------------------------------------------------- 1.155 +void _ctmStreamWriteSTRING(_CTMcontext * self, const char * aValue) 1.156 +{ 1.157 + CTMuint len; 1.158 + 1.159 + // Get string length 1.160 + if(aValue) 1.161 + len = strlen(aValue); 1.162 + else 1.163 + len = 0; 1.164 + 1.165 + // Write string length 1.166 + _ctmStreamWriteUINT(self, len); 1.167 + 1.168 + // Write string 1.169 + if(len > 0) 1.170 + _ctmStreamWrite(self, (void *) aValue, len); 1.171 +} 1.172 + 1.173 +//----------------------------------------------------------------------------- 1.174 +// _ctmStreamReadPackedInts() - Read an compressed binary integer data array 1.175 +// from a stream, and uncompress it. 1.176 +//----------------------------------------------------------------------------- 1.177 +int _ctmStreamReadPackedInts(_CTMcontext * self, CTMint * aData, 1.178 + CTMuint aCount, CTMuint aSize, CTMint aSignedInts) 1.179 +{ 1.180 + size_t packedSize, unpackedSize; 1.181 + CTMuint i, k, x; 1.182 + CTMint value; 1.183 + unsigned char * packed, * tmp; 1.184 + unsigned char props[5]; 1.185 + int lzmaRes; 1.186 + 1.187 + // Read packed data size from the stream 1.188 + packedSize = (size_t) _ctmStreamReadUINT(self); 1.189 + 1.190 + // Read LZMA compression props from the stream 1.191 + _ctmStreamRead(self, (void *) props, 5); 1.192 + 1.193 + // Allocate memory and read the packed data from the stream 1.194 + packed = (unsigned char *) malloc(packedSize); 1.195 + if(!packed) 1.196 + { 1.197 + self->mError = CTM_OUT_OF_MEMORY; 1.198 + return CTM_FALSE; 1.199 + } 1.200 + _ctmStreamRead(self, (void *) packed, packedSize); 1.201 + 1.202 + // Allocate memory for interleaved array 1.203 + tmp = (unsigned char *) malloc(aCount * aSize * 4); 1.204 + if(!tmp) 1.205 + { 1.206 + free(packed); 1.207 + self->mError = CTM_OUT_OF_MEMORY; 1.208 + return CTM_FALSE; 1.209 + } 1.210 + 1.211 + // Uncompress 1.212 + unpackedSize = aCount * aSize * 4; 1.213 + lzmaRes = LzmaUncompress(tmp, &unpackedSize, packed, 1.214 + &packedSize, props, 5); 1.215 + 1.216 + // Free the packed array 1.217 + free(packed); 1.218 + 1.219 + // Error? 1.220 + if((lzmaRes != SZ_OK) || (unpackedSize != aCount * aSize * 4)) 1.221 + { 1.222 + self->mError = CTM_LZMA_ERROR; 1.223 + free(tmp); 1.224 + return CTM_FALSE; 1.225 + } 1.226 + 1.227 + // Convert interleaved array to integers 1.228 + for(i = 0; i < aCount; ++ i) 1.229 + { 1.230 + for(k = 0; k < aSize; ++ k) 1.231 + { 1.232 + value = (CTMint) tmp[i + k * aCount + 3 * aCount * aSize] | 1.233 + (((CTMint) tmp[i + k * aCount + 2 * aCount * aSize]) << 8) | 1.234 + (((CTMint) tmp[i + k * aCount + aCount * aSize]) << 16) | 1.235 + (((CTMint) tmp[i + k * aCount]) << 24); 1.236 + // Convert signed magnitude to two's complement? 1.237 + if(aSignedInts) 1.238 + { 1.239 + x = (CTMuint) value; 1.240 + value = (x & 1) ? -(CTMint)((x + 1) >> 1) : (CTMint)(x >> 1); 1.241 + } 1.242 + aData[i * aSize + k] = value; 1.243 + } 1.244 + } 1.245 + 1.246 + // Free the interleaved array 1.247 + free(tmp); 1.248 + 1.249 + return CTM_TRUE; 1.250 +} 1.251 + 1.252 +//----------------------------------------------------------------------------- 1.253 +// _ctmStreamWritePackedInts() - Compress a binary integer data array, and 1.254 +// write it to a stream. 1.255 +//----------------------------------------------------------------------------- 1.256 +int _ctmStreamWritePackedInts(_CTMcontext * self, CTMint * aData, 1.257 + CTMuint aCount, CTMuint aSize, CTMint aSignedInts) 1.258 +{ 1.259 + int lzmaRes, lzmaAlgo; 1.260 + CTMuint i, k; 1.261 + CTMint value; 1.262 + size_t bufSize, outPropsSize; 1.263 + unsigned char * packed, outProps[5], *tmp; 1.264 +#ifdef __DEBUG_ 1.265 + CTMuint negCount = 0; 1.266 +#endif 1.267 + 1.268 + // Allocate memory for interleaved array 1.269 + tmp = (unsigned char *) malloc(aCount * aSize * 4); 1.270 + if(!tmp) 1.271 + { 1.272 + self->mError = CTM_OUT_OF_MEMORY; 1.273 + return CTM_FALSE; 1.274 + } 1.275 + 1.276 + // Convert integers to an interleaved array 1.277 + for(i = 0; i < aCount; ++ i) 1.278 + { 1.279 + for(k = 0; k < aSize; ++ k) 1.280 + { 1.281 + value = aData[i * aSize + k]; 1.282 + // Convert two's complement to signed magnitude? 1.283 + if(aSignedInts) 1.284 + value = value < 0 ? -1 - (value << 1) : value << 1; 1.285 +#ifdef __DEBUG_ 1.286 + else if(value < 0) 1.287 + ++ negCount; 1.288 +#endif 1.289 + tmp[i + k * aCount + 3 * aCount * aSize] = value & 0x000000ff; 1.290 + tmp[i + k * aCount + 2 * aCount * aSize] = (value >> 8) & 0x000000ff; 1.291 + tmp[i + k * aCount + aCount * aSize] = (value >> 16) & 0x000000ff; 1.292 + tmp[i + k * aCount] = (value >> 24) & 0x000000ff; 1.293 + } 1.294 + } 1.295 + 1.296 + // Allocate memory for the packed data 1.297 + bufSize = 1000 + aCount * aSize * 4; 1.298 + packed = (unsigned char *) malloc(bufSize); 1.299 + if(!packed) 1.300 + { 1.301 + free(tmp); 1.302 + self->mError = CTM_OUT_OF_MEMORY; 1.303 + return CTM_FALSE; 1.304 + } 1.305 + 1.306 + // Call LZMA to compress 1.307 + outPropsSize = 5; 1.308 + lzmaAlgo = (self->mCompressionLevel < 1 ? 0 : 1); 1.309 + lzmaRes = LzmaCompress(packed, 1.310 + &bufSize, 1.311 + (const unsigned char *) tmp, 1.312 + aCount * aSize * 4, 1.313 + outProps, 1.314 + &outPropsSize, 1.315 + self->mCompressionLevel, // Level (0-9) 1.316 + 0, -1, -1, -1, -1, -1, // Default values (set by level) 1.317 + lzmaAlgo // Algorithm (0 = fast, 1 = normal) 1.318 + ); 1.319 + 1.320 + // Free temporary array 1.321 + free(tmp); 1.322 + 1.323 + // Error? 1.324 + if(lzmaRes != SZ_OK) 1.325 + { 1.326 + self->mError = CTM_LZMA_ERROR; 1.327 + free(packed); 1.328 + return CTM_FALSE; 1.329 + } 1.330 + 1.331 +#ifdef __DEBUG_ 1.332 + printf("%d->%d bytes (%d negative words)\n", aCount * aSize * 4, (int) bufSize, negCount); 1.333 +#endif 1.334 + 1.335 + // Write packed data size to the stream 1.336 + _ctmStreamWriteUINT(self, (CTMuint) bufSize); 1.337 + 1.338 + // Write LZMA compression props to the stream 1.339 + _ctmStreamWrite(self, (void *) outProps, 5); 1.340 + 1.341 + // Write the packed data to the stream 1.342 + _ctmStreamWrite(self, (void *) packed, (CTMuint) bufSize); 1.343 + 1.344 + // Free the packed data 1.345 + free(packed); 1.346 + 1.347 + return CTM_TRUE; 1.348 +} 1.349 + 1.350 +//----------------------------------------------------------------------------- 1.351 +// _ctmStreamReadPackedFloats() - Read an compressed binary float data array 1.352 +// from a stream, and uncompress it. 1.353 +//----------------------------------------------------------------------------- 1.354 +int _ctmStreamReadPackedFloats(_CTMcontext * self, CTMfloat * aData, 1.355 + CTMuint aCount, CTMuint aSize) 1.356 +{ 1.357 + CTMuint i, k; 1.358 + size_t packedSize, unpackedSize; 1.359 + union { 1.360 + CTMfloat f; 1.361 + CTMint i; 1.362 + } value; 1.363 + unsigned char * packed, * tmp; 1.364 + unsigned char props[5]; 1.365 + int lzmaRes; 1.366 + 1.367 + // Read packed data size from the stream 1.368 + packedSize = (size_t) _ctmStreamReadUINT(self); 1.369 + 1.370 + // Read LZMA compression props from the stream 1.371 + _ctmStreamRead(self, (void *) props, 5); 1.372 + 1.373 + // Allocate memory and read the packed data from the stream 1.374 + packed = (unsigned char *) malloc(packedSize); 1.375 + if(!packed) 1.376 + { 1.377 + self->mError = CTM_OUT_OF_MEMORY; 1.378 + return CTM_FALSE; 1.379 + } 1.380 + _ctmStreamRead(self, (void *) packed, packedSize); 1.381 + 1.382 + // Allocate memory for interleaved array 1.383 + tmp = (unsigned char *) malloc(aCount * aSize * 4); 1.384 + if(!tmp) 1.385 + { 1.386 + free(packed); 1.387 + self->mError = CTM_OUT_OF_MEMORY; 1.388 + return CTM_FALSE; 1.389 + } 1.390 + 1.391 + // Uncompress 1.392 + unpackedSize = aCount * aSize * 4; 1.393 + lzmaRes = LzmaUncompress(tmp, &unpackedSize, packed, 1.394 + &packedSize, props, 5); 1.395 + 1.396 + // Free the packed array 1.397 + free(packed); 1.398 + 1.399 + // Error? 1.400 + if((lzmaRes != SZ_OK) || (unpackedSize != aCount * aSize * 4)) 1.401 + { 1.402 + self->mError = CTM_LZMA_ERROR; 1.403 + free(tmp); 1.404 + return CTM_FALSE; 1.405 + } 1.406 + 1.407 + // Convert interleaved array to floats 1.408 + for(i = 0; i < aCount; ++ i) 1.409 + { 1.410 + for(k = 0; k < aSize; ++ k) 1.411 + { 1.412 + value.i = (CTMint) tmp[i + k * aCount + 3 * aCount * aSize] | 1.413 + (((CTMint) tmp[i + k * aCount + 2 * aCount * aSize]) << 8) | 1.414 + (((CTMint) tmp[i + k * aCount + aCount * aSize]) << 16) | 1.415 + (((CTMint) tmp[i + k * aCount]) << 24); 1.416 + aData[i * aSize + k] = value.f; 1.417 + } 1.418 + } 1.419 + 1.420 + // Free the interleaved array 1.421 + free(tmp); 1.422 + 1.423 + return CTM_TRUE; 1.424 +} 1.425 + 1.426 +//----------------------------------------------------------------------------- 1.427 +// _ctmStreamWritePackedFloats() - Compress a binary float data array, and 1.428 +// write it to a stream. 1.429 +//----------------------------------------------------------------------------- 1.430 +int _ctmStreamWritePackedFloats(_CTMcontext * self, CTMfloat * aData, 1.431 + CTMuint aCount, CTMuint aSize) 1.432 +{ 1.433 + int lzmaRes, lzmaAlgo; 1.434 + CTMuint i, k; 1.435 + union { 1.436 + CTMfloat f; 1.437 + CTMint i; 1.438 + } value; 1.439 + size_t bufSize, outPropsSize; 1.440 + unsigned char * packed, outProps[5], *tmp; 1.441 + 1.442 + // Allocate memory for interleaved array 1.443 + tmp = (unsigned char *) malloc(aCount * aSize * 4); 1.444 + if(!tmp) 1.445 + { 1.446 + self->mError = CTM_OUT_OF_MEMORY; 1.447 + return CTM_FALSE; 1.448 + } 1.449 + 1.450 + // Convert floats to an interleaved array 1.451 + for(i = 0; i < aCount; ++ i) 1.452 + { 1.453 + for(k = 0; k < aSize; ++ k) 1.454 + { 1.455 + value.f = aData[i * aSize + k]; 1.456 + tmp[i + k * aCount + 3 * aCount * aSize] = value.i & 0x000000ff; 1.457 + tmp[i + k * aCount + 2 * aCount * aSize] = (value.i >> 8) & 0x000000ff; 1.458 + tmp[i + k * aCount + aCount * aSize] = (value.i >> 16) & 0x000000ff; 1.459 + tmp[i + k * aCount] = (value.i >> 24) & 0x000000ff; 1.460 + } 1.461 + } 1.462 + 1.463 + // Allocate memory for the packed data 1.464 + bufSize = 1000 + aCount * aSize * 4; 1.465 + packed = (unsigned char *) malloc(bufSize); 1.466 + if(!packed) 1.467 + { 1.468 + free(tmp); 1.469 + self->mError = CTM_OUT_OF_MEMORY; 1.470 + return CTM_FALSE; 1.471 + } 1.472 + 1.473 + // Call LZMA to compress 1.474 + outPropsSize = 5; 1.475 + lzmaAlgo = (self->mCompressionLevel < 1 ? 0 : 1); 1.476 + lzmaRes = LzmaCompress(packed, 1.477 + &bufSize, 1.478 + (const unsigned char *) tmp, 1.479 + aCount * aSize * 4, 1.480 + outProps, 1.481 + &outPropsSize, 1.482 + self->mCompressionLevel, // Level (0-9) 1.483 + 0, -1, -1, -1, -1, -1, // Default values (set by level) 1.484 + lzmaAlgo // Algorithm (0 = fast, 1 = normal) 1.485 + ); 1.486 + 1.487 + // Free temporary array 1.488 + free(tmp); 1.489 + 1.490 + // Error? 1.491 + if(lzmaRes != SZ_OK) 1.492 + { 1.493 + self->mError = CTM_LZMA_ERROR; 1.494 + free(packed); 1.495 + return CTM_FALSE; 1.496 + } 1.497 + 1.498 +#ifdef __DEBUG_ 1.499 + printf("%d->%d bytes\n", aCount * aSize * 4, (int) bufSize); 1.500 +#endif 1.501 + 1.502 + // Write packed data size to the stream 1.503 + _ctmStreamWriteUINT(self, (CTMuint) bufSize); 1.504 + 1.505 + // Write LZMA compression props to the stream 1.506 + _ctmStreamWrite(self, (void *) outProps, 5); 1.507 + 1.508 + // Write the packed data to the stream 1.509 + _ctmStreamWrite(self, (void *) packed, (CTMuint) bufSize); 1.510 + 1.511 + // Free the packed data 1.512 + free(packed); 1.513 + 1.514 + return CTM_TRUE; 1.515 +}