DSMCC  17.9.0
 All Data Structures Files Functions Typedefs
moduleDecompress.c
Go to the documentation of this file.
1 /*******************************************************************************
2  * Copyright © 2014 The DTVKit Open Software Foundation Ltd (www.dtvkit.org)
3  * Copyright © 2004 Ocean Blue Software Ltd
4  * Copyright © 2001 Koninklijke Philips Electronics N.V
5  *
6  * This file is part of a DTVKit Software Component
7  * You are permitted to copy, modify or distribute this file subject to the terms
8  * of the DTVKit 1.0 Licence which can be found in licence.txt or at www.dtvkit.org
9  *
10  * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
11  * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
12  * OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
13  *
14  * If you or your organisation is not a member of DTVKit then you have access
15  * to this source code outside of the terms of the licence agreement
16  * and you are expected to delete this and any associated files immediately.
17  * Further information on DTVKit, membership and terms can be found at www.dtvkit.org
18  *******************************************************************************/
26 /*---includes for this file--------------------------------------------------*/
27 #include <string.h> /* for memset() */
28 #include "clDsmSystem.h"
29 #include "moduleDecompress.h"
30 
31 #include "moduleData.h"
32 #include "zlib.h"
33 
34 /*------------------------------- Local Macros -------------------------------*/
35 
36 #define ZLIB_HEAP_NUM_BYTES (((U32BIT)1 << 15 /*MAX_WBITS*/) + (1024 * 32))
37 #define ZLIB_HEAP_NUM_PTRS(sz) ((sz) + sizeof(voidpf) - 1) / sizeof(voidpf)
38 
39 /*------------------------------ Exported Data -----------------------------*/
40 
41 
42 /*--------------------------------Local Types --------------------------------*/
43 
44 typedef voidpf Data;
45 typedef Data *P_Data;
46 
47 typedef struct s_ZlibHeap
48 {
49  P_Data ptr;
50  P_Data top;
51 } S_ZlibHeap;
52 
53 /*------------------------------- Local Statics ------------------------------*/
54 
55 
56 /*------------------- local prototypes/forward declarations ------------------*/
57 
58 static voidpf dsmZcalloc( voidpf opaque, uInt items, uInt size );
59 static void dsmZcfree( voidpf opaque, voidpf address );
60 
61 
62 /*---------------------------- Exported Functions ----------------------------*/
63 
64 /* /////////////////////////////////////////////////////////////////////////////
65 // moduleDecompressInit
66 //
68 void moduleDecompressInit( P_DsmCoreInst idp )
69 {
70  P_ZlibHeap pZlibHeap;
71  U32BIT size;
72  dsmDP3(("moduleDecompressInit()\n"));
73  dsmAssert((idp != NULL));
74 
75  size = ZLIB_HEAP_NUM_PTRS( ZLIB_HEAP_NUM_BYTES );
76 
77  pZlibHeap = (P_ZlibHeap)idp->setup.allocFunc( sizeof(S_ZlibHeap) + (size * sizeof(voidpf)) );
78  idp->pZlibHeap = pZlibHeap;
79 
80  pZlibHeap->ptr = (voidpf)(pZlibHeap + 1);
81  pZlibHeap->top = pZlibHeap->ptr + size;
82 
83  /* -- Output some useful info about the zlib heap */
84  dsmDP3(("\nINFO: ZLIB HEAP = %p-%p, size %u bytes\n", pZlibHeap->ptr, pZlibHeap->top, ZLIB_HEAP_NUM_BYTES));
85 }
86 
87 /* /////////////////////////////////////////////////////////////////////////////
88 // moduleDecompress
89 //
91 E_DscError moduleDecompress( P_DsmCoreInst idp,
92  /*I*/ U32BIT compressedSize, U32BIT decompressedSize,
93  /*IO*/P_ModuleData hCompModuleData,
94  /*O*/ P_ModuleData *ppModuleData )
95 {
96  E_DscError err;
97  P_ModuleData pModuleData;
98  MemSeqRef msCompModuleData, msDecompModuleData;
99  U8BIT *pCompModuleData;
100  U8BIT *pDecompModuleData;
101  U32BIT compNumBytesContig, decompNumBytesContig;
102  BOOLEAN decompressOk = TRUE;
103  int zlibErr;
104  z_stream zStream;
105 
106  dsmDP3(("moduleDecompress( %u, %u, %p )\n",
107  compressedSize, decompressedSize, hCompModuleData));
108  dsmAssert((idp != NULL));
109  dsmAssert((hCompModuleData != NULL));
110  dsmAssert((ppModuleData != NULL));
111  dsmAssert((compressedSize > 0));
112 
113 
114  *ppModuleData = NULL;
115 
116  if (compressedSize == 0)
117  {
118  /* -- Should never get passed a 0 compressed size */
119 
120  err = CLDSM_ERR_INTERNAL;
121  goto _return;
122  }
123 
124  if (decompressedSize == 0)
125  {
126  /*
127  -- Decompressed module size of 0 may be possible (eg. for modules
128  -- listed in a DII that are not actually used). Since we cannot
129  -- have a 0 length data area, create one with a nominal length
130  -- (of 1) instead.
131  */
132  err = moduleDataCreate( idp, /*nominal length*/ 1, &pModuleData );
133  }
134  else
135  {
136  err = moduleDataCreate( idp, decompressedSize, &pModuleData );
137  }
138 
139  if (!err)
140  {
141  /* -- Open compressed and decompressed moduleData areas */
142  CHECK_MEM_ERR(
143  memSeqOpen( MEM_CONTEXT, (MemHandle)moduleDataPtr(hCompModuleData), 0, compressedSize,
144  FALSE, &msCompModuleData )
145  );
146  CHECK_MEM_ERR(
147  memSeqOpen( MEM_CONTEXT, (MemHandle)moduleDataPtr(pModuleData), 0, decompressedSize,
148  FALSE, &msDecompModuleData )
149  );
150 
151  zStream.opaque = (voidpf)idp;
152 
153  zStream.zalloc = (alloc_func)dsmZcalloc;
154  zStream.zfree = (free_func)dsmZcfree;
155 
156  zStream.next_in = Z_NULL;
157  zStream.avail_in = 0;
158  zStream.next_out = Z_NULL;
159  zStream.avail_out = 0;
160 
161  zlibErr = inflateInit(&zStream);
162  DEBUG_CHK( zlibErr == Z_OK,
163  dsmDP1(("ERROR: zlib inflateInit: %u\n", err)));
164 
165  #ifdef MEM_CONTIGUOUS
166  /* Get input data area */
167  memSeqAccessContig( msCompModuleData, &pCompModuleData, &compNumBytesContig );
168  zStream.next_in = (Bytef *)pCompModuleData;
169  zStream.avail_in = (uInt)compNumBytesContig;
170  /* Get output data area */
171  memSeqAccessContig( msDecompModuleData, &pDecompModuleData, &decompNumBytesContig );
172  zStream.next_out = (Bytef *)pDecompModuleData;
173  zStream.avail_out = (uInt)decompNumBytesContig;
174  dsmDP3(("Pre-inflate stream -> n_i: %p, a_i: %u, n_o: %p, a_o: %u\n",
175  zStream.next_in, zStream.avail_in, zStream.next_out, zStream.avail_out));
176 
177  /* ZLIB - inflate in one go! */
178  zlibErr = inflate( &zStream, Z_FINISH );
179 
180  #else
181  while (zlibErr == Z_OK)
182  {
183  if (zStream.avail_in == 0)
184  {
185  /* -- Get next contig 'block' of compressed data */
186  memSeqAccessContig( msCompModuleData, &pCompModuleData,
187  &compNumBytesContig );
188  zStream.next_in = (Bytef *)pCompModuleData;
189  zStream.avail_in = (uInt)compNumBytesContig;
190  }
191  if (zStream.avail_out == 0)
192  {
193  /* -- Get next contig 'block' in decompressed memory area */
194  memSeqAccessContig( msDecompModuleData, &pDecompModuleData,
195  &decompNumBytesContig );
196  zStream.next_out = (Bytef *)pDecompModuleData;
197  zStream.avail_out = (uInt)decompNumBytesContig;
198  }
199  dsmDP4(("Pre-inflate stream -> n_i: %p, a_i: %u, n_o: %p, a_o: %u\n",
200  zStream.next_in, zStream.avail_in, zStream.next_out, zStream.avail_out));
201  zlibErr = inflate( &zStream, Z_SYNC_FLUSH );
202  dsmDP4(("Post-inflate stream -> n_i: %p, a_i: %u, n_o: %p, a_o: %u\n",
203  zStream.next_in, zStream.avail_in, zStream.next_out, zStream.avail_out));
204  }
205  #endif
206 
207  if (zlibErr != Z_STREAM_END)
208  {
209  decompressOk = FALSE;
210  dsmDP1(("DATA ERROR: ZLIB uncompress error: %d\n", zlibErr));
211  }
212 
213  zlibErr = inflateEnd( &zStream );
214  DEBUG_CHK( zlibErr == Z_OK,
215  dsmDP1(("ERROR: zlib inflateEnd: %u\n", err)));
216 
217  /* -- Close moduleData areas */
218  memSeqClose( msCompModuleData );
219  memSeqClose( msDecompModuleData );
220 
221  if (decompressOk)
222  {
223  L2_DATA_CHK( zStream.total_out == decompressedSize,
224 
225  dsmDP1(("DATA ERROR: DII decompress size = %u, ",
226  decompressedSize));
227  dsmDP1(("zlib decompress size = %u\n", zStream.total_out)),
228 
229  moduleDataDestroy( idp, &pModuleData );
230  goto _return );
231 
232  /* -- Return decompressed moduleData area handle */
233  *ppModuleData = pModuleData;
234  }
235  else
236  {
237  /* -- Destroy decompressed data area */
238  moduleDataDestroy( idp, &pModuleData );
239  }
240  }
241 
242 _return:
243  DEBUG_CHK( err == CLDSM_OK,
244  dsmDP1(("ERROR: moduleDecompress: %u\n", err)));
245  dsmDP3(("exit moduleDecompress -> rtn: %u\n", err));
246  return err;
247 }
248 
249 /*------------------------------ Local Functions -----------------------------*/
250 
251 /*
252 -- ZLIB HEAP OPERATION:
253 --
254 -- The zlib heap is treated as a simple stack. It works most efficiently if
255 -- items are freed in the reverse order from which they were allocated (which
256 -- appears to be valid for the way zlib allocates/frees memory).
257 --
258 -- Each allocated item is put on the current top of the heap. When an item
259 -- is freed, if it is not at the top of the heap it is marked as empty (by
260 -- setting it's blockSize to 0), if it is at the top of the heap it is removed
261 -- along with any items below it also marked as empty.
262 --
263 -- Memory block sizes are rounded up to an integer number of words.
264 -- Each memory block has the blockSize value stored at the start (bottom) and
265 -- memStartPtr stored at the end (top) with the allocated memory between these.
266 -- Actual heap amount used for each memory block is blockSize + 2.
267 --
268 -- Note that memStartPtr points to the start of the usable memory in the block
269 -- (ie. the address above where the blocksize is stored).
270 -- TODO: NK 16/10/01 - This is rather nasty and non-obvious - revisit.
271 */
272 static voidpf dsmZcalloc( voidpf opaque, uInt items, uInt size )
273 {
274  P_DsmCoreInst idp = (P_DsmCoreInst)opaque;
275  P_ZlibHeap pZlibHeap = idp->pZlibHeap;
276  U_PARAM blksize;
277  voidpf retval;
278 
279  dsmDP4(("dsmZcalloc( %u, %u )\n", items, size));
280 
281 # ifndef NDEBUG
282  /*** DEBUG TEST FOR WORST CASE ZLIB HEAP REQS
283  *** zlib does not specify its worst case memory reqs exactly. Limited 'dumb'
284  *** testing (ie. without attempting to understand zlib) on compressed DMC-CC
285  *** modules has shown that the memory reqs vary according to the data being
286  *** compressed. There is only one alloc which varies significantly in the
287  *** amount of memory allocated. So far it has never been observed to allocate
288  *** more than the size here! */
289  if ((size == 0x4) && (items > 0x13c))
290  {
291  dsmDP1(("\n************************************\n"));
292  dsmDP1(("************************************\n"));
293  dsmDP1(("* ZLIB HEAP ITEMS > 0x13c: %x *\n", items));
294  dsmDP1(("************************************\n"));
295  dsmDP1(("************************************\n\n"));
296  }
297 
298  if (size == 0)
299  {
300  dsmDP1(("\n************************************\n"));
301  dsmDP1(("************************************\n"));
302  dsmDP1(("* ZLIB HEAP, size == 0\n"));
303  dsmDP1(("************************************\n"));
304  dsmDP1(("************************************\n\n"));
305  }
306 
307  if (items == 0)
308  {
309  dsmDP1(("\n************************************\n"));
310  dsmDP1(("************************************\n"));
311  dsmDP1(("* ZLIB HEAP, items == 0\n"));
312  dsmDP1(("************************************\n"));
313  dsmDP1(("************************************\n\n"));
314  }
315 # endif
316 
317  if (pZlibHeap == NULL)
318  {
319  /* -- Error - re-initialise zlib heap */
320  dsmDP1(("ERROR: Local zlib heap error\n"));
321  moduleDecompressInit( idp );
322  }
323 
324  blksize.ptr = NULL;
325  blksize.u32 = ZLIB_HEAP_NUM_PTRS(items * size);
326 
327  /* Make sure we are allocating a non-zero size block */
328  if (blksize.u32 == 0)
329  {
330  dsmDP1(("ERROR: Local zlib attempting to allocate zero length block.\n"));
331  retval = NULL;
332  }
333  else if ((pZlibHeap->ptr + blksize.u32 + 2) >= pZlibHeap->top)
334  {
335  /* -- Error - heap full */
336  dsmDP1(("ERROR: Local zlib heap overflow\n"));
337  retval = NULL;
338  }
339  else
340  {
341  *pZlibHeap->ptr++ = blksize.ptr;
342  retval = (voidpf)pZlibHeap->ptr;
343 
344  pZlibHeap->ptr += blksize.u32;
345 
346  /* -- Clear memory block to zero */
347  memset(retval, '\0', sizeof(Data) * blksize.u32);
348 
349  /* -- Store retval value at top of block */
350  *pZlibHeap->ptr = retval;
351 
352  /* -- Point to free space ready for next block */
353  pZlibHeap->ptr++;
354  }
355 
356  dsmDP4(("exit dsmZcalloc -> rtn: %p\n", retval));
357  return(retval);
358 }
359 
360 static void dsmZcfree( voidpf opaque, voidpf address )
361 {
362  P_DsmCoreInst idp = (P_DsmCoreInst)opaque;
363  P_ZlibHeap pZlibHeap = idp->pZlibHeap;
364  P_Data blockStart = ((P_Data)address) - 1;
365  P_Data topBlockStart;
366 
367  dsmDP4(("dsmZcfree( %p )\n", address));
368  dsmAssert((address != NULL));
369 
370  if (pZlibHeap->ptr <= (P_Data)(pZlibHeap+1))
371  {
372  /* -- Error - re-initialise zlib heap */
373  dsmDP1(("ERROR: Local zlib heap underflow\n"));
374  moduleDecompressInit( idp );
375  }
376  else if (blockStart < (P_Data)(pZlibHeap+1) || blockStart > (pZlibHeap->ptr - 2))
377  {
378  /* blockStart is not within used heap (nb. Zero length blocks allowed) */
379  dsmDP1(("ERROR: Attempt to free illegal zlib heap address\n"));
380  }
381  else
382  {
383  /* -- Zero blockSize for this block to indicate it is empty/free */
384  *blockStart = 0;
385 
386  /* -- Find start of current top stack block */
387  topBlockStart = ((P_Data)(*(pZlibHeap->ptr - 1))) - 1;
388 
389  if (blockStart == topBlockStart)
390  {
391  /* -- This block is at top of heap so remove this and any empty/free blocks below */
392  while (*topBlockStart == 0)
393  {
394  /* -- Remove top block */
395  pZlibHeap->ptr = topBlockStart;
396 
397  if (pZlibHeap->ptr <= (P_Data)(pZlibHeap+1))
398  {
399  break;
400  }
401  /* -- Find start of new top block */
402  topBlockStart = ((P_Data)(*(topBlockStart - 1))) - 1;
403  }
404  }
405  }
406 }
407 
408 /*----------------------------------------------------------------------------*/
General include file for clDsm library internal definitions.
Header to the moduleDecompress module.
Header to the moduleData module.