summaryrefslogtreecommitdiff
path: root/core/multimedia/opieplayer/modplug/load_ams.cpp
Unidiff
Diffstat (limited to 'core/multimedia/opieplayer/modplug/load_ams.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--core/multimedia/opieplayer/modplug/load_ams.cpp631
1 files changed, 631 insertions, 0 deletions
diff --git a/core/multimedia/opieplayer/modplug/load_ams.cpp b/core/multimedia/opieplayer/modplug/load_ams.cpp
new file mode 100644
index 0000000..3dd1c2b
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_ams.cpp
@@ -0,0 +1,631 @@
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//////////////////////////////////////////////
11// AMS module loader //
12//////////////////////////////////////////////
13#include "stdafx.h"
14#include "sndfile.h"
15
16//#pragma warning(disable:4244)
17
18#pragma pack(1)
19
20typedef struct AMSFILEHEADER
21{
22 char szHeader[7];// "Extreme" // changed from CHAR
23 BYTE verlo, verhi;// 0x??,0x01
24 BYTE chncfg;
25 BYTE samples;
26 WORD patterns;
27 WORD orders;
28 BYTE vmidi;
29 WORD extra;
30} Q_PACKED AMSFILEHEADER;
31
32typedef struct AMSSAMPLEHEADER
33{
34 DWORD length;
35 DWORD loopstart;
36 DWORD loopend;
37 BYTE finetune_and_pan;
38 WORD samplerate;// C-2 = 8363
39 BYTE volume; // 0-127
40 BYTE infobyte;
41} Q_PACKED AMSSAMPLEHEADER;
42
43
44#pragma pack()
45
46
47
48BOOL CSoundFile::ReadAMS(LPCBYTE lpStream, DWORD dwMemLength)
49//-----------------------------------------------------------
50{
51 BYTE pkinf[MAX_SAMPLES];
52 AMSFILEHEADER *pfh = (AMSFILEHEADER *)lpStream;
53 DWORD dwMemPos;
54 UINT tmp, tmp2;
55
56 if ((!lpStream) || (dwMemLength < 1024)) return FALSE;
57 if ((pfh->verhi != 0x01) || (strncmp(pfh->szHeader, "Extreme", 7))
58 || (!pfh->patterns) || (!pfh->orders) || (!pfh->samples) || (pfh->samples > MAX_SAMPLES)
59 || (pfh->patterns > MAX_PATTERNS) || (pfh->orders > MAX_ORDERS))
60 {
61 return ReadAMS2(lpStream, dwMemLength);
62 }
63 dwMemPos = sizeof(AMSFILEHEADER) + pfh->extra;
64 if (dwMemPos + pfh->samples * sizeof(AMSSAMPLEHEADER) + 256 >= dwMemLength) return FALSE;
65 m_nType = MOD_TYPE_AMS;
66 m_nInstruments = 0;
67 m_nChannels = (pfh->chncfg & 0x1F) + 1;
68 m_nSamples = pfh->samples;
69 for (UINT nSmp=1; nSmp<=m_nSamples; nSmp++, dwMemPos += sizeof(AMSSAMPLEHEADER))
70 {
71 AMSSAMPLEHEADER *psh = (AMSSAMPLEHEADER *)(lpStream + dwMemPos);
72 MODINSTRUMENT *pins = &Ins[nSmp];
73 pins->nLength = psh->length;
74 pins->nLoopStart = psh->loopstart;
75 pins->nLoopEnd = psh->loopend;
76 pins->nGlobalVol = 64;
77 pins->nVolume = psh->volume << 1;
78 pins->nC4Speed = psh->samplerate;
79 pins->nPan = (psh->finetune_and_pan & 0xF0);
80 if (pins->nPan < 0x80) pins->nPan += 0x10;
81 pins->nFineTune = MOD2XMFineTune(psh->finetune_and_pan & 0x0F);
82 pins->uFlags = (psh->infobyte & 0x80) ? CHN_16BIT : 0;
83 if ((pins->nLoopEnd <= pins->nLength) && (pins->nLoopStart+4 <= pins->nLoopEnd)) pins->uFlags |= CHN_LOOP;
84 pkinf[nSmp] = psh->infobyte;
85 }
86 // Read Song Name
87 tmp = lpStream[dwMemPos++];
88 if (dwMemPos + tmp + 1 >= dwMemLength) return TRUE;
89 tmp2 = (tmp < 32) ? tmp : 31;
90 if (tmp2) memcpy(m_szNames[0], lpStream+dwMemPos, tmp2);
91 m_szNames[0][tmp2] = 0;
92 dwMemPos += tmp;
93 // Read sample names
94 for (UINT sNam=1; sNam<=m_nSamples; sNam++)
95 {
96 if (dwMemPos + 32 >= dwMemLength) return TRUE;
97 tmp = lpStream[dwMemPos++];
98 tmp2 = (tmp < 32) ? tmp : 31;
99 if (tmp2) memcpy(m_szNames[sNam], lpStream+dwMemPos, tmp2);
100 dwMemPos += tmp;
101 }
102 // Skip Channel names
103 for (UINT cNam=0; cNam<m_nChannels; cNam++)
104 {
105 if (dwMemPos + 32 >= dwMemLength) return TRUE;
106 tmp = lpStream[dwMemPos++];
107 dwMemPos += tmp;
108 }
109 // Read Pattern Names
110 m_lpszPatternNames = new char[pfh->patterns * 32]; // changed from CHAR
111 if (!m_lpszPatternNames) return TRUE;
112 m_nPatternNames = pfh->patterns;
113 memset(m_lpszPatternNames, 0, m_nPatternNames * 32);
114 for (UINT pNam=0; pNam < m_nPatternNames; pNam++)
115 {
116 if (dwMemPos + 32 >= dwMemLength) return TRUE;
117 tmp = lpStream[dwMemPos++];
118 tmp2 = (tmp < 32) ? tmp : 31;
119 if (tmp2) memcpy(m_lpszPatternNames+pNam*32, lpStream+dwMemPos, tmp2);
120 dwMemPos += tmp;
121 }
122 // Read Song Comments
123 tmp = *((WORD *)(lpStream+dwMemPos));
124 dwMemPos += 2;
125 if (dwMemPos + tmp >= dwMemLength) return TRUE;
126 if (tmp)
127 {
128 m_lpszSongComments = new char[tmp+1]; // changed from CHAR
129 if (!m_lpszSongComments) return TRUE;
130 memset(m_lpszSongComments, 0, tmp+1);
131 memcpy(m_lpszSongComments, lpStream + dwMemPos, tmp);
132 dwMemPos += tmp;
133 }
134 // Read Order List
135 for (UINT iOrd=0; iOrd<pfh->orders; iOrd++, dwMemPos += 2)
136 {
137 UINT n = *((WORD *)(lpStream+dwMemPos));
138 Order[iOrd] = (BYTE)n;
139 }
140 // Read Patterns
141 for (UINT iPat=0; iPat<pfh->patterns; iPat++)
142 {
143 if (dwMemPos + 4 >= dwMemLength) return TRUE;
144 UINT len = *((DWORD *)(lpStream + dwMemPos));
145 dwMemPos += 4;
146 if ((len >= dwMemLength) || (dwMemPos + len > dwMemLength)) return TRUE;
147 PatternSize[iPat] = 64;
148 MODCOMMAND *m = AllocatePattern(PatternSize[iPat], m_nChannels);
149 if (!m) return TRUE;
150 Patterns[iPat] = m;
151 const BYTE *p = lpStream + dwMemPos;
152 UINT row = 0, i = 0;
153 while ((row < PatternSize[iPat]) && (i+2 < len))
154 {
155 BYTE b0 = p[i++];
156 BYTE b1 = p[i++];
157 BYTE b2 = 0;
158 UINT ch = b0 & 0x3F;
159 // Note+Instr
160 if (!(b0 & 0x40))
161 {
162 b2 = p[i++];
163 if (ch < m_nChannels)
164 {
165 if (b1 & 0x7F) m[ch].note = (b1 & 0x7F) + 25;
166 m[ch].instr = b2;
167 }
168 if (b1 & 0x80)
169 {
170 b0 |= 0x40;
171 b1 = p[i++];
172 }
173 }
174 // Effect
175 if (b0 & 0x40)
176 {
177 anothercommand:
178 if (b1 & 0x40)
179 {
180 if (ch < m_nChannels)
181 {
182 m[ch].volcmd = VOLCMD_VOLUME;
183 m[ch].vol = b1 & 0x3F;
184 }
185 } else
186 {
187 b2 = p[i++];
188 if (ch < m_nChannels)
189 {
190 UINT cmd = b1 & 0x3F;
191 if (cmd == 0x0C)
192 {
193 m[ch].volcmd = VOLCMD_VOLUME;
194 m[ch].vol = b2 >> 1;
195 } else
196 if (cmd == 0x0E)
197 {
198 if (!m[ch].command)
199 {
200 UINT command = CMD_S3MCMDEX;
201 UINT param = b2;
202 switch(param & 0xF0)
203 {
204 case 0x00:if (param & 0x08) { param &= 0x07; param |= 0x90; } else {command=param=0;} break;
205 case 0x10:command = CMD_PORTAMENTOUP; param |= 0xF0; break;
206 case 0x20:command = CMD_PORTAMENTODOWN; param |= 0xF0; break;
207 case 0x30:param = (param & 0x0F) | 0x10; break;
208 case 0x40:param = (param & 0x0F) | 0x30; break;
209 case 0x50:param = (param & 0x0F) | 0x20; break;
210 case 0x60:param = (param & 0x0F) | 0xB0; break;
211 case 0x70:param = (param & 0x0F) | 0x40; break;
212 case 0x90:command = CMD_RETRIG; param &= 0x0F; break;
213 case 0xA0:if (param & 0x0F) { command = CMD_VOLUMESLIDE; param = (param << 4) | 0x0F; } else command=param=0; break;
214 case 0xB0:if (param & 0x0F) { command = CMD_VOLUMESLIDE; param |= 0xF0; } else command=param=0; break;
215 }
216 m[ch].command = command;
217 m[ch].param = param;
218 }
219 } else
220 {
221 m[ch].command = cmd;
222 m[ch].param = b2;
223 ConvertModCommand(&m[ch]);
224 }
225 }
226 }
227 if (b1 & 0x80)
228 {
229 b1 = p[i++];
230 if (i <= len) goto anothercommand;
231 }
232 }
233 if (b0 & 0x80)
234 {
235 row++;
236 m += m_nChannels;
237 }
238 }
239 dwMemPos += len;
240 }
241 // Read Samples
242 for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++) if (Ins[iSmp].nLength)
243 {
244 if (dwMemPos >= dwMemLength - 9) return TRUE;
245 UINT flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_AMS16 : RS_AMS8;
246 dwMemPos += ReadSample(&Ins[iSmp], flags, (LPSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos);
247 }
248 return TRUE;
249}
250
251
252/////////////////////////////////////////////////////////////////////
253// AMS 2.2 loader
254
255#pragma pack(1)
256
257typedef struct AMS2FILEHEADER
258{
259 DWORD dwHdr1; // AMShdr
260 WORD wHdr2;
261 BYTE b1A; // 0x1A
262 BYTE titlelen; // 30-bytes max
263 CHAR szTitle[30];// [titlelen]
264} Q_PACKED AMS2FILEHEADER;
265
266typedef struct AMS2SONGHEADER
267{
268 WORD version;
269 BYTE instruments;
270 WORD patterns;
271 WORD orders;
272 WORD bpm;
273 BYTE speed;
274 BYTE channels;
275 BYTE commands;
276 BYTE rows;
277 WORD flags;
278} Q_PACKED AMS2SONGHEADER;
279
280typedef struct AMS2INSTRUMENT
281{
282 BYTE samples;
283 BYTE notemap[120];
284} Q_PACKED AMS2INSTRUMENT;
285
286typedef struct AMS2ENVELOPE
287{
288 BYTE speed;
289 BYTE sustain;
290 BYTE loopbegin;
291 BYTE loopend;
292 BYTE points;
293 BYTE info[3];
294} Q_PACKED AMS2ENVELOPE;
295
296typedef struct AMS2SAMPLE
297{
298 DWORD length;
299 DWORD loopstart;
300 DWORD loopend;
301 WORD frequency;
302 BYTE finetune;
303 WORD c4speed;
304 CHAR transpose;
305 BYTE volume;
306 BYTE flags;
307} Q_PACKED AMS2SAMPLE;
308
309
310#pragma pack()
311
312
313BOOL CSoundFile::ReadAMS2(LPCBYTE lpStream, DWORD dwMemLength)
314//------------------------------------------------------------
315{
316 AMS2FILEHEADER *pfh = (AMS2FILEHEADER *)lpStream;
317 AMS2SONGHEADER *psh;
318 DWORD dwMemPos;
319 BYTE smpmap[16];
320 BYTE packedsamples[MAX_SAMPLES];
321
322 if ((pfh->dwHdr1 != 0x68534D41) || (pfh->wHdr2 != 0x7264)
323 || (pfh->b1A != 0x1A) || (pfh->titlelen > 30)) return FALSE;
324 dwMemPos = pfh->titlelen + 8;
325 psh = (AMS2SONGHEADER *)(lpStream + dwMemPos);
326 if (((psh->version & 0xFF00) != 0x0200) || (!psh->instruments)
327 || (psh->instruments > MAX_INSTRUMENTS) || (!psh->patterns) || (!psh->orders)) return FALSE;
328 dwMemPos += sizeof(AMS2SONGHEADER);
329 if (pfh->titlelen)
330 {
331 memcpy(m_szNames, pfh->szTitle, pfh->titlelen);
332 m_szNames[0][pfh->titlelen] = 0;
333 }
334 m_nType = MOD_TYPE_AMS;
335 m_nChannels = 32;
336 m_nDefaultTempo = psh->bpm >> 8;
337 m_nDefaultSpeed = psh->speed;
338 m_nInstruments = psh->instruments;
339 m_nSamples = 0;
340 if (psh->flags & 0x40) m_dwSongFlags |= SONG_LINEARSLIDES;
341 for (UINT nIns=1; nIns<=m_nInstruments; nIns++)
342 {
343 UINT insnamelen = lpStream[dwMemPos];
344 CHAR *pinsname = (CHAR *)(lpStream+dwMemPos+1);
345 dwMemPos += insnamelen + 1;
346 AMS2INSTRUMENT *pins = (AMS2INSTRUMENT *)(lpStream + dwMemPos);
347 dwMemPos += sizeof(AMS2INSTRUMENT);
348 if (dwMemPos + 1024 >= dwMemLength) return TRUE;
349 AMS2ENVELOPE *volenv, *panenv, *pitchenv;
350 volenv = (AMS2ENVELOPE *)(lpStream+dwMemPos);
351 dwMemPos += 5 + volenv->points*3;
352 panenv = (AMS2ENVELOPE *)(lpStream+dwMemPos);
353 dwMemPos += 5 + panenv->points*3;
354 pitchenv = (AMS2ENVELOPE *)(lpStream+dwMemPos);
355 dwMemPos += 5 + pitchenv->points*3;
356 INSTRUMENTHEADER *penv = new INSTRUMENTHEADER;
357 if (!penv) return TRUE;
358 memset(smpmap, 0, sizeof(smpmap));
359 memset(penv, 0, sizeof(INSTRUMENTHEADER));
360 for (UINT ismpmap=0; ismpmap<pins->samples; ismpmap++)
361 {
362 if ((ismpmap >= 16) || (m_nSamples+1 >= MAX_SAMPLES)) break;
363 m_nSamples++;
364 smpmap[ismpmap] = m_nSamples;
365 }
366 penv->nGlobalVol = 64;
367 penv->nPan = 128;
368 penv->nPPC = 60;
369 Headers[nIns] = penv;
370 if (insnamelen)
371 {
372 if (insnamelen > 31) insnamelen = 31;
373 memcpy(penv->name, pinsname, insnamelen);
374 penv->name[insnamelen] = 0;
375 }
376 for (UINT inotemap=0; inotemap<120; inotemap++)
377 {
378 penv->NoteMap[inotemap] = inotemap+1;
379 penv->Keyboard[inotemap] = smpmap[pins->notemap[inotemap] & 0x0F];
380 }
381 // Volume Envelope
382 {
383 UINT pos = 0;
384 penv->nVolEnv = (volenv->points > 16) ? 16 : volenv->points;
385 penv->nVolSustainBegin = penv->nVolSustainEnd = volenv->sustain;
386 penv->nVolLoopStart = volenv->loopbegin;
387 penv->nVolLoopEnd = volenv->loopend;
388 for (UINT i=0; i<penv->nVolEnv; i++)
389 {
390 penv->VolEnv[i] = (BYTE)((volenv->info[i*3+2] & 0x7F) >> 1);
391 pos += volenv->info[i*3] + ((volenv->info[i*3+1] & 1) << 8);
392 penv->VolPoints[i] = (WORD)pos;
393 }
394 }
395 penv->nFadeOut = (((lpStream[dwMemPos+2] & 0x0F) << 8) | (lpStream[dwMemPos+1])) << 3;
396 UINT envflags = lpStream[dwMemPos+3];
397 if (envflags & 0x01) penv->dwFlags |= ENV_VOLLOOP;
398 if (envflags & 0x02) penv->dwFlags |= ENV_VOLSUSTAIN;
399 if (envflags & 0x04) penv->dwFlags |= ENV_VOLUME;
400 dwMemPos += 5;
401 // Read Samples
402 for (UINT ismp=0; ismp<pins->samples; ismp++)
403 {
404 MODINSTRUMENT *psmp = ((ismp < 16) && (smpmap[ismp])) ? &Ins[smpmap[ismp]] : NULL;
405 UINT smpnamelen = lpStream[dwMemPos];
406 if ((psmp) && (smpnamelen) && (smpnamelen <= 22))
407 {
408 memcpy(m_szNames[smpmap[ismp]], lpStream+dwMemPos+1, smpnamelen);
409 }
410 dwMemPos += smpnamelen + 1;
411 if (psmp)
412 {
413 AMS2SAMPLE *pams = (AMS2SAMPLE *)(lpStream+dwMemPos);
414 psmp->nGlobalVol = 64;
415 psmp->nPan = 128;
416 psmp->nLength = pams->length;
417 psmp->nLoopStart = pams->loopstart;
418 psmp->nLoopEnd = pams->loopend;
419 psmp->nC4Speed = pams->c4speed;
420 psmp->RelativeTone = pams->transpose;
421 psmp->nVolume = pams->volume / 2;
422 packedsamples[smpmap[ismp]] = pams->flags;
423 if (pams->flags & 0x04) psmp->uFlags |= CHN_16BIT;
424 if (pams->flags & 0x08) psmp->uFlags |= CHN_LOOP;
425 if (pams->flags & 0x10) psmp->uFlags |= CHN_PINGPONGLOOP;
426 }
427 dwMemPos += sizeof(AMS2SAMPLE);
428 }
429 }
430 if (dwMemPos + 256 >= dwMemLength) return TRUE;
431 // Comments
432 {
433 UINT composernamelen = lpStream[dwMemPos];
434 if (composernamelen)
435 {
436 m_lpszSongComments = new char[composernamelen+1]; // changed from CHAR
437 if (m_lpszSongComments)
438 {
439 memcpy(m_lpszSongComments, lpStream+dwMemPos+1, composernamelen);
440 m_lpszSongComments[composernamelen] = 0;
441 }
442 }
443 dwMemPos += composernamelen + 1;
444 // channel names
445 for (UINT i=0; i<32; i++)
446 {
447 UINT chnnamlen = lpStream[dwMemPos];
448 if ((chnnamlen) && (chnnamlen < MAX_CHANNELNAME))
449 {
450 memcpy(ChnSettings[i].szName, lpStream+dwMemPos+1, chnnamlen);
451 }
452 dwMemPos += chnnamlen + 1;
453 if (dwMemPos + chnnamlen + 256 >= dwMemLength) return TRUE;
454 }
455 // packed comments (ignored)
456 UINT songtextlen = *((LPDWORD)(lpStream+dwMemPos));
457 dwMemPos += songtextlen;
458 if (dwMemPos + 256 >= dwMemLength) return TRUE;
459 }
460 // Order List
461 {
462 for (UINT i=0; i<MAX_ORDERS; i++)
463 {
464 Order[i] = 0xFF;
465 if (dwMemPos + 2 >= dwMemLength) return TRUE;
466 if (i < psh->orders)
467 {
468 Order[i] = lpStream[dwMemPos];
469 dwMemPos += 2;
470 }
471 }
472 }
473 // Pattern Data
474 for (UINT ipat=0; ipat<psh->patterns; ipat++)
475 {
476 if (dwMemPos+8 >= dwMemLength) return TRUE;
477 UINT packedlen = *((LPDWORD)(lpStream+dwMemPos));
478 UINT numrows = 1 + (UINT)(lpStream[dwMemPos+4]);
479 //UINT patchn = 1 + (UINT)(lpStream[dwMemPos+5] & 0x1F);
480 //UINT patcmds = 1 + (UINT)(lpStream[dwMemPos+5] >> 5);
481 UINT patnamlen = lpStream[dwMemPos+6];
482 dwMemPos += 4;
483 if ((ipat < MAX_PATTERNS) && (packedlen < dwMemLength-dwMemPos) && (numrows >= 8))
484 {
485 if ((patnamlen) && (patnamlen < MAX_PATTERNNAME))
486 {
487 char s[MAX_PATTERNNAME]; // changed from CHAR
488 memcpy(s, lpStream+dwMemPos+3, patnamlen);
489 s[patnamlen] = 0;
490 SetPatternName(ipat, s);
491 }
492 PatternSize[ipat] = numrows;
493 Patterns[ipat] = AllocatePattern(numrows, m_nChannels);
494 if (!Patterns[ipat]) return TRUE;
495 // Unpack Pattern Data
496 LPCBYTE psrc = lpStream + dwMemPos;
497 UINT pos = 3 + patnamlen;
498 UINT row = 0;
499 while ((pos < packedlen) && (row < numrows))
500 {
501 MODCOMMAND *m = Patterns[ipat] + row * m_nChannels;
502 UINT byte1 = psrc[pos++];
503 UINT ch = byte1 & 0x1F;
504 // Read Note + Instr
505 if (!(byte1 & 0x40))
506 {
507 UINT byte2 = psrc[pos++];
508 UINT note = byte2 & 0x7F;
509 if (note) m[ch].note = (note > 1) ? (note-1) : 0xFF;
510 m[ch].instr = psrc[pos++];
511 // Read Effect
512 while (byte2 & 0x80)
513 {
514 byte2 = psrc[pos++];
515 if (byte2 & 0x40)
516 {
517 m[ch].volcmd = VOLCMD_VOLUME;
518 m[ch].vol = byte2 & 0x3F;
519 } else
520 {
521 UINT command = byte2 & 0x3F;
522 UINT param = psrc[pos++];
523 if (command == 0x0C)
524 {
525 m[ch].volcmd = VOLCMD_VOLUME;
526 m[ch].vol = param / 2;
527 } else
528 if (command < 0x10)
529 {
530 m[ch].command = command;
531 m[ch].param = param;
532 ConvertModCommand(&m[ch]);
533 } else
534 {
535 // TODO: AMS effects
536 }
537 }
538 }
539 }
540 if (byte1 & 0x80) row++;
541 }
542 }
543 dwMemPos += packedlen;
544 }
545 // Read Samples
546 for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++) if (Ins[iSmp].nLength)
547 {
548 if (dwMemPos >= dwMemLength - 9) return TRUE;
549 UINT flags;
550 if (packedsamples[iSmp] & 0x03)
551 {
552 flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_AMS16 : RS_AMS8;
553 } else
554 {
555 flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S;
556 }
557 dwMemPos += ReadSample(&Ins[iSmp], flags, (LPSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos);
558 }
559 return TRUE;
560}
561
562
563/////////////////////////////////////////////////////////////////////
564// AMS Sample unpacking
565
566void AMSUnpack(const char *psrc, UINT inputlen, char *pdest, UINT dmax, char packcharacter)
567{
568 UINT tmplen = dmax;
569 signed char *amstmp = new signed char[tmplen];
570
571 if (!amstmp) return;
572 // Unpack Loop
573 {
574 signed char *p = amstmp;
575 UINT i=0, j=0;
576 while ((i < inputlen) && (j < tmplen))
577 {
578 signed char ch = psrc[i++];
579 if (ch == packcharacter)
580 {
581 BYTE ch2 = psrc[i++];
582 if (ch2)
583 {
584 ch = psrc[i++];
585 while (ch2--)
586 {
587 p[j++] = ch;
588 if (j >= tmplen) break;
589 }
590 } else p[j++] = packcharacter;
591 } else p[j++] = ch;
592 }
593 }
594 // Bit Unpack Loop
595 {
596 signed char *p = amstmp;
597 UINT bitcount = 0x80, dh;
598 UINT k=0;
599 for (UINT i=0; i<dmax; i++)
600 {
601 BYTE al = *p++;
602 dh = 0;
603 for (UINT count=0; count<8; count++)
604 {
605 UINT bl = al & bitcount;
606 bl = ((bl|(bl<<8)) >> ((dh+8-count) & 7)) & 0xFF;
607 bitcount = ((bitcount|(bitcount<<8)) >> 1) & 0xFF;
608 pdest[k++] |= bl;
609 if (k >= dmax)
610 {
611 k = 0;
612 dh++;
613 }
614 }
615 bitcount = ((bitcount|(bitcount<<8)) >> dh) & 0xFF;
616 }
617 }
618 // Delta Unpack
619 {
620 signed char old = 0;
621 for (UINT i=0; i<dmax; i++)
622 {
623 int pos = ((LPBYTE)pdest)[i];
624 if ((pos != 128) && (pos & 0x80)) pos = -(pos & 0x7F);
625 old -= (signed char)pos;
626 pdest[i] = old;
627 }
628 }
629 delete amstmp;
630}
631