Coverage Report

Created: 2026-09-01 07:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/contrib/contrib-build/libmodplug/src/mmcmp.cpp
Line
Count
Source
1
/*
2
 * This source code is public domain.
3
 *
4
 * Handles unpacking of Powerpack PP20
5
 * Authors: Olivier Lapicque <olivierl@jps.net>
6
*/
7
8
#include "stdafx.h"
9
#include "sndfile.h"
10
11
BOOL PP20_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength);
12
13
#pragma pack(1)
14
typedef struct MMCMPFILEHEADER
15
{
16
  char id[8]; // "ziRCONia"
17
  WORD hdrsize;
18
} MMCMPFILEHEADER, *LPMMCMPFILEHEADER;
19
20
typedef struct MMCMPHEADER
21
{
22
  WORD version;
23
  WORD nblocks;
24
  DWORD filesize;
25
  DWORD blktable;
26
  BYTE glb_comp;
27
  BYTE fmt_comp;
28
} MMCMPHEADER, *LPMMCMPHEADER;
29
30
typedef struct MMCMPBLOCK
31
{
32
  DWORD unpk_size;
33
  DWORD pk_size;
34
  DWORD xor_chk;
35
  WORD sub_blk;
36
  WORD flags;
37
  WORD tt_entries;
38
  USHORT num_bits;
39
} MMCMPBLOCK, *LPMMCMPBLOCK;
40
41
typedef struct MMCMPSUBBLOCK
42
{
43
  DWORD unpk_pos;
44
  DWORD unpk_size;
45
} MMCMPSUBBLOCK, *LPMMCMPSUBBLOCK;
46
#pragma pack()
47
48
// make sure of structure sizes
49
typedef int chk_MMCMPFILEHEADER[(sizeof(struct MMCMPFILEHEADER) == 10) * 2 - 1];
50
typedef int chk_MMCMPHEADER[(sizeof(struct MMCMPHEADER) == 14) * 2 - 1];
51
typedef int chk_MMCMPBLOCK[(sizeof(struct MMCMPBLOCK) == 20) * 2 - 1];
52
typedef int chk_MMCMPSUBBLOCK[(sizeof(struct MMCMPSUBBLOCK) == 8) * 2 - 1];
53
54
0
#define MMCMP_COMP    0x0001
55
0
#define MMCMP_DELTA   0x0002
56
0
#define MMCMP_16BIT   0x0004
57
#define MMCMP_STEREO  0x0100
58
0
#define MMCMP_ABS16   0x0200
59
#define MMCMP_ENDIAN  0x0400
60
61
typedef struct MMCMPBITBUFFER
62
{
63
  UINT bitcount;
64
  DWORD bitbuffer;
65
  LPCBYTE pSrc;
66
  LPCBYTE pEnd;
67
68
  DWORD GetBits(UINT nBits);
69
} MMCMPBITBUFFER;
70
71
72
DWORD MMCMPBITBUFFER::GetBits(UINT nBits)
73
//---------------------------------------
74
0
{
75
0
  DWORD d;
76
0
  if (!nBits) return 0;
77
0
  while (bitcount < 24)
78
0
  {
79
0
    bitbuffer |= ((pSrc < pEnd) ? *pSrc++ : 0) << bitcount;
80
0
    bitcount += 8;
81
0
  }
82
0
  d = bitbuffer & ((1 << nBits) - 1);
83
0
  bitbuffer >>= nBits;
84
0
  bitcount -= nBits;
85
0
  return d;
86
0
}
87
88
//#define MMCMP_LOG
89
90
#ifdef MMCMP_LOG
91
extern void Log(LPCSTR s, ...);
92
#endif
93
94
static const DWORD MMCMP8BitCommands[8] =
95
{
96
  0x01, 0x03, 0x07, 0x0F, 0x1E, 0x3C, 0x78, 0xF8
97
};
98
99
static const UINT MMCMP8BitFetch[8] =
100
{
101
  3, 3, 3, 3, 2, 1, 0, 0
102
};
103
104
static const DWORD MMCMP16BitCommands[16] =
105
{
106
  0x01, 0x03, 0x07, 0x0F, 0x1E, 0x3C, 0x78, 0xF0,
107
  0x1F0, 0x3F0, 0x7F0, 0xFF0, 0x1FF0, 0x3FF0, 0x7FF0, 0xFFF0
108
};
109
110
static const UINT MMCMP16BitFetch[16] =
111
{
112
  4, 4, 4, 4, 3, 2, 1, 0,
113
  0, 0, 0, 0, 0, 0, 0, 0
114
};
115
116
117
static void swap_mfh(LPMMCMPFILEHEADER fh)
118
3.38k
{
119
3.38k
  fh->hdrsize = bswapLE16(fh->hdrsize);
120
3.38k
}
121
122
static void swap_mmh(LPMMCMPHEADER mh)
123
3.38k
{
124
3.38k
  mh->version = bswapLE16(mh->version);
125
3.38k
  mh->nblocks = bswapLE16(mh->nblocks);
126
3.38k
  mh->filesize = bswapLE32(mh->filesize);
127
3.38k
  mh->blktable = bswapLE32(mh->blktable);
128
3.38k
}
129
130
static void swap_block (LPMMCMPBLOCK blk)
131
0
{
132
0
  blk->unpk_size = bswapLE32(blk->unpk_size);
133
0
  blk->pk_size = bswapLE32(blk->pk_size);
134
0
  blk->xor_chk = bswapLE32(blk->xor_chk);
135
0
  blk->sub_blk = bswapLE16(blk->sub_blk);
136
0
  blk->flags = bswapLE16(blk->flags);
137
0
  blk->tt_entries = bswapLE16(blk->tt_entries);
138
0
  blk->num_bits = bswapLE16(blk->num_bits);
139
0
}
140
141
static void swap_subblock (LPMMCMPSUBBLOCK sblk)
142
0
{
143
0
  sblk->unpk_pos = bswapLE32(sblk->unpk_pos);
144
0
  sblk->unpk_size = bswapLE32(sblk->unpk_size);
145
0
}
146
147
148
BOOL MMCMP_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength)
149
//---------------------------------------------------------
150
4.68k
{
151
4.68k
  DWORD dwMemLength;
152
4.68k
  LPCBYTE lpMemFile;
153
4.68k
  LPBYTE pBuffer;
154
4.68k
  LPMMCMPFILEHEADER pmfh;
155
4.68k
  LPMMCMPHEADER pmmh;
156
4.68k
  const DWORD *pblk_table;
157
4.68k
  DWORD dwFileSize;
158
4.68k
  BYTE tmp0[32], tmp1[32];
159
160
4.68k
  if (PP20_Unpack(ppMemFile, pdwMemLength))
161
240
  {
162
240
    return TRUE;
163
240
  }
164
165
4.44k
  dwMemLength = *pdwMemLength;
166
4.44k
  lpMemFile = *ppMemFile;
167
4.44k
  if ((dwMemLength < 256) || (!lpMemFile)) return FALSE;
168
3.38k
  memcpy(tmp0, lpMemFile, 24);
169
3.38k
  pmfh = (LPMMCMPFILEHEADER)(tmp0);
170
3.38k
  pmmh = (LPMMCMPHEADER)(tmp0+10);
171
3.38k
  swap_mfh(pmfh);
172
3.38k
  swap_mmh(pmmh);
173
174
3.38k
  if ((memcmp(pmfh->id,"ziRCONia",8) != 0) || (pmfh->hdrsize < 14)
175
10
   || (!pmmh->nblocks) || (pmmh->filesize < 16) || (pmmh->filesize > 0x8000000)
176
3.38k
   || (pmmh->blktable >= dwMemLength) || (pmmh->blktable + 4*pmmh->nblocks > dwMemLength)) return FALSE;
177
0
  dwFileSize = pmmh->filesize;
178
0
  if ((pBuffer = (LPBYTE)GlobalAllocPtr(GHND, (dwFileSize + 31) & ~15)) == NULL) return FALSE;
179
0
  pblk_table = (const DWORD *)(lpMemFile+pmmh->blktable);
180
0
  for (UINT nBlock=0; nBlock<pmmh->nblocks; nBlock++)
181
0
  {
182
0
    DWORD dwMemPos = bswapLE32(pblk_table[nBlock]);
183
0
    DWORD dwSubPos;
184
0
    LPMMCMPBLOCK pblk;
185
0
    LPMMCMPSUBBLOCK psubblk;
186
187
0
    if (dwMemPos >= dwMemLength - 20) break;
188
0
    memcpy(tmp1, lpMemFile+dwMemPos, 28);
189
0
    pblk = (LPMMCMPBLOCK)(tmp1);
190
0
    psubblk = (LPMMCMPSUBBLOCK)(tmp1+20);
191
0
    swap_block(pblk);
192
0
    swap_subblock(psubblk);
193
194
0
    if (dwMemPos + 20 + pblk->sub_blk*8 >= dwMemLength) break;
195
0
    dwSubPos = dwMemPos + 20;
196
0
    dwMemPos += 20 + pblk->sub_blk*8;
197
#ifdef MMCMP_LOG
198
    Log("block %d: flags=%04X sub_blocks=%d", nBlock, (UINT)pblk->flags, (UINT)pblk->sub_blk);
199
    Log(" pksize=%d unpksize=%d", pblk->pk_size, pblk->unpk_size);
200
    Log(" tt_entries=%d num_bits=%d\n", pblk->tt_entries, pblk->num_bits);
201
#endif
202
    // Data is not packed
203
0
    if (!(pblk->flags & MMCMP_COMP))
204
0
    {
205
0
      for (UINT i=0; i<pblk->sub_blk; i++)
206
0
      {
207
0
        if ((psubblk->unpk_pos >= dwFileSize) ||
208
0
          (psubblk->unpk_size >= dwFileSize) ||
209
0
          (psubblk->unpk_size > dwFileSize - psubblk->unpk_pos) ||
210
0
          psubblk->unpk_size > dwMemLength - dwMemPos) break;
211
#ifdef MMCMP_LOG
212
        Log("  Unpacked sub-block %d: offset %d, size=%d\n", i, psubblk->unpk_pos, psubblk->unpk_size);
213
#endif
214
0
        memcpy(pBuffer+psubblk->unpk_pos, lpMemFile+dwMemPos, psubblk->unpk_size);
215
0
        dwMemPos += psubblk->unpk_size;
216
0
        memcpy(tmp1+20,lpMemFile+dwSubPos+i*8,8);
217
0
        swap_subblock(psubblk);
218
0
      }
219
0
    } else
220
    // Data is 16-bit packed
221
0
    if (pblk->flags & MMCMP_16BIT && pblk->num_bits < 16)
222
0
    {
223
0
      MMCMPBITBUFFER bb;
224
0
      LPWORD pDest = (LPWORD)(pBuffer + psubblk->unpk_pos);
225
0
      DWORD dwSize = psubblk->unpk_size >> 1;
226
0
      DWORD dwPos = 0;
227
0
      UINT numbits = pblk->num_bits;
228
0
      UINT subblk = 0, oldval = 0;
229
230
0
      if (dwSize * 2 > dwFileSize-psubblk->unpk_pos ||
231
0
        psubblk->unpk_pos > dwMemLength-dwMemPos)
232
0
        break;
233
234
#ifdef MMCMP_LOG
235
      Log("  16-bit block: pos=%d size=%d ", psubblk->unpk_pos, psubblk->unpk_size);
236
      if (pblk->flags & MMCMP_DELTA) Log("DELTA ");
237
      if (pblk->flags & MMCMP_ABS16) Log("ABS16 ");
238
      Log("\n");
239
#endif
240
0
      bb.bitcount = 0;
241
0
      bb.bitbuffer = 0;
242
0
      bb.pSrc = lpMemFile+dwMemPos+pblk->tt_entries;
243
0
      bb.pEnd = lpMemFile+dwMemPos+pblk->pk_size;
244
0
      if (bb.pEnd > lpMemFile+dwMemLength)
245
0
        bb.pEnd = lpMemFile+dwMemLength;
246
0
      while (subblk < pblk->sub_blk)
247
0
      {
248
0
        UINT newval = 0x10000;
249
0
        DWORD d = bb.GetBits(numbits+1);
250
251
0
        if ((psubblk->unpk_pos >= dwFileSize) ||
252
0
          (psubblk->unpk_size >= dwFileSize) ||
253
0
          (psubblk->unpk_size > dwFileSize - psubblk->unpk_pos))
254
0
          dwPos = dwSize;
255
256
0
        if (d >= MMCMP16BitCommands[numbits])
257
0
        {
258
0
          UINT nFetch = MMCMP16BitFetch[numbits];
259
0
          UINT newbits = bb.GetBits(nFetch) + ((d - MMCMP16BitCommands[numbits]) << nFetch);
260
0
          if (newbits != numbits)
261
0
          {
262
0
            numbits = newbits & 0x0F;
263
0
          } else
264
0
          {
265
0
            if ((d = bb.GetBits(4)) == 0x0F)
266
0
            {
267
0
              if (bb.GetBits(1)) break;
268
0
              newval = 0xFFFF;
269
0
            } else
270
0
            {
271
0
              newval = 0xFFF0 + d;
272
0
            }
273
0
          }
274
0
        } else
275
0
        {
276
0
          newval = d;
277
0
        }
278
0
        if (newval < 0x10000 && dwPos < dwSize)
279
0
        {
280
0
          newval = (newval & 1) ? (UINT)(-(LONG)((newval+1) >> 1)) : (UINT)(newval >> 1);
281
0
          if (pblk->flags & MMCMP_DELTA)
282
0
          {
283
0
            newval += oldval;
284
0
            oldval = newval;
285
0
          } else
286
0
          if (!(pblk->flags & MMCMP_ABS16))
287
0
          {
288
0
            newval ^= 0x8000;
289
0
          }
290
0
          WORD swapped = (WORD)newval;
291
0
          pDest[dwPos++] = bswapLE16(swapped);
292
0
        }
293
0
        if (dwPos >= dwSize)
294
0
        {
295
0
          subblk++;
296
0
          memcpy(tmp1+20,lpMemFile+dwSubPos+subblk*8,8);
297
0
          swap_subblock(psubblk);
298
0
          dwPos = 0;
299
0
          dwSize = psubblk->unpk_size >> 1;
300
0
          if ( psubblk->unpk_pos >= dwFileSize ||
301
0
            dwSize * 2 > dwFileSize ) {
302
0
            break;
303
0
          }
304
0
          pDest = (LPWORD)(pBuffer + psubblk->unpk_pos);
305
0
        }
306
0
      }
307
0
    } else if (pblk->num_bits < 8)
308
    // Data is 8-bit packed
309
0
    {
310
0
      MMCMPBITBUFFER bb;
311
0
      LPBYTE pDest = pBuffer + psubblk->unpk_pos;
312
0
      DWORD dwSize = psubblk->unpk_size;
313
0
      DWORD dwPos = 0;
314
0
      UINT numbits = pblk->num_bits;
315
0
      UINT subblk = 0, oldval = 0;
316
0
      LPCBYTE ptable = lpMemFile+dwMemPos;
317
318
0
      if (dwSize > dwFileSize-psubblk->unpk_pos ||
319
0
        psubblk->unpk_pos > dwMemLength-dwMemPos)
320
0
        break;
321
322
0
      bb.bitcount = 0;
323
0
      bb.bitbuffer = 0;
324
0
      bb.pSrc = lpMemFile+dwMemPos+pblk->tt_entries;
325
0
      bb.pEnd = lpMemFile+dwMemPos+pblk->pk_size;
326
0
      if (bb.pEnd > lpMemFile+dwMemLength)
327
0
        bb.pEnd = lpMemFile+dwMemLength; 
328
0
      while (subblk < pblk->sub_blk)
329
0
      {
330
0
        UINT newval = 0x100;
331
0
        DWORD d = bb.GetBits(numbits+1);
332
333
0
        if ((psubblk->unpk_pos >= dwFileSize) ||
334
0
          (psubblk->unpk_size >= dwFileSize) ||
335
0
          (psubblk->unpk_size > dwFileSize - (psubblk->unpk_pos)))
336
0
          dwPos = dwSize;
337
338
0
        if (d >= MMCMP8BitCommands[numbits])
339
0
        {
340
0
          UINT nFetch = MMCMP8BitFetch[numbits];
341
0
          UINT newbits = bb.GetBits(nFetch) + ((d - MMCMP8BitCommands[numbits]) << nFetch);
342
0
          if (newbits != numbits)
343
0
          {
344
0
            numbits = newbits & 0x07;
345
0
          } else
346
0
          {
347
0
            if ((d = bb.GetBits(3)) == 7)
348
0
            {
349
0
              if (bb.GetBits(1)) break;
350
0
              newval = 0xFF;
351
0
            } else
352
0
            {
353
0
              newval = 0xF8 + d;
354
0
            }
355
0
          }
356
0
        } else
357
0
        {
358
0
          newval = d;
359
0
        }
360
0
        if (newval < 0x100 && dwPos < dwSize && dwMemPos < dwMemLength - newval)
361
0
        {
362
0
          int n = ptable[newval];
363
0
          if (pblk->flags & MMCMP_DELTA)
364
0
          {
365
0
            n += oldval;
366
0
            oldval = n;
367
0
          }
368
0
          pDest[dwPos++] = (BYTE)n;
369
0
        }
370
0
        if (dwPos >= dwSize)
371
0
        {
372
0
          subblk++;
373
0
          memcpy(tmp1+20,lpMemFile+dwSubPos+subblk*8,8);
374
0
          swap_subblock(psubblk);
375
0
          dwPos = 0;
376
0
          dwSize = psubblk->unpk_size;
377
0
          if ( psubblk->unpk_pos >= dwFileSize ||
378
0
            dwSize > dwFileSize )
379
0
            break;
380
0
          pDest = pBuffer + psubblk->unpk_pos;
381
0
        }
382
0
      }
383
0
    } else
384
0
    {
385
0
      GlobalFreePtr(pBuffer);
386
0
      return FALSE;
387
0
    }
388
0
  }
389
0
  *ppMemFile = pBuffer;
390
0
  *pdwMemLength = dwFileSize;
391
0
  return TRUE;
392
0
}
393
394
395
//////////////////////////////////////////////////////////////////////////////
396
//
397
// PowerPack PP20 Unpacker
398
//
399
400
typedef struct _PPBITBUFFER
401
{
402
  UINT bitcount;
403
  ULONG bitbuffer;
404
  LPCBYTE pStart;
405
  LPCBYTE pSrc;
406
407
  ULONG GetBits(UINT n);
408
} PPBITBUFFER;
409
410
411
ULONG PPBITBUFFER::GetBits(UINT n)
412
2.14M
{
413
2.14M
  ULONG result = 0;
414
415
8.68M
  for (UINT i=0; i<n; i++)
416
6.54M
  {
417
6.54M
    if (!bitcount)
418
817k
    {
419
817k
      bitcount = 8;
420
817k
      if (pSrc != pStart) pSrc--;
421
817k
      bitbuffer = *pSrc;
422
817k
    }
423
6.54M
    result = (result<<1) | (bitbuffer&1);
424
6.54M
    bitbuffer >>= 1;
425
6.54M
    bitcount--;
426
6.54M
  }
427
2.14M
  return result;
428
2.14M
}
429
430
431
static VOID PP20_DoUnpack(const BYTE *pSrc, UINT nSrcLen, BYTE *pDst, UINT nDstLen)
432
240
{
433
240
  PPBITBUFFER BitBuffer;
434
240
  ULONG nBytesLeft;
435
436
240
  BitBuffer.pStart = pSrc;
437
240
  BitBuffer.pSrc = pSrc + nSrcLen - 4;
438
240
  BitBuffer.bitbuffer = 0;
439
240
  BitBuffer.bitcount = 0;
440
240
  BitBuffer.GetBits(pSrc[nSrcLen-1]);
441
240
  nBytesLeft = nDstLen;
442
470k
  while (nBytesLeft > 0)
443
470k
  {
444
470k
    if (!BitBuffer.GetBits(1))
445
326k
    {
446
326k
      UINT n = 1;
447
336k
      while (n < nBytesLeft)
448
336k
      {
449
336k
        UINT code = BitBuffer.GetBits(2);
450
336k
        n += code;
451
336k
        if (code != 3) break;
452
336k
      }
453
691k
      for (UINT i=0; i<n; i++)
454
365k
      {
455
365k
        pDst[nBytesLeft - 1] = (BYTE)BitBuffer.GetBits(8);
456
365k
        if (!--nBytesLeft) break;
457
365k
      }
458
326k
      if (!nBytesLeft) break;
459
326k
    }
460
470k
    {
461
470k
      UINT n = BitBuffer.GetBits(2)+1;
462
470k
      UINT nbits = pSrc[n-1];
463
470k
      UINT nofs;
464
470k
      if (n==4)
465
7.27k
      {
466
7.27k
        nofs = BitBuffer.GetBits( (BitBuffer.GetBits(1)) ? nbits : 7 );
467
20.7k
        while (n < nBytesLeft)
468
20.7k
        {
469
20.7k
          UINT code = BitBuffer.GetBits(3);
470
20.7k
          n += code;
471
20.7k
          if (code != 7) break;
472
20.7k
        }
473
7.27k
      } else
474
462k
      {
475
462k
        nofs = BitBuffer.GetBits(nbits);
476
462k
      }
477
1.55M
      for (UINT i=0; i<=n; i++)
478
1.08M
      {
479
1.08M
        pDst[nBytesLeft-1] = (nBytesLeft+nofs < nDstLen) ? pDst[nBytesLeft+nofs] : 0;
480
1.08M
        if (!--nBytesLeft) break;
481
1.08M
      }
482
470k
    }
483
470k
  }
484
240
}
485
486
487
BOOL PP20_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength)
488
4.68k
{
489
4.68k
  DWORD dwMemLength = *pdwMemLength;
490
4.68k
  LPCBYTE lpMemFile = *ppMemFile;
491
4.68k
  DWORD dwDstLen;
492
4.68k
  LPBYTE pBuffer;
493
494
4.68k
  if ((!lpMemFile) || (dwMemLength < 256) || (memcmp(lpMemFile,"PP20",4) != 0)) return FALSE;
495
258
  dwDstLen = (lpMemFile[dwMemLength-4]<<16) | (lpMemFile[dwMemLength-3]<<8) | (lpMemFile[dwMemLength-2]);
496
  //Log("PP20 detected: Packed length=%d, Unpacked length=%d\n", dwMemLength, dwDstLen);
497
258
  if ((dwDstLen < 512) || (dwDstLen > 0x400000) || (dwDstLen > 16*dwMemLength)) return FALSE;
498
240
  if ((pBuffer = (LPBYTE)GlobalAllocPtr(GHND, (dwDstLen + 31) & ~15)) == NULL) return FALSE;
499
240
  PP20_DoUnpack(lpMemFile+4, dwMemLength-4, pBuffer, dwDstLen);
500
240
  *ppMemFile = pBuffer;
501
240
  *pdwMemLength = dwDstLen;
502
240
  return TRUE;
503
240
}