goat3d

view libs/openctm/stream.c @ 54:dad392c710df

added copyright headers and license files + readme
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 17 Apr 2014 08:50:36 +0300
parents
children 21319e71117f
line source
1 //-----------------------------------------------------------------------------
2 // Product: OpenCTM
3 // File: stream.c
4 // Description: Stream I/O functions.
5 //-----------------------------------------------------------------------------
6 // Copyright (c) 2009-2010 Marcus Geelnard
7 //
8 // This software is provided 'as-is', without any express or implied
9 // warranty. In no event will the authors be held liable for any damages
10 // arising from the use of this software.
11 //
12 // Permission is granted to anyone to use this software for any purpose,
13 // including commercial applications, and to alter it and redistribute it
14 // freely, subject to the following restrictions:
15 //
16 // 1. The origin of this software must not be misrepresented; you must not
17 // claim that you wrote the original software. If you use this software
18 // in a product, an acknowledgment in the product documentation would be
19 // appreciated but is not required.
20 //
21 // 2. Altered source versions must be plainly marked as such, and must not
22 // be misrepresented as being the original software.
23 //
24 // 3. This notice may not be removed or altered from any source
25 // distribution.
26 //-----------------------------------------------------------------------------
28 #include <stdlib.h>
29 #include <string.h>
30 #include <LzmaLib.h>
31 #include "openctm.h"
32 #include "internal.h"
34 #ifdef __DEBUG_
35 #include <stdio.h>
36 #endif
38 //-----------------------------------------------------------------------------
39 // _ctmStreamRead() - Read data from a stream.
40 //-----------------------------------------------------------------------------
41 CTMuint _ctmStreamRead(_CTMcontext * self, void * aBuf, CTMuint aCount)
42 {
43 if(!self->mUserData || !self->mReadFn)
44 return 0;
46 return self->mReadFn(aBuf, aCount, self->mUserData);
47 }
49 //-----------------------------------------------------------------------------
50 // _ctmStreamWrite() - Write data to a stream.
51 //-----------------------------------------------------------------------------
52 CTMuint _ctmStreamWrite(_CTMcontext * self, void * aBuf, CTMuint aCount)
53 {
54 if(!self->mUserData || !self->mWriteFn)
55 return 0;
57 return self->mWriteFn(aBuf, aCount, self->mUserData);
58 }
60 //-----------------------------------------------------------------------------
61 // _ctmStreamReadUINT() - Read an unsigned integer from a stream in a machine
62 // endian independent manner (for portability).
63 //-----------------------------------------------------------------------------
64 CTMuint _ctmStreamReadUINT(_CTMcontext * self)
65 {
66 unsigned char buf[4];
67 _ctmStreamRead(self, (void *) buf, 4);
68 return ((CTMuint) buf[0]) |
69 (((CTMuint) buf[1]) << 8) |
70 (((CTMuint) buf[2]) << 16) |
71 (((CTMuint) buf[3]) << 24);
72 }
74 //-----------------------------------------------------------------------------
75 // _ctmStreamWriteUINT() - Write an unsigned integer to a stream in a machine
76 // endian independent manner (for portability).
77 //-----------------------------------------------------------------------------
78 void _ctmStreamWriteUINT(_CTMcontext * self, CTMuint aValue)
79 {
80 unsigned char buf[4];
81 buf[0] = aValue & 0x000000ff;
82 buf[1] = (aValue >> 8) & 0x000000ff;
83 buf[2] = (aValue >> 16) & 0x000000ff;
84 buf[3] = (aValue >> 24) & 0x000000ff;
85 _ctmStreamWrite(self, (void *) buf, 4);
86 }
88 //-----------------------------------------------------------------------------
89 // _ctmStreamReadFLOAT() - Read a floating point value from a stream in a
90 // machine endian independent manner (for portability).
91 //-----------------------------------------------------------------------------
92 CTMfloat _ctmStreamReadFLOAT(_CTMcontext * self)
93 {
94 union {
95 CTMfloat f;
96 CTMuint i;
97 } u;
98 u.i = _ctmStreamReadUINT(self);
99 return u.f;
100 }
102 //-----------------------------------------------------------------------------
103 // _ctmStreamWriteFLOAT() - Write a floating point value to a stream in a
104 // machine endian independent manner (for portability).
105 //-----------------------------------------------------------------------------
106 void _ctmStreamWriteFLOAT(_CTMcontext * self, CTMfloat aValue)
107 {
108 union {
109 CTMfloat f;
110 CTMuint i;
111 } u;
112 u.f = aValue;
113 _ctmStreamWriteUINT(self, u.i);
114 }
116 //-----------------------------------------------------------------------------
117 // _ctmStreamReadSTRING() - Read a string value from a stream. The format of
118 // the string in the stream is: an unsigned integer (string length) followed by
119 // the string (without null termination).
120 //-----------------------------------------------------------------------------
121 void _ctmStreamReadSTRING(_CTMcontext * self, char ** aValue)
122 {
123 CTMuint len;
125 // Clear the old string
126 if(*aValue)
127 {
128 free(*aValue);
129 *aValue = (char *) 0;
130 }
132 // Get string length
133 len = _ctmStreamReadUINT(self);
135 // Read string
136 if(len > 0)
137 {
138 *aValue = (char *) malloc(len + 1);
139 if(*aValue)
140 {
141 _ctmStreamRead(self, (void *) *aValue, len);
142 (*aValue)[len] = 0;
143 }
144 }
145 }
147 //-----------------------------------------------------------------------------
148 // _ctmStreamWriteSTRING() - Write a string value to a stream. The format of
149 // the string in the stream is: an unsigned integer (string length) followed by
150 // the string (without null termination).
151 //-----------------------------------------------------------------------------
152 void _ctmStreamWriteSTRING(_CTMcontext * self, const char * aValue)
153 {
154 CTMuint len;
156 // Get string length
157 if(aValue)
158 len = strlen(aValue);
159 else
160 len = 0;
162 // Write string length
163 _ctmStreamWriteUINT(self, len);
165 // Write string
166 if(len > 0)
167 _ctmStreamWrite(self, (void *) aValue, len);
168 }
170 //-----------------------------------------------------------------------------
171 // _ctmStreamReadPackedInts() - Read an compressed binary integer data array
172 // from a stream, and uncompress it.
173 //-----------------------------------------------------------------------------
174 int _ctmStreamReadPackedInts(_CTMcontext * self, CTMint * aData,
175 CTMuint aCount, CTMuint aSize, CTMint aSignedInts)
176 {
177 size_t packedSize, unpackedSize;
178 CTMuint i, k, x;
179 CTMint value;
180 unsigned char * packed, * tmp;
181 unsigned char props[5];
182 int lzmaRes;
184 // Read packed data size from the stream
185 packedSize = (size_t) _ctmStreamReadUINT(self);
187 // Read LZMA compression props from the stream
188 _ctmStreamRead(self, (void *) props, 5);
190 // Allocate memory and read the packed data from the stream
191 packed = (unsigned char *) malloc(packedSize);
192 if(!packed)
193 {
194 self->mError = CTM_OUT_OF_MEMORY;
195 return CTM_FALSE;
196 }
197 _ctmStreamRead(self, (void *) packed, packedSize);
199 // Allocate memory for interleaved array
200 tmp = (unsigned char *) malloc(aCount * aSize * 4);
201 if(!tmp)
202 {
203 free(packed);
204 self->mError = CTM_OUT_OF_MEMORY;
205 return CTM_FALSE;
206 }
208 // Uncompress
209 unpackedSize = aCount * aSize * 4;
210 lzmaRes = LzmaUncompress(tmp, &unpackedSize, packed,
211 &packedSize, props, 5);
213 // Free the packed array
214 free(packed);
216 // Error?
217 if((lzmaRes != SZ_OK) || (unpackedSize != aCount * aSize * 4))
218 {
219 self->mError = CTM_LZMA_ERROR;
220 free(tmp);
221 return CTM_FALSE;
222 }
224 // Convert interleaved array to integers
225 for(i = 0; i < aCount; ++ i)
226 {
227 for(k = 0; k < aSize; ++ k)
228 {
229 value = (CTMint) tmp[i + k * aCount + 3 * aCount * aSize] |
230 (((CTMint) tmp[i + k * aCount + 2 * aCount * aSize]) << 8) |
231 (((CTMint) tmp[i + k * aCount + aCount * aSize]) << 16) |
232 (((CTMint) tmp[i + k * aCount]) << 24);
233 // Convert signed magnitude to two's complement?
234 if(aSignedInts)
235 {
236 x = (CTMuint) value;
237 value = (x & 1) ? -(CTMint)((x + 1) >> 1) : (CTMint)(x >> 1);
238 }
239 aData[i * aSize + k] = value;
240 }
241 }
243 // Free the interleaved array
244 free(tmp);
246 return CTM_TRUE;
247 }
249 //-----------------------------------------------------------------------------
250 // _ctmStreamWritePackedInts() - Compress a binary integer data array, and
251 // write it to a stream.
252 //-----------------------------------------------------------------------------
253 int _ctmStreamWritePackedInts(_CTMcontext * self, CTMint * aData,
254 CTMuint aCount, CTMuint aSize, CTMint aSignedInts)
255 {
256 int lzmaRes, lzmaAlgo;
257 CTMuint i, k;
258 CTMint value;
259 size_t bufSize, outPropsSize;
260 unsigned char * packed, outProps[5], *tmp;
261 #ifdef __DEBUG_
262 CTMuint negCount = 0;
263 #endif
265 // Allocate memory for interleaved array
266 tmp = (unsigned char *) malloc(aCount * aSize * 4);
267 if(!tmp)
268 {
269 self->mError = CTM_OUT_OF_MEMORY;
270 return CTM_FALSE;
271 }
273 // Convert integers to an interleaved array
274 for(i = 0; i < aCount; ++ i)
275 {
276 for(k = 0; k < aSize; ++ k)
277 {
278 value = aData[i * aSize + k];
279 // Convert two's complement to signed magnitude?
280 if(aSignedInts)
281 value = value < 0 ? -1 - (value << 1) : value << 1;
282 #ifdef __DEBUG_
283 else if(value < 0)
284 ++ negCount;
285 #endif
286 tmp[i + k * aCount + 3 * aCount * aSize] = value & 0x000000ff;
287 tmp[i + k * aCount + 2 * aCount * aSize] = (value >> 8) & 0x000000ff;
288 tmp[i + k * aCount + aCount * aSize] = (value >> 16) & 0x000000ff;
289 tmp[i + k * aCount] = (value >> 24) & 0x000000ff;
290 }
291 }
293 // Allocate memory for the packed data
294 bufSize = 1000 + aCount * aSize * 4;
295 packed = (unsigned char *) malloc(bufSize);
296 if(!packed)
297 {
298 free(tmp);
299 self->mError = CTM_OUT_OF_MEMORY;
300 return CTM_FALSE;
301 }
303 // Call LZMA to compress
304 outPropsSize = 5;
305 lzmaAlgo = (self->mCompressionLevel < 1 ? 0 : 1);
306 lzmaRes = LzmaCompress(packed,
307 &bufSize,
308 (const unsigned char *) tmp,
309 aCount * aSize * 4,
310 outProps,
311 &outPropsSize,
312 self->mCompressionLevel, // Level (0-9)
313 0, -1, -1, -1, -1, -1, // Default values (set by level)
314 lzmaAlgo // Algorithm (0 = fast, 1 = normal)
315 );
317 // Free temporary array
318 free(tmp);
320 // Error?
321 if(lzmaRes != SZ_OK)
322 {
323 self->mError = CTM_LZMA_ERROR;
324 free(packed);
325 return CTM_FALSE;
326 }
328 #ifdef __DEBUG_
329 printf("%d->%d bytes (%d negative words)\n", aCount * aSize * 4, (int) bufSize, negCount);
330 #endif
332 // Write packed data size to the stream
333 _ctmStreamWriteUINT(self, (CTMuint) bufSize);
335 // Write LZMA compression props to the stream
336 _ctmStreamWrite(self, (void *) outProps, 5);
338 // Write the packed data to the stream
339 _ctmStreamWrite(self, (void *) packed, (CTMuint) bufSize);
341 // Free the packed data
342 free(packed);
344 return CTM_TRUE;
345 }
347 //-----------------------------------------------------------------------------
348 // _ctmStreamReadPackedFloats() - Read an compressed binary float data array
349 // from a stream, and uncompress it.
350 //-----------------------------------------------------------------------------
351 int _ctmStreamReadPackedFloats(_CTMcontext * self, CTMfloat * aData,
352 CTMuint aCount, CTMuint aSize)
353 {
354 CTMuint i, k;
355 size_t packedSize, unpackedSize;
356 union {
357 CTMfloat f;
358 CTMint i;
359 } value;
360 unsigned char * packed, * tmp;
361 unsigned char props[5];
362 int lzmaRes;
364 // Read packed data size from the stream
365 packedSize = (size_t) _ctmStreamReadUINT(self);
367 // Read LZMA compression props from the stream
368 _ctmStreamRead(self, (void *) props, 5);
370 // Allocate memory and read the packed data from the stream
371 packed = (unsigned char *) malloc(packedSize);
372 if(!packed)
373 {
374 self->mError = CTM_OUT_OF_MEMORY;
375 return CTM_FALSE;
376 }
377 _ctmStreamRead(self, (void *) packed, packedSize);
379 // Allocate memory for interleaved array
380 tmp = (unsigned char *) malloc(aCount * aSize * 4);
381 if(!tmp)
382 {
383 free(packed);
384 self->mError = CTM_OUT_OF_MEMORY;
385 return CTM_FALSE;
386 }
388 // Uncompress
389 unpackedSize = aCount * aSize * 4;
390 lzmaRes = LzmaUncompress(tmp, &unpackedSize, packed,
391 &packedSize, props, 5);
393 // Free the packed array
394 free(packed);
396 // Error?
397 if((lzmaRes != SZ_OK) || (unpackedSize != aCount * aSize * 4))
398 {
399 self->mError = CTM_LZMA_ERROR;
400 free(tmp);
401 return CTM_FALSE;
402 }
404 // Convert interleaved array to floats
405 for(i = 0; i < aCount; ++ i)
406 {
407 for(k = 0; k < aSize; ++ k)
408 {
409 value.i = (CTMint) tmp[i + k * aCount + 3 * aCount * aSize] |
410 (((CTMint) tmp[i + k * aCount + 2 * aCount * aSize]) << 8) |
411 (((CTMint) tmp[i + k * aCount + aCount * aSize]) << 16) |
412 (((CTMint) tmp[i + k * aCount]) << 24);
413 aData[i * aSize + k] = value.f;
414 }
415 }
417 // Free the interleaved array
418 free(tmp);
420 return CTM_TRUE;
421 }
423 //-----------------------------------------------------------------------------
424 // _ctmStreamWritePackedFloats() - Compress a binary float data array, and
425 // write it to a stream.
426 //-----------------------------------------------------------------------------
427 int _ctmStreamWritePackedFloats(_CTMcontext * self, CTMfloat * aData,
428 CTMuint aCount, CTMuint aSize)
429 {
430 int lzmaRes, lzmaAlgo;
431 CTMuint i, k;
432 union {
433 CTMfloat f;
434 CTMint i;
435 } value;
436 size_t bufSize, outPropsSize;
437 unsigned char * packed, outProps[5], *tmp;
439 // Allocate memory for interleaved array
440 tmp = (unsigned char *) malloc(aCount * aSize * 4);
441 if(!tmp)
442 {
443 self->mError = CTM_OUT_OF_MEMORY;
444 return CTM_FALSE;
445 }
447 // Convert floats to an interleaved array
448 for(i = 0; i < aCount; ++ i)
449 {
450 for(k = 0; k < aSize; ++ k)
451 {
452 value.f = aData[i * aSize + k];
453 tmp[i + k * aCount + 3 * aCount * aSize] = value.i & 0x000000ff;
454 tmp[i + k * aCount + 2 * aCount * aSize] = (value.i >> 8) & 0x000000ff;
455 tmp[i + k * aCount + aCount * aSize] = (value.i >> 16) & 0x000000ff;
456 tmp[i + k * aCount] = (value.i >> 24) & 0x000000ff;
457 }
458 }
460 // Allocate memory for the packed data
461 bufSize = 1000 + aCount * aSize * 4;
462 packed = (unsigned char *) malloc(bufSize);
463 if(!packed)
464 {
465 free(tmp);
466 self->mError = CTM_OUT_OF_MEMORY;
467 return CTM_FALSE;
468 }
470 // Call LZMA to compress
471 outPropsSize = 5;
472 lzmaAlgo = (self->mCompressionLevel < 1 ? 0 : 1);
473 lzmaRes = LzmaCompress(packed,
474 &bufSize,
475 (const unsigned char *) tmp,
476 aCount * aSize * 4,
477 outProps,
478 &outPropsSize,
479 self->mCompressionLevel, // Level (0-9)
480 0, -1, -1, -1, -1, -1, // Default values (set by level)
481 lzmaAlgo // Algorithm (0 = fast, 1 = normal)
482 );
484 // Free temporary array
485 free(tmp);
487 // Error?
488 if(lzmaRes != SZ_OK)
489 {
490 self->mError = CTM_LZMA_ERROR;
491 free(packed);
492 return CTM_FALSE;
493 }
495 #ifdef __DEBUG_
496 printf("%d->%d bytes\n", aCount * aSize * 4, (int) bufSize);
497 #endif
499 // Write packed data size to the stream
500 _ctmStreamWriteUINT(self, (CTMuint) bufSize);
502 // Write LZMA compression props to the stream
503 _ctmStreamWrite(self, (void *) outProps, 5);
505 // Write the packed data to the stream
506 _ctmStreamWrite(self, (void *) packed, (CTMuint) bufSize);
508 // Free the packed data
509 free(packed);
511 return CTM_TRUE;
512 }