Diffstat (limited to 'core/multimedia/opieplayer/modplug/mmcmp.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | core/multimedia/opieplayer/modplug/mmcmp.cpp | 409 |
1 files changed, 409 insertions, 0 deletions
diff --git a/core/multimedia/opieplayer/modplug/mmcmp.cpp b/core/multimedia/opieplayer/modplug/mmcmp.cpp new file mode 100644 index 0000000..8c32eb2 --- a/dev/null +++ b/core/multimedia/opieplayer/modplug/mmcmp.cpp | |||
@@ -0,0 +1,409 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and modify it | ||
3 | * under the terms of the GNU General Public License as published by the | ||
4 | * Free Software Foundation; either version 2 of the license or (at your | ||
5 | * option) any later version. | ||
6 | * | ||
7 | * Authors: Olivier Lapicque <olivierl@jps.net> | ||
8 | */ | ||
9 | |||
10 | #include "stdafx.h" | ||
11 | #include "sndfile.h" | ||
12 | |||
13 | BOOL PP20_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength); | ||
14 | |||
15 | typedef struct MMCMPFILEHEADER | ||
16 | { | ||
17 | DWORD id_ziRC;// "ziRC" | ||
18 | DWORD id_ONia;// "ONia" | ||
19 | WORD hdrsize; | ||
20 | } Q_PACKED MMCMPFILEHEADER, *LPMMCMPFILEHEADER; | ||
21 | |||
22 | typedef struct MMCMPHEADER | ||
23 | { | ||
24 | WORD version; | ||
25 | WORD nblocks; | ||
26 | DWORD filesize; | ||
27 | DWORD blktable; | ||
28 | BYTE glb_comp; | ||
29 | BYTE fmt_comp; | ||
30 | } Q_PACKED MMCMPHEADER, *LPMMCMPHEADER; | ||
31 | |||
32 | typedef struct MMCMPBLOCK | ||
33 | { | ||
34 | DWORD unpk_size; | ||
35 | DWORD pk_size; | ||
36 | DWORD xor_chk; | ||
37 | WORD sub_blk; | ||
38 | WORD flags; | ||
39 | WORD tt_entries; | ||
40 | WORD num_bits; | ||
41 | } Q_PACKED MMCMPBLOCK, *LPMMCMPBLOCK; | ||
42 | |||
43 | typedef struct MMCMPSUBBLOCK | ||
44 | { | ||
45 | DWORD unpk_pos; | ||
46 | DWORD unpk_size; | ||
47 | } Q_PACKED MMCMPSUBBLOCK, *LPMMCMPSUBBLOCK; | ||
48 | |||
49 | #define MMCMP_COMP 0x0001 | ||
50 | #define MMCMP_DELTA 0x0002 | ||
51 | #define MMCMP_16BIT 0x0004 | ||
52 | #define MMCMP_STEREO0x0100 | ||
53 | #define MMCMP_ABS16 0x0200 | ||
54 | #define MMCMP_ENDIAN0x0400 | ||
55 | |||
56 | typedef struct MMCMPBITBUFFER | ||
57 | { | ||
58 | UINT bitcount; | ||
59 | DWORD bitbuffer; | ||
60 | LPCBYTE pSrc; | ||
61 | LPCBYTE pEnd; | ||
62 | |||
63 | DWORD GetBits(UINT nBits); | ||
64 | } Q_PACKED MMCMPBITBUFFER; | ||
65 | |||
66 | |||
67 | DWORD MMCMPBITBUFFER::GetBits(UINT nBits) | ||
68 | //--------------------------------------- | ||
69 | { | ||
70 | DWORD d; | ||
71 | if (!nBits) return 0; | ||
72 | while (bitcount < 24) | ||
73 | { | ||
74 | bitbuffer |= ((pSrc < pEnd) ? *pSrc++ : 0) << bitcount; | ||
75 | bitcount += 8; | ||
76 | } | ||
77 | d = bitbuffer & ((1 << nBits) - 1); | ||
78 | bitbuffer >>= nBits; | ||
79 | bitcount -= nBits; | ||
80 | return d; | ||
81 | } | ||
82 | |||
83 | //#define MMCMP_LOG | ||
84 | |||
85 | #ifdef MMCMP_LOG | ||
86 | extern void Log(LPCSTR s, ...); | ||
87 | #endif | ||
88 | |||
89 | const DWORD MMCMP8BitCommands[8] = | ||
90 | { | ||
91 | 0x01, 0x03, 0x07, 0x0F, 0x1E, 0x3C,0x78, 0xF8 | ||
92 | }; | ||
93 | |||
94 | const UINT MMCMP8BitFetch[8] = | ||
95 | { | ||
96 | 3, 3, 3, 3, 2, 1, 0, 0 | ||
97 | }; | ||
98 | |||
99 | const DWORD MMCMP16BitCommands[16] = | ||
100 | { | ||
101 | 0x01, 0x03, 0x07, 0x0F, 0x1E, 0x3C,0x78, 0xF0, | ||
102 | 0x1F0, 0x3F0, 0x7F0, 0xFF0, 0x1FF0, 0x3FF0, 0x7FF0, 0xFFF0 | ||
103 | }; | ||
104 | |||
105 | const UINT MMCMP16BitFetch[16] = | ||
106 | { | ||
107 | 4, 4, 4, 4, 3, 2, 1, 0, | ||
108 | 0, 0, 0, 0, 0, 0, 0, 0 | ||
109 | }; | ||
110 | |||
111 | |||
112 | BOOL MMCMP_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength) | ||
113 | //--------------------------------------------------------- | ||
114 | { | ||
115 | DWORD dwMemLength = *pdwMemLength; | ||
116 | LPCBYTE lpMemFile = *ppMemFile; | ||
117 | LPBYTE pBuffer; | ||
118 | LPMMCMPFILEHEADER pmfh = (LPMMCMPFILEHEADER)(lpMemFile); | ||
119 | LPMMCMPHEADER pmmh = (LPMMCMPHEADER)(lpMemFile+10); | ||
120 | LPDWORD pblk_table; | ||
121 | DWORD dwFileSize; | ||
122 | |||
123 | if (PP20_Unpack(ppMemFile, pdwMemLength)) | ||
124 | { | ||
125 | return TRUE; | ||
126 | } | ||
127 | if ((dwMemLength < 256) || (!pmfh) || (pmfh->id_ziRC != 0x4352697A) || (pmfh->id_ONia != 0x61694e4f) || (pmfh->hdrsize < 14) | ||
128 | || (!pmmh->nblocks) || (pmmh->filesize < 16) || (pmmh->filesize > 0x8000000) | ||
129 | || (pmmh->blktable >= dwMemLength) || (pmmh->blktable + 4*pmmh->nblocks > dwMemLength)) return FALSE; | ||
130 | dwFileSize = pmmh->filesize; | ||
131 | if ((pBuffer = (LPBYTE)GlobalAllocPtr(GHND, (dwFileSize + 31) & ~15)) == NULL) return FALSE; | ||
132 | pblk_table = (LPDWORD)(lpMemFile+pmmh->blktable); | ||
133 | for (UINT nBlock=0; nBlock<pmmh->nblocks; nBlock++) | ||
134 | { | ||
135 | DWORD dwMemPos = pblk_table[nBlock]; | ||
136 | LPMMCMPBLOCK pblk = (LPMMCMPBLOCK)(lpMemFile+dwMemPos); | ||
137 | LPMMCMPSUBBLOCK psubblk = (LPMMCMPSUBBLOCK)(lpMemFile+dwMemPos+20); | ||
138 | |||
139 | if ((dwMemPos + 20 >= dwMemLength) || (dwMemPos + 20 + pblk->sub_blk*8 >= dwMemLength)) break; | ||
140 | dwMemPos += 20 + pblk->sub_blk*8; | ||
141 | #ifdef MMCMP_LOG | ||
142 | Log("block %d: flags=%04X sub_blocks=%d", nBlock, (UINT)pblk->flags, (UINT)pblk->sub_blk); | ||
143 | Log(" pksize=%d unpksize=%d", pblk->pk_size, pblk->unpk_size); | ||
144 | Log(" tt_entries=%d num_bits=%d\n", pblk->tt_entries, pblk->num_bits); | ||
145 | #endif | ||
146 | // Data is not packed | ||
147 | if (!(pblk->flags & MMCMP_COMP)) | ||
148 | { | ||
149 | for (UINT i=0; i<pblk->sub_blk; i++) | ||
150 | { | ||
151 | if ((psubblk->unpk_pos > dwFileSize) || (psubblk->unpk_pos + psubblk->unpk_size > dwFileSize)) break; | ||
152 | #ifdef MMCMP_LOG | ||
153 | Log(" Unpacked sub-block %d: offset %d, size=%d\n", i, psubblk->unpk_pos, psubblk->unpk_size); | ||
154 | #endif | ||
155 | memcpy(pBuffer+psubblk->unpk_pos, lpMemFile+dwMemPos, psubblk->unpk_size); | ||
156 | dwMemPos += psubblk->unpk_size; | ||
157 | psubblk++; | ||
158 | } | ||
159 | } else | ||
160 | // Data is 16-bit packed | ||
161 | if (pblk->flags & MMCMP_16BIT) | ||
162 | { | ||
163 | MMCMPBITBUFFER bb; | ||
164 | LPWORD pDest = (LPWORD)(pBuffer + psubblk->unpk_pos); | ||
165 | DWORD dwSize = psubblk->unpk_size >> 1; | ||
166 | DWORD dwPos = 0; | ||
167 | UINT numbits = pblk->num_bits; | ||
168 | UINT subblk = 0, oldval = 0; | ||
169 | |||
170 | #ifdef MMCMP_LOG | ||
171 | Log(" 16-bit block: pos=%d size=%d ", psubblk->unpk_pos, psubblk->unpk_size); | ||
172 | if (pblk->flags & MMCMP_DELTA) Log("DELTA "); | ||
173 | if (pblk->flags & MMCMP_ABS16) Log("ABS16 "); | ||
174 | Log("\n"); | ||
175 | #endif | ||
176 | bb.bitcount = 0; | ||
177 | bb.bitbuffer = 0; | ||
178 | bb.pSrc = lpMemFile+dwMemPos+pblk->tt_entries; | ||
179 | bb.pEnd = lpMemFile+dwMemPos+pblk->pk_size; | ||
180 | while (subblk < pblk->sub_blk) | ||
181 | { | ||
182 | UINT newval = 0x10000; | ||
183 | DWORD d = bb.GetBits(numbits+1); | ||
184 | |||
185 | if (d >= MMCMP16BitCommands[numbits]) | ||
186 | { | ||
187 | UINT nFetch = MMCMP16BitFetch[numbits]; | ||
188 | UINT newbits = bb.GetBits(nFetch) + ((d - MMCMP16BitCommands[numbits]) << nFetch); | ||
189 | if (newbits != numbits) | ||
190 | { | ||
191 | numbits = newbits & 0x0F; | ||
192 | } else | ||
193 | { | ||
194 | if ((d = bb.GetBits(4)) == 0x0F) | ||
195 | { | ||
196 | if (bb.GetBits(1)) break; | ||
197 | newval = 0xFFFF; | ||
198 | } else | ||
199 | { | ||
200 | newval = 0xFFF0 + d; | ||
201 | } | ||
202 | } | ||
203 | } else | ||
204 | { | ||
205 | newval = d; | ||
206 | } | ||
207 | if (newval < 0x10000) | ||
208 | { | ||
209 | newval = (newval & 1) ? (UINT)(-(LONG)((newval+1) >> 1)) : (UINT)(newval >> 1); | ||
210 | if (pblk->flags & MMCMP_DELTA) | ||
211 | { | ||
212 | newval += oldval; | ||
213 | oldval = newval; | ||
214 | } else | ||
215 | if (!(pblk->flags & MMCMP_ABS16)) | ||
216 | { | ||
217 | newval ^= 0x8000; | ||
218 | } | ||
219 | pDest[dwPos++] = (WORD)newval; | ||
220 | } | ||
221 | if (dwPos >= dwSize) | ||
222 | { | ||
223 | subblk++; | ||
224 | dwPos = 0; | ||
225 | dwSize = psubblk[subblk].unpk_size >> 1; | ||
226 | pDest = (LPWORD)(pBuffer + psubblk[subblk].unpk_pos); | ||
227 | } | ||
228 | } | ||
229 | } else | ||
230 | // Data is 8-bit packed | ||
231 | { | ||
232 | MMCMPBITBUFFER bb; | ||
233 | LPBYTE pDest = pBuffer + psubblk->unpk_pos; | ||
234 | DWORD dwSize = psubblk->unpk_size; | ||
235 | DWORD dwPos = 0; | ||
236 | UINT numbits = pblk->num_bits; | ||
237 | UINT subblk = 0, oldval = 0; | ||
238 | LPCBYTE ptable = lpMemFile+dwMemPos; | ||
239 | |||
240 | bb.bitcount = 0; | ||
241 | bb.bitbuffer = 0; | ||
242 | bb.pSrc = lpMemFile+dwMemPos+pblk->tt_entries; | ||
243 | bb.pEnd = lpMemFile+dwMemPos+pblk->pk_size; | ||
244 | while (subblk < pblk->sub_blk) | ||
245 | { | ||
246 | UINT newval = 0x100; | ||
247 | DWORD d = bb.GetBits(numbits+1); | ||
248 | |||
249 | if (d >= MMCMP8BitCommands[numbits]) | ||
250 | { | ||
251 | UINT nFetch = MMCMP8BitFetch[numbits]; | ||
252 | UINT newbits = bb.GetBits(nFetch) + ((d - MMCMP8BitCommands[numbits]) << nFetch); | ||
253 | if (newbits != numbits) | ||
254 | { | ||
255 | numbits = newbits & 0x07; | ||
256 | } else | ||
257 | { | ||
258 | if ((d = bb.GetBits(3)) == 7) | ||
259 | { | ||
260 | if (bb.GetBits(1)) break; | ||
261 | newval = 0xFF; | ||
262 | } else | ||
263 | { | ||
264 | newval = 0xF8 + d; | ||
265 | } | ||
266 | } | ||
267 | } else | ||
268 | { | ||
269 | newval = d; | ||
270 | } | ||
271 | if (newval < 0x100) | ||
272 | { | ||
273 | int n = ptable[newval]; | ||
274 | if (pblk->flags & MMCMP_DELTA) | ||
275 | { | ||
276 | n += oldval; | ||
277 | oldval = n; | ||
278 | } | ||
279 | pDest[dwPos++] = (BYTE)n; | ||
280 | } | ||
281 | if (dwPos >= dwSize) | ||
282 | { | ||
283 | subblk++; | ||
284 | dwPos = 0; | ||
285 | dwSize = psubblk[subblk].unpk_size; | ||
286 | pDest = pBuffer + psubblk[subblk].unpk_pos; | ||
287 | } | ||
288 | } | ||
289 | } | ||
290 | } | ||
291 | *ppMemFile = pBuffer; | ||
292 | *pdwMemLength = dwFileSize; | ||
293 | return TRUE; | ||
294 | } | ||
295 | |||
296 | |||
297 | ////////////////////////////////////////////////////////////////////////////// | ||
298 | // | ||
299 | // PowerPack PP20 Unpacker | ||
300 | // | ||
301 | |||
302 | typedef struct _PPBITBUFFER | ||
303 | { | ||
304 | UINT bitcount; | ||
305 | ULONG bitbuffer; | ||
306 | LPCBYTE pStart; | ||
307 | LPCBYTE pSrc; | ||
308 | |||
309 | ULONG GetBits(UINT n); | ||
310 | } Q_PACKED PPBITBUFFER; | ||
311 | |||
312 | |||
313 | ULONG PPBITBUFFER::GetBits(UINT n) | ||
314 | { | ||
315 | ULONG result = 0; | ||
316 | |||
317 | for (UINT i=0; i<n; i++) | ||
318 | { | ||
319 | if (!bitcount) | ||
320 | { | ||
321 | bitcount = 8; | ||
322 | if (pSrc != pStart) pSrc--; | ||
323 | bitbuffer = *pSrc; | ||
324 | } | ||
325 | result = (result<<1) | (bitbuffer&1); | ||
326 | bitbuffer >>= 1; | ||
327 | bitcount--; | ||
328 | } | ||
329 | return result; | ||
330 | } | ||
331 | |||
332 | |||
333 | VOID PP20_DoUnpack(const BYTE *pSrc, UINT nSrcLen, BYTE *pDst, UINT nDstLen) | ||
334 | { | ||
335 | PPBITBUFFER BitBuffer; | ||
336 | ULONG nBytesLeft; | ||
337 | |||
338 | BitBuffer.pStart = pSrc; | ||
339 | BitBuffer.pSrc = pSrc + nSrcLen - 4; | ||
340 | BitBuffer.bitbuffer = 0; | ||
341 | BitBuffer.bitcount = 0; | ||
342 | BitBuffer.GetBits(pSrc[nSrcLen-1]); | ||
343 | nBytesLeft = nDstLen; | ||
344 | while (nBytesLeft > 0) | ||
345 | { | ||
346 | if (!BitBuffer.GetBits(1)) | ||
347 | { | ||
348 | UINT n = 1; | ||
349 | while (n < nBytesLeft) | ||
350 | { | ||
351 | UINT code = BitBuffer.GetBits(2); | ||
352 | n += code; | ||
353 | if (code != 3) break; | ||
354 | } | ||
355 | for (UINT i=0; i<n; i++) | ||
356 | { | ||
357 | pDst[--nBytesLeft] = (BYTE)BitBuffer.GetBits(8); | ||
358 | } | ||
359 | if (!nBytesLeft) break; | ||
360 | } | ||
361 | { | ||
362 | UINT n = BitBuffer.GetBits(2)+1; | ||
363 | UINT nbits = pSrc[n-1]; | ||
364 | UINT nofs; | ||
365 | if (n==4) | ||
366 | { | ||
367 | nofs = BitBuffer.GetBits( (BitBuffer.GetBits(1)) ? nbits : 7 ); | ||
368 | while (n < nBytesLeft) | ||
369 | { | ||
370 | UINT code = BitBuffer.GetBits(3); | ||
371 | n += code; | ||
372 | if (code != 7) break; | ||
373 | } | ||
374 | } else | ||
375 | { | ||
376 | nofs = BitBuffer.GetBits(nbits); | ||
377 | } | ||
378 | for (UINT i=0; i<=n; i++) | ||
379 | { | ||
380 | pDst[nBytesLeft-1] = (nBytesLeft+nofs < nDstLen) ? pDst[nBytesLeft+nofs] : 0; | ||
381 | if (!--nBytesLeft) break; | ||
382 | } | ||
383 | } | ||
384 | } | ||
385 | } | ||
386 | |||
387 | |||
388 | BOOL PP20_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength) | ||
389 | { | ||
390 | DWORD dwMemLength = *pdwMemLength; | ||
391 | LPCBYTE lpMemFile = *ppMemFile; | ||
392 | DWORD dwDstLen; | ||
393 | LPBYTE pBuffer; | ||
394 | |||
395 | if ((!lpMemFile) || (dwMemLength < 256) || (*(DWORD *)lpMemFile != 0x30325050)) return FALSE; | ||
396 | dwDstLen = (lpMemFile[dwMemLength-4]<<16) | (lpMemFile[dwMemLength-3]<<8) | (lpMemFile[dwMemLength-2]); | ||
397 | //Log("PP20 detected: Packed length=%d, Unpacked length=%d\n", dwMemLength, dwDstLen); | ||
398 | if ((dwDstLen < 512) || (dwDstLen > 0x400000) || (dwDstLen > 16*dwMemLength)) return FALSE; | ||
399 | if ((pBuffer = (LPBYTE)GlobalAllocPtr(GHND, (dwDstLen + 31) & ~15)) == NULL) return FALSE; | ||
400 | PP20_DoUnpack(lpMemFile+4, dwMemLength-4, pBuffer, dwDstLen); | ||
401 | *ppMemFile = pBuffer; | ||
402 | *pdwMemLength = dwDstLen; | ||
403 | return TRUE; | ||
404 | } | ||
405 | |||
406 | |||
407 | |||
408 | |||
409 | |||