File Coverage

lib/Archive/Lha.xs
Criterion Covered Total %
statement 262 326 80.3
branch 93 158 58.8
condition n/a
subroutine n/a
pod n/a
total 355 484 73.3


line stmt bran cond sub pod time code
1             /*
2             XS for Archive::Lha
3            
4             This XS is, though largely modified, based on LHa for UNIX.
5             See lib/Archive/Lha.pm for Authors/Copyright/License information.
6             */
7             #include "EXTERN.h"
8             #include "perl.h"
9             #include "XSUB.h"
10             #include "ppport.h"
11             #include "Lha.h"
12             #include
13            
14             /*
15             these are not from LHa for UNIX
16             */
17            
18             void
19 19           destroy_stash(LhaStash * stash)
20             {
21 19           Safefree(stash->tree->left);
22 19           Safefree(stash->tree->right);
23 19           Safefree(stash->tree);
24 19           Safefree(stash->pt->table);
25 19           Safefree(stash->pt->length);
26 19           Safefree(stash->pt);
27 19           Safefree(stash->c->table);
28 19           Safefree(stash->c->length);
29 19           Safefree(stash->c);
30 19           Safefree(stash->bit);
31 19           Safefree(stash->queue);
32 19           Safefree(stash);
33 19           }
34            
35             void
36 0           safe_croak(LhaStash * stash, char * dying_message)
37             {
38 0           destroy_stash(stash);
39 0           croak("%s", dying_message);
40             }
41            
42             void
43 19           output(LhaStash * stash, unsigned char * queue, int len)
44             {
45 19           dSP;
46 19           ENTER;
47 19           SAVETMPS;
48 19 50         PUSHMARK(SP);
49 19 50         XPUSHs(sv_2mortal(newSVpv(queue, len)));
50 19           PUTBACK;
51 19           call_sv(stash->write, G_VOID);
52 19           SPAGAIN;
53 19           PUTBACK;
54 19 50         FREETMPS;
55 19           LEAVE;
56 19           }
57            
58             void
59 19           input(LhaStash * stash, int len)
60             {
61             int n;
62             SV *sv;
63             STRLEN got;
64             const char *ptr;
65 19           dSP;
66 19           ENTER;
67 19           SAVETMPS;
68 19 50         PUSHMARK(SP);
69 19 50         XPUSHs(sv_2mortal(newSViv(len)));
70 19           PUTBACK;
71 19           n = call_sv(stash->read, G_SCALAR);
72 19           SPAGAIN;
73 19 50         if (n != 1)
74 0           safe_croak(stash, "There's something wrong in 'read' callback");
75 19           sv = POPs;
76 19           ptr = SvPVbyte(sv, got);
77 19           Copy(ptr, stash->bit->readbuf, (STRLEN)len <= got ? (STRLEN)len : got, unsigned char);
78 19           PUTBACK;
79 19 50         FREETMPS;
80 19           LEAVE;
81 19           }
82            
83             /*
84             modified from LHa for UNIX: bitio.c ver 1.14
85             original authors:
86             Source All chagned 1995.01.14 N.Watazaki
87             Separated from crcio.c 2002.10.26 Koji Arai
88             */
89            
90             unsigned short
91 9638           shiftbits(LhaBitstream * bit, unsigned char n)
92             {
93 9638           return (bit->value << n)
94 9638           + (bit->buf >> (char_bit - n));
95             }
96            
97             void
98 6192           fillbuf(LhaStash * stash, unsigned char n)
99             {
100             unsigned short len;
101 6192           LhaBitstream * bit = stash->bit;
102 9638 100         while (n > bit->pos) {
103 3446           n -= bit->pos;
104 3446           bit->value = shiftbits(bit, bit->pos);
105 3446 100         if (stash->encoded_size > 0) {
106 3408 100         if (bit->readpos == 0) {
107 19 50         if (stash->encoded_size > readbuf_size)
108 0           len = readbuf_size;
109             else
110 19           len = stash->encoded_size;
111 19           input(stash, len);
112             }
113 3408           bit->buf = bit->readbuf[bit->readpos++];
114 3408 50         if (bit->readpos == readbuf_size)
115 0           bit->readpos = 0;
116 3408           stash->encoded_size--;
117             }
118             else
119 38           bit->buf = 0;
120 3446           bit->pos = char_bit;
121             }
122 6192           bit->pos -= n;
123 6192           bit->value = shiftbits(bit, n);
124 6192           bit->buf <<= n;
125 6192           }
126            
127             unsigned short
128 6173           peekbits(LhaStash * stash, unsigned char n)
129             {
130 6173           return (stash->bit->value >> (ushort_bit - n));
131             }
132            
133             unsigned short
134 727           getbits(LhaStash * stash, unsigned char n)
135             {
136 727           unsigned short bits = peekbits(stash, n);
137 727           fillbuf(stash, n);
138 727           return bits;
139             }
140            
141             void
142 19           init_bitstream(LhaStash * stash)
143             {
144             LhaBitstream * bitstream;
145            
146 19           Newxz(bitstream, 1, LhaBitstream);
147 19           stash->bit = bitstream;
148            
149 19           stash->bit->blocksize = 0;
150 19           stash->bit->readpos = 0;
151 19           stash->bit->value = 0;
152 19           stash->bit->buf = 0;
153 19           stash->bit->pos = 0;
154 19           fillbuf(stash, ushort_bit);
155 19           }
156            
157             /*
158             modified from LHa for UNIX: maketbl.c ver 1.14
159             original author(s):
160             Source All chagned 1995.01.14 N.Watazaki
161             */
162            
163             void
164 56           make_table(LhaStash * stash, LhaTable * table, unsigned short nchar)
165             {
166             unsigned short count[ushort_bit + 1];
167             unsigned short weight[ushort_bit + 1];
168             unsigned short start[ushort_bit + 1];
169             unsigned short total, avail;
170             unsigned short from, to;
171             unsigned char bits_to_shift, bit;
172             unsigned int i, j, l;
173             char n;
174             unsigned short *p;
175            
176 56 50         if (table->bit > ushort_bit) {
177 0           safe_croak(stash, "Table is broken: table bit is too large");
178             }
179            
180 952 100         for(i = 1; i <= ushort_bit; i++) {
181 896           count[i] = 0;
182 896           weight[i] = 1u << (ushort_bit - i);
183             }
184            
185 10383 100         for(i = 0; i < nchar; i++)
186 10327 50         if (table->length[i] > ushort_bit) {
187 0           safe_croak(stash, "Table is broken: bit length is too large");
188             }
189             else
190 10327           count[table->length[i]]++;
191            
192 56           total = 0;
193 952 100         for(i = 1; i <= ushort_bit; i++) {
194 896           start[i] = total;
195 896           total += weight[i] * count[i];
196             }
197 56 50         if (total & ushort_max) {
198 0           safe_croak(stash, "Table is broken: total mismatch");
199             }
200            
201 56           bits_to_shift = ushort_bit - table->bit;
202 580 100         for(i = 1; i <= table->bit; i++) {
203 524           start[i] >>= bits_to_shift;
204 524           weight[i] >>= bits_to_shift;
205             }
206            
207 56           from = start[table->bit + 1] >> bits_to_shift;
208 56           to = min(1u << table->bit, table->size);
209 56 50         if (from)
210 0 0         for(i = from; i < to; i++)
211 0           table->table[i] = 0;
212            
213 56           avail = nchar;
214 10383 100         for(i = 0; i < nchar; i++) {
215 10327           bit = table->length[i];
216 10327 100         if (bit == 0)
217 9087           continue;
218 1240           l = start[bit] + weight[bit];
219 1240 50         if (bit <= table->bit) {
220 1240           l = min(l, table->size);
221 88536 100         for(j = start[bit]; j < l; j++)
222 87296           table->table[j] = i;
223             }
224             else {
225 0           j = start[bit];
226 0 0         if ((j >> bits_to_shift) > table->size) {
227 0           safe_croak(stash, "Table is broken");
228             }
229 0           p = &(table->table[j >> bits_to_shift]);
230 0           j <<= table->bit;
231 0           n = bit - table->bit;
232 0 0         while (--n >= 0) {
233 0 0         if (*p == 0) {
234 0           stash->tree->right[avail] = stash->tree->left[avail] = 0;
235 0           *p = avail++;
236             }
237 0 0         if (j & ushort_center)
238 0           p = &(stash->tree->right[*p]);
239             else
240 0           p = &(stash->tree->left[*p]);
241 0           j <<= 1;
242             }
243 0           *p = i;
244             }
245 1240           start[bit] = l;
246             }
247 56           }
248            
249             /*
250             modified from LHa for UNIX: huf.c ver 1.14
251             original authors:
252             Source All chagned 1995.01.14 N.Watazaki
253             Support LH7 & Bug Fixed 2000.10. 6 t.okamoto
254             */
255            
256             void
257 38           read_pt_len(LhaStash * stash, short nn, unsigned char nbit, short threshold)
258             {
259             int i, c;
260             unsigned short n, mask;
261            
262 38           n = getbits(stash, nbit);
263 38 100         if (n == 0) {
264 1           c = getbits(stash, nbit);
265 15 100         for(i = 0; i < nn; i++)
266 14           stash->pt->length[i] = 0;
267 257 100         for(i = 0; i < stash->pt->size; i++)
268 256           stash->pt->table[i] = c;
269             }
270             else {
271 37           i = 0;
272 383 100         while (i < min(n, stash->pt->length_size)) {
273 309           c = peekbits(stash, 3);
274 309 100         if (c != 7)
275 307           fillbuf(stash, 3);
276             else {
277 2           mask = create_mask(3);
278 2 50         while (stash->bit->value & mask) {
279 0           mask >>= 1;
280 0           c++;
281             }
282 2           fillbuf(stash, (unsigned char)(c - 3));
283             }
284 309           stash->pt->length[i++] = c;
285 309 100         if (i == threshold) {
286 19           c = getbits(stash, 2);
287 60 100         while (--c >= 0 && i < stash->pt->length_size)
    50          
288 41           stash->pt->length[i++] = 0;
289             }
290             }
291 324 100         while (i < nn)
292 287           stash->pt->length[i++] = 0;
293 37           make_table(stash, stash->pt, nn);
294             }
295 38           }
296            
297             void
298 19           read_c_len(LhaStash * stash)
299             {
300             short i, c, n;
301             unsigned short mask;
302            
303 19           n = getbits(stash, stash->CBIT);
304 19 50         if (n == 0) {
305 0           c = getbits(stash, stash->CBIT);
306 0 0         for(i = 0; i < stash->c->length_size; i++)
307 0           stash->c->length[i] = 0;
308 0 0         for(i = 0; i < stash->c->size; i++)
309 0           stash->c->table[i] = c;
310             }
311             else {
312 19           i = 0;
313 1583 100         while (i < min(n, stash->c->length_size)) {
314 1564           c = stash->pt->table[peekbits(stash, stash->pt->bit)];
315 1564 50         if (c >= stash->NT) {
316 0           mask = create_mask(stash->pt->bit);
317             do {
318 0 0         if (stash->bit->value & mask)
319 0           c = stash->tree->right[c];
320             else
321 0           c = stash->tree->left[c];
322 0           mask >>= 1;
323 0 0         } while (c >= stash->NT && (mask || c != stash->tree->left[c]));
    0          
    0          
324             }
325 1564           fillbuf(stash, stash->pt->length[c]);
326 1564 100         if (c <= 2) {
327 566 100         if (c == 0)
328 376           c = 1;
329 190 100         else if (c == 1)
330 164           c = getbits(stash, 4) + 3;
331             else
332 26           c = getbits(stash, stash->CBIT) + 20;
333 5238 100         while (--c >= 0)
334 4672           stash->c->length[i++] = 0;
335             }
336             else
337 998           stash->c->length[i++] = c - 2;
338             }
339 4039 100         while (i < stash->c->length_size)
340 4020           stash->c->length[i++] = 0;
341 19           make_table(stash, stash->c, stash->c->length_size);
342             }
343 19           }
344            
345             unsigned short
346 3130           decode_c(LhaStash * stash)
347             {
348             unsigned short j, mask;
349            
350 3130 100         if (stash->bit->blocksize == 0) {
351 19           stash->bit->blocksize = getbits(stash, ushort_bit);
352 19           read_pt_len(stash, stash->NT, stash->TBIT, 3);
353 19           read_c_len(stash);
354 19           read_pt_len(stash, stash->NP, stash->PBIT, -1);
355             }
356 3130           stash->bit->blocksize--;
357 3130           j = stash->c->table[peekbits(stash, stash->c->bit)];
358 3130 50         if (j < stash->c->length_size)
359 3130           fillbuf(stash, stash->c->length[j]);
360             else {
361 0           fillbuf(stash, stash->c->bit);
362 0           mask = create_mask(0);
363             do {
364 0 0         if (stash->bit->value & mask)
365 0           j = stash->tree->right[j];
366             else
367 0           j = stash->tree->left[j];
368 0           mask >>= 1;
369 0 0         } while (j >= stash->c->length_size && (mask || j != stash->tree->left[j]));
    0          
    0          
370 0           fillbuf(stash, (unsigned char)(stash->c->length[j] - stash->c->bit));
371             }
372 3130           return j;
373             }
374            
375             unsigned short
376 443           decode_p(LhaStash * stash)
377             {
378             unsigned short j, mask;
379            
380 443           j = stash->pt->table[peekbits(stash, stash->pt->bit)];
381 443 50         if (j < stash->NP)
382 443           fillbuf(stash, stash->pt->length[j]);
383             else {
384 0           fillbuf(stash, stash->pt->bit);
385 0           mask = create_mask(0);
386             do {
387 0 0         if (stash->bit->value & mask)
388 0           j = stash->tree->right[j];
389             else
390 0           j = stash->tree->left[j];
391 0           mask >>= 1;
392 0 0         } while (j >= stash->NP && (mask || j != stash->tree->left[j]));
    0          
    0          
393 0           fillbuf(stash, (unsigned char)(stash->pt->length[j] - stash->pt->bit));
394             }
395 443 100         if (j != 0)
396 441           j = (1u << (j - 1)) + getbits(stash, (unsigned char)(j - 1));
397 443           return j;
398             }
399            
400             /*
401             modified from LHa for UNIX: crcio.c ver 1.14
402             original author(s):
403             Source All chagned 1995.01.14 N.Watazaki
404             */
405            
406             unsigned short
407 27           calc_crc16(unsigned short crc, unsigned char * str, unsigned int len)
408             {
409 12210 100         while (len-- > 0)
410 12183           crc = crctable[(crc ^ *str++) & uchar_max] ^ (crc >> char_bit);
411 27           return crc;
412             }
413            
414             /*
415             this is not from LHa for UNIX
416             */
417            
418             void
419 19           init_tables(HV * self, LhaStash * stash)
420             {
421             LhaTable * pt_table;
422             LhaTable * c_table;
423             LhaTree * tree;
424            
425 19           stash->NPT = self_ushort("NPT");
426 19           stash->NP = self_ushort("NP");
427 19           stash->NT = self_ushort("NT");
428 19           stash->NC = self_ushort("NC");
429 19           stash->PBIT = self_uchar("PBIT");
430 19           stash->TBIT = self_uchar("TBIT");
431 19           stash->CBIT = self_uchar("CBIT");
432            
433 19           Newxz(pt_table, 1, LhaTable);
434 19           Newxz(c_table, 1, LhaTable);
435 19           Newxz(tree, 1, LhaTree);
436            
437 19           pt_table->bit = self_uchar("PT_TABLE_BIT");
438 19           pt_table->size = self_ushort("PT_TABLE_SIZE");
439 19           pt_table->length_size = stash->NPT;
440            
441 19           Newxz(pt_table->table, pt_table->size, unsigned short);
442 19           Newxz(pt_table->length, pt_table->length_size, unsigned char);
443            
444 19           c_table->bit = self_uchar("C_TABLE_BIT");
445 19           c_table->size = self_ushort("C_TABLE_SIZE");
446 19           c_table->length_size = stash->NC;
447            
448 19           Newxz(c_table->table, c_table->size, unsigned short);
449 19           Newxz(c_table->length, c_table->length_size, unsigned char);
450            
451 19           Newxz(tree->left, 2 * stash->NC - 1, unsigned short);
452 19           Newxz(tree->right, 2 * stash->NC - 1, unsigned short);
453            
454 19           stash->tree = tree;
455 19           stash->pt = pt_table;
456 19           stash->c = c_table;
457 19           }
458            
459             MODULE = Archive::Lha PACKAGE = Archive::Lha::Decode::Base PREFIX = xs_
460            
461             PROTOTYPES: DISABLE
462            
463             #/*
464             # modified from LHa for UNIX: slide.c ver 1.14
465             # original authors:
466             # Modified Nobutaka Watazaki
467             # Ver. 1.14d Exchanging a search algorithm 1997.01.11 T.Okamoto
468             #*/
469            
470             unsigned short
471             xs_decode(hashref)
472             SV * hashref;
473             CODE:
474             HV * self;
475             unsigned char * queue;
476             LhaStash * stash;
477             unsigned short crc16;
478             int i, c, matchlen, matchoff, matchpos, adjust;
479             unsigned int dicsize, dicsize1, total, loc;
480            
481 19           dSP;
482 19           self = (HV *) SvRV(hashref);
483            
484 19 50         if ( !hash_exists(self, "read") )
485 0           croak("'read' callback is missing");
486 19 50         if ( !hash_exists(self, "write") )
487 0           croak("'write' callback is missing");
488            
489 19           dicsize = self_uint("DICSIZE");
490 19           dicsize1 = dicsize - 1;
491            
492 19           Newxz(queue, dicsize, unsigned char);
493 19           Newxz(stash, 1, LhaStash);
494            
495 19           stash->queue = queue;
496            
497 19           stash->read = self_sv("read");
498 19           stash->write = self_sv("write");
499 19           stash->original_size = self_uint("original_size");
500 19           stash->encoded_size = self_uint("encoded_size");
501            
502 19           init_tables(self, stash);
503 19           init_bitstream(stash);
504            
505 19           adjust = (1u << uchar_bit) - self_uchar("THRESHOLD");
506 19           crc16 = 0;
507 19           loc = 0;
508 19           total = 0;
509 3149 100         while ( total < stash->original_size ) {
510 3130           c = decode_c(stash);
511 3130 100         if (c <= uchar_max) {
512 2687           queue[loc++] = c;
513 2687 50         if (loc == dicsize) {
514 0           output(stash, queue, dicsize);
515 0           crc16 = calc_crc16(crc16, queue, dicsize);
516 0           loc = 0;
517             }
518 2687           total++;
519             }
520             else {
521 443           matchlen = c - adjust;
522 443           matchoff = decode_p(stash) + 1;
523 443           matchpos = (loc - matchoff) & dicsize1;
524 443           total += matchlen;
525 5655 100         for(i = 0; i < matchlen; i++) {
526 5212           queue[loc++] = queue[(matchpos + i) & dicsize1];
527 5212 50         if (loc == dicsize) {
528 0           output(stash, queue, dicsize);
529 0           crc16 = calc_crc16(crc16, queue, dicsize);
530 0           loc = 0;
531             }
532             }
533             }
534             }
535 19 50         if (loc) {
536 19           output(stash, queue, loc);
537 19           crc16 = calc_crc16(crc16, queue, loc);
538             }
539            
540 19           destroy_stash(stash);
541            
542 19 100         RETVAL = crc16;
543            
544             OUTPUT:
545             RETVAL
546            
547             MODULE = Archive::Lha PACKAGE = Archive::Lha::CRC PREFIX = xs_
548            
549             PROTOTYPES: DISABLE
550            
551             #/* this is not from LHa for UNIX */
552            
553             unsigned short
554             xs_update(unsigned short crc, SV * str, STRLEN len)
555             CODE:
556 8           RETVAL = calc_crc16(crc, SvPV(str, len), len);
557            
558             OUTPUT:
559             RETVAL
560            
561             MODULE = Archive::Lha PACKAGE = Archive::Lha::Header::Utils PREFIX = xs_
562            
563             PROTOTYPES: DISABLE
564            
565             unsigned char
566             xs_checksum(SV * buf, STRLEN offset)
567             CODE:
568             STRLEN len;
569 239           unsigned char * s = (unsigned char *) SvPV(buf, len);
570 239           unsigned char sum = 0;
571             STRLEN i;
572 9342 100         for (i = offset; i < len; i++)
573 9103           sum += s[i];
574 239 100         RETVAL = sum;
575             OUTPUT:
576             RETVAL
577            
578             IV
579             xs_dostime2utime(U32 v)
580             CODE:
581             struct tm t;
582             time_t result;
583 2 50         if (v == 0) {
584 0           RETVAL = 0;
585             } else {
586 2           t.tm_sec = (v & 0x1F) * 2;
587 2           t.tm_min = (v >> 5) & 0x3F;
588 2           t.tm_hour = (v >> 11) & 0x1F;
589 2           t.tm_mday = (v >> 16) & 0x1F;
590 2           t.tm_mon = ((v >> 21) & 0x0F) - 1;
591 2           t.tm_year = ((v >> 25) & 0x7F) + 80;
592 2           t.tm_isdst = -1;
593 2           result = mktime(&t);
594 2 50         RETVAL = (result == (time_t)-1) ? 0 : (IV)result;
595             }
596             OUTPUT:
597             RETVAL
598            
599             MODULE = Archive::Lha PACKAGE = Archive::Lha PREFIX = xs_
600            
601             PROTOTYPES: DISABLE