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