1 #pragma prototyped
2
3 /*-------------------------------------------------------------*/
4 /*--- Decompression machinery ---*/
5 /*--- decompress.c ---*/
6 /*-------------------------------------------------------------*/
7
8 /*--
9 This file is a part of bzip2 and/or libbzip2, a program and
10 library for lossless, block-sorting data compression.
11
12 Copyright (C) 1996-1998 Julian R Seward. All rights reserved.
13
14 Redistribution and use in source and binary forms, with or without
15 modification, are permitted provided that the following conditions
16 are met:
17
18 1. Redistributions of source code must retain the above copyright
19 notice, this list of conditions and the following disclaimer.
20
21 2. The origin of this software must not be misrepresented; you must
22 not claim that you wrote the original software. If you use this
23 software in a product, an acknowledgment in the product
24 documentation would be appreciated but is not required.
25
26 3. Altered source versions must be plainly marked as such, and must
27 not be misrepresented as being the original software.
28
29 4. The name of the author may not be used to endorse or promote
30 products derived from this software without specific prior written
31 permission.
32
33 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
34 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
35 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
37 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
39 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
40 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
41 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
42 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
43 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44
45 Julian Seward, Guildford, Surrey, UK.
46 jseward@acm.org
47 bzip2/libbzip2 version 0.9.0c of 18 October 1998
48
49 This program is based on (at least) the work of:
50 Mike Burrows
51 David Wheeler
52 Peter Fenwick
53 Alistair Moffat
54 Radford Neal
55 Ian H. Witten
56 Robert Sedgewick
57 Jon L. Bentley
58
59 For more information on these sources, see the manual.
60 --*/
61
62
63 #include "bzhdr.h"
64
65
66 /*---------------------------------------------------*/
67 static
makeMaps_d(DState * s)68 void makeMaps_d ( DState* s )
69 {
70 Int32 i;
71 s->nInUse = 0;
72 for (i = 0; i < 256; i++)
73 if (s->inUse[i]) {
74 s->seqToUnseq[s->nInUse] = i;
75 s->nInUse++;
76 }
77 }
78
79
80 /*---------------------------------------------------*/
81 #define RETURN(rrr) \
82 { retVal = rrr; goto save_state_and_return; };
83
84 #define GET_BITS(lll,vvv,nnn) \
85 case lll: s->state = lll; \
86 while (True) { \
87 if (s->bsLive >= nnn) { \
88 UInt32 v; \
89 v = (s->bsBuff >> \
90 (s->bsLive-nnn)) & ((1 << nnn)-1); \
91 s->bsLive -= nnn; \
92 vvv = v; \
93 break; \
94 } \
95 if (s->strm->avail_in == 0) RETURN(BZ_OK); \
96 s->bsBuff \
97 = (s->bsBuff << 8) | \
98 ((UInt32) \
99 (*((UChar*)(s->strm->next_in)))); \
100 s->bsLive += 8; \
101 s->strm->next_in++; \
102 s->strm->avail_in--; \
103 s->strm->total_in++; \
104 }
105
106 #define GET_UCHAR(lll,uuu) \
107 GET_BITS(lll,uuu,8)
108
109 #define GET_BIT(lll,uuu) \
110 GET_BITS(lll,uuu,1)
111
112 /*---------------------------------------------------*/
113 #define GET_MTF_VAL(label1,label2,lval) \
114 { \
115 if (groupPos == 0) { \
116 groupNo++; \
117 groupPos = BZ_G_SIZE; \
118 gSel = s->selector[groupNo]; \
119 gMinlen = s->minLens[gSel]; \
120 gLimit = &(s->limit[gSel][0]); \
121 gPerm = &(s->perm[gSel][0]); \
122 gBase = &(s->base[gSel][0]); \
123 } \
124 groupPos--; \
125 zn = gMinlen; \
126 GET_BITS(label1, zvec, zn); \
127 while (zvec > gLimit[zn]) { \
128 zn++; \
129 GET_BIT(label2, zj); \
130 zvec = (zvec << 1) | zj; \
131 }; \
132 lval = gPerm[zvec - gBase[zn]]; \
133 }
134
135
136 /*---------------------------------------------------*/
decompress(DState * s)137 Int32 decompress ( DState* s )
138 {
139 UChar uc;
140 Int32 retVal;
141 Int32 minLen, maxLen;
142 bz_stream* strm = s->strm;
143
144 /* stuff that needs to be saved/restored */
145 Int32 i ;
146 Int32 j;
147 Int32 t;
148 Int32 alphaSize;
149 Int32 nGroups;
150 Int32 nSelectors;
151 Int32 EOB;
152 Int32 groupNo;
153 Int32 groupPos;
154 Int32 nextSym;
155 Int32 nblockMAX;
156 Int32 nblock;
157 Int32 es;
158 Int32 N;
159 Int32 curr;
160 Int32 zt;
161 Int32 zn;
162 Int32 zvec;
163 Int32 zj;
164 Int32 gSel;
165 Int32 gMinlen;
166 Int32* gLimit;
167 Int32* gBase;
168 Int32* gPerm;
169
170 if (s->state == BZ_X_MAGIC_1) {
171 /*initialise the save area*/
172 s->save_i = 0;
173 s->save_j = 0;
174 s->save_t = 0;
175 s->save_alphaSize = 0;
176 s->save_nGroups = 0;
177 s->save_nSelectors = 0;
178 s->save_EOB = 0;
179 s->save_groupNo = 0;
180 s->save_groupPos = 0;
181 s->save_nextSym = 0;
182 s->save_nblockMAX = 0;
183 s->save_nblock = 0;
184 s->save_es = 0;
185 s->save_N = 0;
186 s->save_curr = 0;
187 s->save_zt = 0;
188 s->save_zn = 0;
189 s->save_zvec = 0;
190 s->save_zj = 0;
191 s->save_gSel = 0;
192 s->save_gMinlen = 0;
193 s->save_gLimit = NULL;
194 s->save_gBase = NULL;
195 s->save_gPerm = NULL;
196 }
197
198 /*restore from the save area*/
199 i = s->save_i;
200 j = s->save_j;
201 t = s->save_t;
202 alphaSize = s->save_alphaSize;
203 nGroups = s->save_nGroups;
204 nSelectors = s->save_nSelectors;
205 EOB = s->save_EOB;
206 groupNo = s->save_groupNo;
207 groupPos = s->save_groupPos;
208 nextSym = s->save_nextSym;
209 nblockMAX = s->save_nblockMAX;
210 nblock = s->save_nblock;
211 es = s->save_es;
212 N = s->save_N;
213 curr = s->save_curr;
214 zt = s->save_zt;
215 zn = s->save_zn;
216 zvec = s->save_zvec;
217 zj = s->save_zj;
218 gSel = s->save_gSel;
219 gMinlen = s->save_gMinlen;
220 gLimit = s->save_gLimit;
221 gBase = s->save_gBase;
222 gPerm = s->save_gPerm;
223
224 retVal = BZ_OK;
225
226 switch (s->state) {
227
228 GET_UCHAR(BZ_X_MAGIC_1, uc);
229 if (uc != 'B') RETURN(BZ_DATA_ERROR_MAGIC);
230
231 GET_UCHAR(BZ_X_MAGIC_2, uc);
232 if (uc != 'Z') RETURN(BZ_DATA_ERROR_MAGIC);
233
234 GET_UCHAR(BZ_X_MAGIC_3, uc)
235 if (uc != 'h') RETURN(BZ_DATA_ERROR_MAGIC);
236
237 GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8)
238 if (s->blockSize100k < '1' ||
239 s->blockSize100k > '9') RETURN(BZ_DATA_ERROR_MAGIC);
240 s->blockSize100k -= '0';
241
242 if (s->smallDecompress) {
243 s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) );
244 s->ll4 = BZALLOC(
245 ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar)
246 );
247 if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR);
248 } else {
249 s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) );
250 if (s->tt == NULL) RETURN(BZ_MEM_ERROR);
251 }
252
253 GET_UCHAR(BZ_X_BLKHDR_1, uc);
254
255 if (uc == 0x17) goto endhdr_2;
256 if (uc != 0x31) RETURN(BZ_DATA_ERROR);
257 GET_UCHAR(BZ_X_BLKHDR_2, uc);
258 if (uc != 0x41) RETURN(BZ_DATA_ERROR);
259 GET_UCHAR(BZ_X_BLKHDR_3, uc);
260 if (uc != 0x59) RETURN(BZ_DATA_ERROR);
261 GET_UCHAR(BZ_X_BLKHDR_4, uc);
262 if (uc != 0x26) RETURN(BZ_DATA_ERROR);
263 GET_UCHAR(BZ_X_BLKHDR_5, uc);
264 if (uc != 0x53) RETURN(BZ_DATA_ERROR);
265 GET_UCHAR(BZ_X_BLKHDR_6, uc);
266 if (uc != 0x59) RETURN(BZ_DATA_ERROR);
267
268 s->currBlockNo++;
269 if (s->verbosity >= 2)
270 VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo );
271
272 s->storedBlockCRC = 0;
273 GET_UCHAR(BZ_X_BCRC_1, uc);
274 s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
275 GET_UCHAR(BZ_X_BCRC_2, uc);
276 s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
277 GET_UCHAR(BZ_X_BCRC_3, uc);
278 s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
279 GET_UCHAR(BZ_X_BCRC_4, uc);
280 s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
281
282 GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1);
283
284 s->origPtr = 0;
285 GET_UCHAR(BZ_X_ORIGPTR_1, uc);
286 s->origPtr = (s->origPtr << 8) | ((Int32)uc);
287 GET_UCHAR(BZ_X_ORIGPTR_2, uc);
288 s->origPtr = (s->origPtr << 8) | ((Int32)uc);
289 GET_UCHAR(BZ_X_ORIGPTR_3, uc);
290 s->origPtr = (s->origPtr << 8) | ((Int32)uc);
291
292 /*--- Receive the mapping table ---*/
293 for (i = 0; i < 16; i++) {
294 GET_BIT(BZ_X_MAPPING_1, uc);
295 if (uc == 1)
296 s->inUse16[i] = True; else
297 s->inUse16[i] = False;
298 }
299
300 for (i = 0; i < 256; i++) s->inUse[i] = False;
301
302 for (i = 0; i < 16; i++)
303 if (s->inUse16[i])
304 for (j = 0; j < 16; j++) {
305 GET_BIT(BZ_X_MAPPING_2, uc);
306 if (uc == 1) s->inUse[i * 16 + j] = True;
307 }
308 makeMaps_d ( s );
309 alphaSize = s->nInUse+2;
310
311 /*--- Now the selectors ---*/
312 GET_BITS(BZ_X_SELECTOR_1, nGroups, 3);
313 GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15);
314 for (i = 0; i < nSelectors; i++) {
315 j = 0;
316 while (True) {
317 GET_BIT(BZ_X_SELECTOR_3, uc);
318 if (uc == 0) break;
319 j++;
320 if (j > 5) RETURN(BZ_DATA_ERROR);
321 }
322 s->selectorMtf[i] = j;
323 }
324
325 /*--- Undo the MTF values for the selectors. ---*/
326 {
327 UChar pos[BZ_N_GROUPS], tmp, v;
328 for (v = 0; v < nGroups; v++) pos[v] = v;
329
330 for (i = 0; i < nSelectors; i++) {
331 v = s->selectorMtf[i];
332 tmp = pos[v];
333 while (v > 0) { pos[v] = pos[v-1]; v--; }
334 pos[0] = tmp;
335 s->selector[i] = tmp;
336 }
337 }
338
339 /*--- Now the coding tables ---*/
340 for (t = 0; t < nGroups; t++) {
341 GET_BITS(BZ_X_CODING_1, curr, 5);
342 for (i = 0; i < alphaSize; i++) {
343 while (True) {
344 if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR);
345 GET_BIT(BZ_X_CODING_2, uc);
346 if (uc == 0) break;
347 GET_BIT(BZ_X_CODING_3, uc);
348 if (uc == 0) curr++; else curr--;
349 }
350 s->len[t][i] = curr;
351 }
352 }
353
354 /*--- Create the Huffman decoding tables ---*/
355 for (t = 0; t < nGroups; t++) {
356 minLen = 32;
357 maxLen = 0;
358 for (i = 0; i < alphaSize; i++) {
359 if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
360 if (s->len[t][i] < minLen) minLen = s->len[t][i];
361 }
362 hbCreateDecodeTables (
363 &(s->limit[t][0]),
364 &(s->base[t][0]),
365 &(s->perm[t][0]),
366 &(s->len[t][0]),
367 minLen, maxLen, alphaSize
368 );
369 s->minLens[t] = minLen;
370 }
371
372 /*--- Now the MTF values ---*/
373
374 EOB = s->nInUse+1;
375 nblockMAX = 100000 * s->blockSize100k;
376 groupNo = -1;
377 groupPos = 0;
378
379 for (i = 0; i <= 255; i++) s->unzftab[i] = 0;
380
381 /*-- MTF init --*/
382 {
383 Int32 ii, jj, kk;
384 kk = MTFA_SIZE-1;
385 for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) {
386 for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
387 s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj);
388 kk--;
389 }
390 s->mtfbase[ii] = kk + 1;
391 }
392 }
393 /*-- end MTF init --*/
394
395 nblock = 0;
396
397 GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym);
398
399 while (True) {
400
401 if (nextSym == EOB) break;
402
403 if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) {
404
405 es = -1;
406 N = 1;
407 do {
408 if (nextSym == BZ_RUNA) es = es + (0+1) * N; else
409 if (nextSym == BZ_RUNB) es = es + (1+1) * N;
410 N = N * 2;
411 GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym);
412 }
413 while (nextSym == BZ_RUNA || nextSym == BZ_RUNB);
414
415 es++;
416 uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ];
417 s->unzftab[uc] += es;
418
419 if (s->smallDecompress)
420 while (es > 0) {
421 s->ll16[nblock] = (UInt16)uc;
422 nblock++;
423 es--;
424 }
425 else
426 while (es > 0) {
427 s->tt[nblock] = (UInt32)uc;
428 nblock++;
429 es--;
430 };
431
432 if (nblock > nblockMAX) RETURN(BZ_DATA_ERROR);
433 continue;
434
435 } else {
436
437 if (nblock > nblockMAX) RETURN(BZ_DATA_ERROR);
438
439 /*-- uc = MTF ( nextSym-1 ) --*/
440 {
441 Int32 ii, jj, kk, pp, lno, off;
442 UInt32 nn;
443 nn = (UInt32)(nextSym - 1);
444
445 if (nn < MTFL_SIZE) {
446 /* avoid general-case expense */
447 pp = s->mtfbase[0];
448 uc = s->mtfa[pp+nn];
449 while (nn > 3) {
450 Int32 z = pp+nn;
451 s->mtfa[(z) ] = s->mtfa[(z)-1];
452 s->mtfa[(z)-1] = s->mtfa[(z)-2];
453 s->mtfa[(z)-2] = s->mtfa[(z)-3];
454 s->mtfa[(z)-3] = s->mtfa[(z)-4];
455 nn -= 4;
456 }
457 while (nn > 0) {
458 s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--;
459 };
460 s->mtfa[pp] = uc;
461 } else {
462 /* general case */
463 lno = nn / MTFL_SIZE;
464 off = nn % MTFL_SIZE;
465 pp = s->mtfbase[lno] + off;
466 uc = s->mtfa[pp];
467 while (pp > s->mtfbase[lno]) {
468 s->mtfa[pp] = s->mtfa[pp-1]; pp--;
469 };
470 s->mtfbase[lno]++;
471 while (lno > 0) {
472 s->mtfbase[lno]--;
473 s->mtfa[s->mtfbase[lno]]
474 = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1];
475 lno--;
476 }
477 s->mtfbase[0]--;
478 s->mtfa[s->mtfbase[0]] = uc;
479 if (s->mtfbase[0] == 0) {
480 kk = MTFA_SIZE-1;
481 for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) {
482 for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
483 s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj];
484 kk--;
485 }
486 s->mtfbase[ii] = kk + 1;
487 }
488 }
489 }
490 }
491 /*-- end uc = MTF ( nextSym-1 ) --*/
492
493 s->unzftab[s->seqToUnseq[uc]]++;
494 if (s->smallDecompress)
495 s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else
496 s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]);
497 nblock++;
498
499 GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym);
500 continue;
501 }
502 }
503
504 s->state_out_len = 0;
505 s->state_out_ch = 0;
506 BZ_INITIALISE_CRC ( s->calculatedBlockCRC );
507 s->state = BZ_X_OUTPUT;
508 if (s->verbosity >= 2) VPrintf0 ( "rt+rld" );
509
510 /*-- Set up cftab to facilitate generation of T^(-1) --*/
511 s->cftab[0] = 0;
512 for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1];
513 for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1];
514
515 if (s->smallDecompress) {
516
517 /*-- Make a copy of cftab, used in generation of T --*/
518 for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i];
519
520 /*-- compute the T vector --*/
521 for (i = 0; i < nblock; i++) {
522 uc = (UChar)(s->ll16[i]);
523 SET_LL(i, s->cftabCopy[uc]);
524 s->cftabCopy[uc]++;
525 }
526
527 /*-- Compute T^(-1) by pointer reversal on T --*/
528 i = s->origPtr;
529 j = GET_LL(i);
530 do {
531 Int32 tmp = GET_LL(j);
532 SET_LL(j, i);
533 i = j;
534 j = tmp;
535 }
536 while (i != s->origPtr);
537
538 s->tPos = s->origPtr;
539 s->nblock_used = 0;
540 if (s->blockRandomised) {
541 BZ_RAND_INIT_MASK;
542 BZ_GET_SMALL(s->k0); s->nblock_used++;
543 BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK;
544 } else {
545 BZ_GET_SMALL(s->k0); s->nblock_used++;
546 }
547
548 } else {
549
550 /*-- compute the T^(-1) vector --*/
551 for (i = 0; i < nblock; i++) {
552 uc = (UChar)(s->tt[i] & 0xff);
553 s->tt[s->cftab[uc]] |= (i << 8);
554 s->cftab[uc]++;
555 }
556
557 s->tPos = s->tt[s->origPtr] >> 8;
558 s->nblock_used = 0;
559 if (s->blockRandomised) {
560 BZ_RAND_INIT_MASK;
561 BZ_GET_FAST(s->k0); s->nblock_used++;
562 BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK;
563 } else {
564 BZ_GET_FAST(s->k0); s->nblock_used++;
565 }
566
567 }
568
569 RETURN(BZ_OK);
570
571
572
573 endhdr_2:
574
575 GET_UCHAR(BZ_X_ENDHDR_2, uc);
576 if (uc != 0x72) RETURN(BZ_DATA_ERROR);
577 GET_UCHAR(BZ_X_ENDHDR_3, uc);
578 if (uc != 0x45) RETURN(BZ_DATA_ERROR);
579 GET_UCHAR(BZ_X_ENDHDR_4, uc);
580 if (uc != 0x38) RETURN(BZ_DATA_ERROR);
581 GET_UCHAR(BZ_X_ENDHDR_5, uc);
582 if (uc != 0x50) RETURN(BZ_DATA_ERROR);
583 GET_UCHAR(BZ_X_ENDHDR_6, uc);
584 if (uc != 0x90) RETURN(BZ_DATA_ERROR);
585
586 s->storedCombinedCRC = 0;
587 GET_UCHAR(BZ_X_CCRC_1, uc);
588 s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
589 GET_UCHAR(BZ_X_CCRC_2, uc);
590 s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
591 GET_UCHAR(BZ_X_CCRC_3, uc);
592 s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
593 GET_UCHAR(BZ_X_CCRC_4, uc);
594 s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
595
596 s->state = BZ_X_IDLE;
597 RETURN(BZ_STREAM_END);
598
599 default: AssertH ( False, 4001 );
600 }
601
602 AssertH ( False, 4002 );
603
604 save_state_and_return:
605
606 s->save_i = i;
607 s->save_j = j;
608 s->save_t = t;
609 s->save_alphaSize = alphaSize;
610 s->save_nGroups = nGroups;
611 s->save_nSelectors = nSelectors;
612 s->save_EOB = EOB;
613 s->save_groupNo = groupNo;
614 s->save_groupPos = groupPos;
615 s->save_nextSym = nextSym;
616 s->save_nblockMAX = nblockMAX;
617 s->save_nblock = nblock;
618 s->save_es = es;
619 s->save_N = N;
620 s->save_curr = curr;
621 s->save_zt = zt;
622 s->save_zn = zn;
623 s->save_zvec = zvec;
624 s->save_zj = zj;
625 s->save_gSel = gSel;
626 s->save_gMinlen = gMinlen;
627 s->save_gLimit = gLimit;
628 s->save_gBase = gBase;
629 s->save_gPerm = gPerm;
630
631 return retVal;
632 }
633
634
635 /*-------------------------------------------------------------*/
636 /*--- end decompress.c ---*/
637 /*-------------------------------------------------------------*/
638