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