pack.c
DEFINITIONS
This source file includes following functions.
- OFF16B
- OFF32B
- NATINT_I32
- NATINT_U32
- NATINT_LEN
- OFF16
- OFF32
- NATINT_I32
- NATINT_U32
- NATINT_LEN
- OFF16
- OFF32
- OFF16B
- OFF32B
- swapd
- swapd
- endian
- pack_pack
- encodes
- qpencode
- hex2num
- infected_str_new
- pack_unpack
- uv_to_utf8
- utf8_to_uv
- Init_pack
1
2
3
4
5
6
7
8
9
10
11
12
13 #include "ruby.h"
14 #include <sys/types.h>
15 #include <ctype.h>
16
17 #define SIZE16 2
18 #define SIZE32 4
19
20 #if SIZEOF_SHORT != 2 || SIZEOF_LONG != 4
21 # define NATINT_PACK
22 #endif
23
24 #ifdef NATINT_PACK
25 # define OFF16B(p) ((char*)(p) + (natint?0:(sizeof(short) - SIZE16)))
26 # define OFF32B(p) ((char*)(p) + (natint?0:(sizeof(long) - SIZE32)))
27 # define NATINT_I32(x) (natint?NUM2LONG(x):(NUM2I32(x)))
28 # define NATINT_U32(x) (natint?NUM2ULONG(x):(NUM2U32(x)))
29 # define NATINT_LEN(type,len) (natint?sizeof(type):(len))
30 # ifdef WORDS_BIGENDIAN
31 # define OFF16(p) OFF16B(p)
32 # define OFF32(p) OFF32B(p)
33 # endif
34 #else
35 # define NATINT_I32(x) NUM2I32(x)
36 # define NATINT_U32(x) NUM2U32(x)
37 # define NATINT_LEN(type,len) sizeof(type)
38 #endif
39
40 #ifndef OFF16
41 # define OFF16(p) (char*)(p)
42 # define OFF32(p) (char*)(p)
43 #endif
44
45 #ifndef OFF16B
46 # define OFF16B(p) (char*)(p)
47 # define OFF32B(p) (char*)(p)
48 #endif
49
50 #define define_swapx(x, xtype) \
51 static xtype \
52 TOKEN_PASTE(swap,x)(z) \
53 xtype z; \
54 { \
55 xtype r; \
56 xtype *zp; \
57 unsigned char *s, *t; \
58 int i; \
59 \
60 zp = (xtype *)malloc(sizeof(xtype));\
61 *zp = z; \
62 s = (char *)zp; \
63 t = (char *)malloc(sizeof(xtype)); \
64 for (i=0; i<sizeof(xtype); i++) { \
65 t[sizeof(xtype)-i-1] = s[i]; \
66 } \
67 r = *(xtype *)t; \
68 free(t); \
69 free(zp); \
70 return r; \
71 }
72
73 #if SIZEOF_SHORT == 2
74 #define swaps(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
75 #else
76 #if SIZEOF_SHORT == 4
77 #define swaps(x) ((((x)&0xFF)<<24) \
78 |(((x)>>24)&0xFF) \
79 |(((x)&0x0000FF00)<<8) \
80 |(((x)&0x00FF0000)>>8) )
81 #else
82 define_swapx(s,short);
83 #endif
84 #endif
85
86 #if SIZEOF_LONG == 4
87 #define swapl(x) ((((x)&0xFF)<<24) \
88 |(((x)>>24)&0xFF) \
89 |(((x)&0x0000FF00)<<8) \
90 |(((x)&0x00FF0000)>>8) )
91 #else
92 #if SIZEOF_LONG == 8
93 #define swapl(x) ((((x)&0x00000000000000FF)<<56) \
94 |(((x)&0xFF00000000000000)>>56) \
95 |(((x)&0x000000000000FF00)<<40) \
96 |(((x)&0x00FF000000000000)>>40) \
97 |(((x)&0x0000000000FF0000)<<24) \
98 |(((x)&0x0000FF0000000000)>>24) \
99 |(((x)&0x00000000FF000000)<<8) \
100 |(((x)&0x000000FF00000000)>>8))
101 #else
102 define_swapx(l,long);
103 #endif
104 #endif
105
106 #if SIZEOF_FLOAT == 4
107 #if SIZEOF_LONG == 4
108 #define swapf(x) swapl(x)
109 #define FLOAT_SWAPPER unsigned long
110 #else
111 #if SIZEOF_SHORT == 4
112 #define swapf(x) swaps(x)
113 #define FLOAT_SWAPPER unsigned short
114 #else
115 define_swapx(f,float);
116 #endif
117 #endif
118 #else
119 define_swapx(f,float);
120 #endif
121
122 #if SIZEOF_DOUBLE == 8
123 #if SIZEOF_LONG == 8
124 #define swapd(x) swapl(x)
125 #define DOUBLE_SWAPPER unsigned long
126 #else
127 #if SIZEOF_LONG == 4
128 static double
129 swapd(d)
130 const double d;
131 {
132 double dtmp = d;
133 unsigned long utmp[2];
134 unsigned long utmp0;
135
136 utmp[0] = 0; utmp[1] = 0;
137 memcpy(utmp,&dtmp,sizeof(double));
138 utmp0 = utmp[0];
139 utmp[0] = swapl(utmp[1]);
140 utmp[1] = swapl(utmp0);
141 memcpy(&dtmp,utmp,sizeof(double));
142 return dtmp;
143 }
144 #else
145 #if SIZEOF_SHORT == 4
146 static double
147 swapd(d)
148 const double d;
149 {
150 double dtmp = d;
151 unsigned short utmp[2];
152 unsigned short utmp0;
153
154 utmp[0] = 0; utmp[1] = 0;
155 memcpy(utmp,&dtmp,sizeof(double));
156 utmp0 = utmp[0];
157 utmp[0] = swaps(utmp[1]);
158 utmp[1] = swaps(utmp0);
159 memcpy(&dtmp,utmp,sizeof(double));
160 return dtmp;
161 }
162 #else
163 define_swapx(d, double);
164 #endif
165 #endif
166 #endif
167 #else
168 define_swapx(d, double);
169 #endif
170
171 #undef define_swapx
172
173 #ifdef DYNAMIC_ENDIAN
174 #ifdef ntohs
175 #undef ntohs
176 #undef ntohl
177 #undef htons
178 #undef htonl
179 #endif
180 static int
181 endian()
182 {
183 static int init = 0;
184 static int endian_value;
185 char *p;
186
187 if (init) return endian_value;
188 init = 1;
189 p = (char*)&init;
190 return endian_value = p[0]?0:1;
191 }
192
193 #define ntohs(x) (endian()?(x):swaps(x))
194 #define ntohl(x) (endian()?(x):swapl(x))
195 #define ntohf(x) (endian()?(x):swapf(x))
196 #define ntohd(x) (endian()?(x):swapd(x))
197 #define htons(x) (endian()?(x):swaps(x))
198 #define htonl(x) (endian()?(x):swapl(x))
199 #define htonf(x) (endian()?(x):swapf(x))
200 #define htond(x) (endian()?(x):swapd(x))
201 #define htovs(x) (endian()?swaps(x):(x))
202 #define htovl(x) (endian()?swapl(x):(x))
203 #define htovf(x) (endian()?swapf(x):(x))
204 #define htovd(x) (endian()?swapd(x):(x))
205 #define vtohs(x) (endian()?swaps(x):(x))
206 #define vtohl(x) (endian()?swapl(x):(x))
207 #define vtohf(x) (endian()?swapf(x):(x))
208 #define vtohd(x) (endian()?swapd(x):(x))
209 #else
210 #ifdef WORDS_BIGENDIAN
211 #ifndef ntohs
212 #define ntohs(x) (x)
213 #define ntohl(x) (x)
214 #define htons(x) (x)
215 #define htonl(x) (x)
216 #endif
217 #define ntohf(x) (x)
218 #define ntohd(x) (x)
219 #define htonf(x) (x)
220 #define htond(x) (x)
221 #define htovs(x) swaps(x)
222 #define htovl(x) swapl(x)
223 #define htovf(x) swapf(x)
224 #define htovd(x) swapd(x)
225 #define vtohs(x) swaps(x)
226 #define vtohl(x) swapl(x)
227 #define vtohf(x) swapf(x)
228 #define vtohd(x) swapd(x)
229 #else
230 #ifndef ntohs
231 #undef ntohs
232 #undef ntohl
233 #undef htons
234 #undef htonl
235 #define ntohs(x) swaps(x)
236 #define ntohl(x) swapl(x)
237 #define htons(x) swaps(x)
238 #define htonl(x) swapl(x)
239 #endif
240 #define ntohf(x) swapf(x)
241 #define ntohd(x) swapd(x)
242 #define htonf(x) swapf(x)
243 #define htond(x) swapd(x)
244 #define htovs(x) (x)
245 #define htovl(x) (x)
246 #define htovf(x) (x)
247 #define htovd(x) (x)
248 #define vtohs(x) (x)
249 #define vtohl(x) (x)
250 #define vtohf(x) (x)
251 #define vtohd(x) (x)
252 #endif
253 #endif
254
255 #ifdef FLOAT_SWAPPER
256 #define FLOAT_CONVWITH(y) FLOAT_SWAPPER y;
257 #define HTONF(x,y) (memcpy(&y,&x,sizeof(float)), \
258 y = htonf((FLOAT_SWAPPER)y), \
259 memcpy(&x,&y,sizeof(float)), \
260 x)
261 #define HTOVF(x,y) (memcpy(&y,&x,sizeof(float)), \
262 y = htovf((FLOAT_SWAPPER)y), \
263 memcpy(&x,&y,sizeof(float)), \
264 x)
265 #define NTOHF(x,y) (memcpy(&y,&x,sizeof(float)), \
266 y = ntohf((FLOAT_SWAPPER)y), \
267 memcpy(&x,&y,sizeof(float)), \
268 x)
269 #define VTOHF(x,y) (memcpy(&y,&x,sizeof(float)), \
270 y = vtohf((FLOAT_SWAPPER)y), \
271 memcpy(&x,&y,sizeof(float)), \
272 x)
273 #else
274 #define FLOAT_CONVWITH(y)
275 #define HTONF(x,y) htonf(x)
276 #define HTOVF(x,y) htovf(x)
277 #define NTOHF(x,y) ntohf(x)
278 #define VTOHF(x,y) vtohf(x)
279 #endif
280
281 #ifdef DOUBLE_SWAPPER
282 #define DOUBLE_CONVWITH(y) DOUBLE_SWAPPER y;
283 #define HTOND(x,y) (memcpy(&y,&x,sizeof(double)), \
284 y = htond((DOUBLE_SWAPPER)y), \
285 memcpy(&x,&y,sizeof(double)), \
286 x)
287 #define HTOVD(x,y) (memcpy(&y,&x,sizeof(double)), \
288 y = htovd((DOUBLE_SWAPPER)y), \
289 memcpy(&x,&y,sizeof(double)), \
290 x)
291 #define NTOHD(x,y) (memcpy(&y,&x,sizeof(double)), \
292 y = ntohd((DOUBLE_SWAPPER)y), \
293 memcpy(&x,&y,sizeof(double)), \
294 x)
295 #define VTOHD(x,y) (memcpy(&y,&x,sizeof(double)), \
296 y = vtohd((DOUBLE_SWAPPER)y), \
297 memcpy(&x,&y,sizeof(double)), \
298 x)
299 #else
300 #define DOUBLE_CONVWITH(y)
301 #define HTOND(x,y) htond(x)
302 #define HTOVD(x,y) htovd(x)
303 #define NTOHD(x,y) ntohd(x)
304 #define VTOHD(x,y) vtohd(x)
305 #endif
306
307 #if SIZEOF_LONG == SIZE32
308 typedef long I32;
309 typedef unsigned long U32;
310 #define NUM2I32(x) NUM2LONG(x)
311 #define NUM2U32(x) NUM2ULONG(x)
312 #elif SIZEOF_INT == SIZE32
313 typedef int I32;
314 typedef unsigned int U32;
315 #define NUM2I32(x) NUM2INT(x)
316 #define NUM2U32(x) NUM2UINT(x)
317 #endif
318
319 #ifdef HAVE_LONG_LONG
320 # define QUAD_SIZE sizeof(LONG_LONG)
321 #else
322 # define QUAD_SIZE 8
323 #endif
324 static char *toofew = "too few arguments";
325
326 static void encodes _((VALUE,char*,long,int));
327 static void qpencode _((VALUE,VALUE,long));
328
329 static int uv_to_utf8 _((char*,unsigned long));
330 static unsigned long utf8_to_uv _((char*,long*));
331
332 static VALUE
333 pack_pack(ary, fmt)
334 VALUE ary, fmt;
335 {
336 static char *nul10 = "\0\0\0\0\0\0\0\0\0\0";
337 static char *spc10 = " ";
338 char *p, *pend;
339 VALUE res, from, associates = 0;
340 char type;
341 long items, len, idx, plen;
342 char *ptr;
343 #ifdef NATINT_PACK
344 int natint;
345 #endif
346
347 StringValue(fmt);
348 p = RSTRING(fmt)->ptr;
349 pend = p + RSTRING(fmt)->len;
350 res = rb_str_buf_new(0);
351
352 items = RARRAY(ary)->len;
353 idx = 0;
354
355 #define THISFROM RARRAY(ary)->ptr[idx]
356 #define NEXTFROM (items-- > 0 ? RARRAY(ary)->ptr[idx++] : (rb_raise(rb_eArgError, toofew),0))
357
358 while (p < pend) {
359 type = *p++;
360 #ifdef NATINT_PACK
361 natint = 0;
362 #endif
363
364 if (ISSPACE(type)) continue;
365 if (type == '#') {
366 while ((p < pend) && (*p != '\n')) {
367 p++;
368 }
369 continue;
370 }
371 if (*p == '_' || *p == '!') {
372 char *natstr = "sSiIlL";
373
374 if (strchr(natstr, type)) {
375 #ifdef NATINT_PACK
376 natint = 1;
377 #endif
378 p++;
379 }
380 else {
381 rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, natstr);
382 }
383 }
384 if (*p == '*') {
385 len = strchr("@Xxu", type) ? 0 : items;
386 p++;
387 }
388 else if (ISDIGIT(*p)) {
389 len = strtoul(p, (char**)&p, 10);
390 }
391 else {
392 len = 1;
393 }
394
395 switch (type) {
396 case 'A': case 'a': case 'Z':
397 case 'B': case 'b':
398 case 'H': case 'h':
399 from = NEXTFROM;
400 if (NIL_P(from)) {
401 ptr = "";
402 plen = 0;
403 }
404 else {
405 StringValue(from);
406 ptr = RSTRING(from)->ptr;
407 plen = RSTRING(from)->len;
408 OBJ_INFECT(res, from);
409 }
410
411 if (p[-1] == '*')
412 len = plen;
413
414 switch (type) {
415 case 'a':
416 case 'A':
417 case 'Z':
418 if (plen >= len)
419 rb_str_buf_cat(res, ptr, len);
420 else {
421 rb_str_buf_cat(res, ptr, plen);
422 len -= plen;
423 while (len >= 10) {
424 rb_str_buf_cat(res, (type == 'A')?spc10:nul10, 10);
425 len -= 10;
426 }
427 rb_str_buf_cat(res, (type == 'A')?spc10:nul10, len);
428 }
429 break;
430
431 case 'b':
432 {
433 int byte = 0;
434 long i, j = 0;
435
436 if (len > plen) {
437 j = (len - plen + 1)/2;
438 len = plen;
439 }
440 for (i=0; i++ < len; ptr++) {
441 if (*ptr & 1)
442 byte |= 128;
443 if (i & 7)
444 byte >>= 1;
445 else {
446 char c = byte & 0xff;
447 rb_str_buf_cat(res, &c, 1);
448 byte = 0;
449 }
450 }
451 if (len & 7) {
452 char c;
453 byte >>= 7 - (len & 7);
454 c = byte & 0xff;
455 rb_str_buf_cat(res, &c, 1);
456 }
457 rb_str_buf_cat(res, 0, j);
458 }
459 break;
460
461 case 'B':
462 {
463 int byte = 0;
464 long i, j = 0;
465
466 if (len > plen) {
467 j = (len - plen + 1)/2;
468 len = plen;
469 }
470 for (i=0; i++ < len; ptr++) {
471 byte |= *ptr & 1;
472 if (i & 7)
473 byte <<= 1;
474 else {
475 char c = byte & 0xff;
476 rb_str_buf_cat(res, &c, 1);
477 byte = 0;
478 }
479 }
480 if (len & 7) {
481 char c;
482 byte <<= 7 - (len & 7);
483 c = byte & 0xff;
484 rb_str_buf_cat(res, &c, 1);
485 }
486 rb_str_buf_cat(res, 0, j);
487 }
488 break;
489
490 case 'h':
491 {
492 int byte = 0;
493 long i, j = 0;
494
495 if (len > plen) {
496 j = (len - plen + 1)/2;
497 len = plen;
498 }
499 for (i=0; i++ < len; ptr++) {
500 if (ISALPHA(*ptr))
501 byte |= (((*ptr & 15) + 9) & 15) << 4;
502 else
503 byte |= (*ptr & 15) << 4;
504 if (i & 1)
505 byte >>= 4;
506 else {
507 char c = byte & 0xff;
508 rb_str_buf_cat(res, &c, 1);
509 byte = 0;
510 }
511 }
512 if (len & 1) {
513 char c = byte & 0xff;
514 rb_str_buf_cat(res, &c, 1);
515 }
516 rb_str_buf_cat(res, 0, j);
517 }
518 break;
519
520 case 'H':
521 {
522 int byte = 0;
523 long i, j = 0;
524
525 if (len > plen) {
526 j = (len - plen + 1)/2;
527 len = plen;
528 }
529 for (i=0; i++ < len; ptr++) {
530 if (ISALPHA(*ptr))
531 byte |= ((*ptr & 15) + 9) & 15;
532 else
533 byte |= *ptr & 15;
534 if (i & 1)
535 byte <<= 4;
536 else {
537 char c = byte & 0xff;
538 rb_str_buf_cat(res, &c, 1);
539 byte = 0;
540 }
541 }
542 if (len & 1) {
543 char c = byte & 0xff;
544 rb_str_buf_cat(res, &c, 1);
545 }
546 rb_str_buf_cat(res, 0, j);
547 }
548 break;
549 }
550 break;
551
552 case 'c':
553 case 'C':
554 while (len-- > 0) {
555 char c;
556
557 from = NEXTFROM;
558 if (NIL_P(from)) c = 0;
559 else {
560 c = NUM2INT(from);
561 }
562 rb_str_buf_cat(res, &c, sizeof(char));
563 }
564 break;
565
566 case 's':
567 case 'S':
568 while (len-- > 0) {
569 short s;
570
571 from = NEXTFROM;
572 if (NIL_P(from)) s = 0;
573 else {
574 s = NUM2INT(from);
575 }
576 rb_str_buf_cat(res, OFF16(&s), NATINT_LEN(short,2));
577 }
578 break;
579
580 case 'i':
581 case 'I':
582 while (len-- > 0) {
583 int i;
584
585 from = NEXTFROM;
586 if (NIL_P(from)) i = 0;
587 else {
588 i = NUM2UINT(from);
589 }
590 rb_str_buf_cat(res, (char*)&i, sizeof(int));
591 }
592 break;
593
594 case 'l':
595 case 'L':
596 while (len-- > 0) {
597 long l;
598
599 from = NEXTFROM;
600 if (NIL_P(from)) l = 0;
601 else {
602 l = NATINT_U32(from);
603 }
604 rb_str_buf_cat(res, OFF32(&l), NATINT_LEN(long,4));
605 }
606 break;
607
608 case 'q':
609 case 'Q':
610 while (len-- > 0) {
611 char tmp[QUAD_SIZE];
612
613 from = NEXTFROM;
614 if (NIL_P(from)) from = INT2FIX(0);
615 rb_quad_pack(tmp, from);
616 rb_str_buf_cat(res, (char*)&tmp, QUAD_SIZE);
617 }
618 break;
619
620 case 'n':
621 while (len-- > 0) {
622 unsigned short s;
623
624 from = NEXTFROM;
625 if (NIL_P(from)) s = 0;
626 else {
627 s = NUM2INT(from);
628 }
629 s = htons(s);
630 rb_str_buf_cat(res, OFF16B(&s), NATINT_LEN(short,2));
631 }
632 break;
633
634 case 'N':
635 while (len-- > 0) {
636 unsigned long l;
637
638 from = NEXTFROM;
639 if (NIL_P(from)) l = 0;
640 else {
641 l = NATINT_U32(from);
642 }
643 l = htonl(l);
644 rb_str_buf_cat(res, OFF32B(&l), NATINT_LEN(long,4));
645 }
646 break;
647
648 case 'v':
649 while (len-- > 0) {
650 unsigned short s;
651
652 from = NEXTFROM;
653 if (NIL_P(from)) s = 0;
654 else {
655 s = NUM2INT(from);
656 }
657 s = htovs(s);
658 rb_str_buf_cat(res, OFF16(&s), NATINT_LEN(short,2));
659 }
660 break;
661
662 case 'V':
663 while (len-- > 0) {
664 unsigned long l;
665
666 from = NEXTFROM;
667 if (NIL_P(from)) l = 0;
668 else {
669 l = NATINT_U32(from);
670 }
671 l = htovl(l);
672 rb_str_buf_cat(res, OFF32(&l), NATINT_LEN(long,4));
673 }
674 break;
675
676 case 'f':
677 case 'F':
678 while (len-- > 0) {
679 float f;
680
681 from = NEXTFROM;
682 f = RFLOAT(rb_Float(from))->value;
683 rb_str_buf_cat(res, (char*)&f, sizeof(float));
684 }
685 break;
686
687 case 'e':
688 while (len-- > 0) {
689 float f;
690 FLOAT_CONVWITH(ftmp);
691
692 from = NEXTFROM;
693 f = RFLOAT(rb_Float(from))->value;
694 f = HTOVF(f,ftmp);
695 rb_str_buf_cat(res, (char*)&f, sizeof(float));
696 }
697 break;
698
699 case 'E':
700 while (len-- > 0) {
701 double d;
702 DOUBLE_CONVWITH(dtmp);
703
704 from = NEXTFROM;
705 d = RFLOAT(rb_Float(from))->value;
706 d = HTOVD(d,dtmp);
707 rb_str_buf_cat(res, (char*)&d, sizeof(double));
708 }
709 break;
710
711 case 'd':
712 case 'D':
713 while (len-- > 0) {
714 double d;
715
716 from = NEXTFROM;
717 d = RFLOAT(rb_Float(from))->value;
718 rb_str_buf_cat(res, (char*)&d, sizeof(double));
719 }
720 break;
721
722 case 'g':
723 while (len-- > 0) {
724 float f;
725 FLOAT_CONVWITH(ftmp);
726
727 from = NEXTFROM;
728 f = RFLOAT(rb_Float(from))->value;
729 f = HTONF(f,ftmp);
730 rb_str_buf_cat(res, (char*)&f, sizeof(float));
731 }
732 break;
733
734 case 'G':
735 while (len-- > 0) {
736 double d;
737 DOUBLE_CONVWITH(dtmp);
738
739 from = NEXTFROM;
740 d = RFLOAT(rb_Float(from))->value;
741 d = HTOND(d,dtmp);
742 rb_str_buf_cat(res, (char*)&d, sizeof(double));
743 }
744 break;
745
746 case 'x':
747 grow:
748 while (len >= 10) {
749 rb_str_buf_cat(res, nul10, 10);
750 len -= 10;
751 }
752 rb_str_buf_cat(res, nul10, len);
753 break;
754
755 case 'X':
756 shrink:
757 plen = RSTRING(res)->len;
758 if (plen < len)
759 rb_raise(rb_eArgError, "X outside of string");
760 RSTRING(res)->len = plen - len;
761 RSTRING(res)->ptr[plen - len] = '\0';
762 break;
763
764 case '@':
765 len -= RSTRING(res)->len;
766 if (len > 0) goto grow;
767 len = -len;
768 if (len > 0) goto shrink;
769 break;
770
771 case '%':
772 rb_raise(rb_eArgError, "%% is not supported");
773 break;
774
775 case 'U':
776 while (len-- > 0) {
777 unsigned long l;
778 char buf[8];
779 int le;
780
781 from = NEXTFROM;
782 if (NIL_P(from)) l = 0;
783 else {
784 l = NUM2ULONG(from);
785 }
786 le = uv_to_utf8(buf, l);
787 rb_str_buf_cat(res, (char*)buf, le);
788 }
789 break;
790
791 case 'u':
792 case 'm':
793 from = NEXTFROM;
794 StringValue(from);
795 ptr = RSTRING(from)->ptr;
796 plen = RSTRING(from)->len;
797
798 if (len <= 2)
799 len = 45;
800 else
801 len = len / 3 * 3;
802 while (plen > 0) {
803 long todo;
804
805 if (plen > len)
806 todo = len;
807 else
808 todo = plen;
809 encodes(res, ptr, todo, type);
810 plen -= todo;
811 ptr += todo;
812 }
813 break;
814
815 case 'M':
816 from = rb_obj_as_string(NEXTFROM);
817 if (len <= 1)
818 len = 72;
819 qpencode(res, from, len);
820 break;
821
822 case 'P':
823 from = THISFROM;
824 if (!NIL_P(from)) {
825 StringValue(from);
826 if (RSTRING(from)->len < len) {
827 rb_raise(rb_eArgError, "too short buffer for P(%ld for %ld)",
828 RSTRING(from)->len, len);
829 }
830 }
831 len = 1;
832
833 case 'p':
834 while (len-- > 0) {
835 char *t;
836 from = NEXTFROM;
837 if (NIL_P(from)) {
838 t = 0;
839 }
840 else {
841 StringValue(from);
842 t = RSTRING(from)->ptr;
843 }
844 if (!associates) {
845 associates = rb_ary_new();
846 }
847 rb_ary_push(associates, from);
848 rb_str_buf_cat(res, (char*)&t, sizeof(char*));
849 }
850 break;
851
852 case 'w':
853 while (len-- > 0) {
854 unsigned long ul;
855 VALUE buf = rb_str_new(0, 0);
856 char c, *bufs, *bufe;
857
858 from = NEXTFROM;
859 if (TYPE(from) == T_BIGNUM) {
860 VALUE big128 = rb_uint2big(128);
861 while (TYPE(from) == T_BIGNUM) {
862 from = rb_big_divmod(from, big128);
863 c = NUM2INT(RARRAY(from)->ptr[1]) | 0x80;
864 rb_str_buf_cat(buf, &c, sizeof(char));
865 from = RARRAY(from)->ptr[0];
866 }
867 }
868
869 if (NIL_P(from)) ul = 0;
870 else {
871 ul = NUM2ULONG(from);
872 }
873
874 while (ul) {
875 c = ((ul & 0x7f) | 0x80);
876 rb_str_buf_cat(buf, &c, sizeof(char));
877 ul >>= 7;
878 }
879
880 if (RSTRING(buf)->len) {
881 bufs = RSTRING(buf)->ptr;
882 bufe = bufs + RSTRING(buf)->len - 1;
883 *bufs &= 0x7f;
884 while (bufs < bufe) {
885 c = *bufs;
886 *bufs++ = *bufe;
887 *bufe-- = c;
888 }
889 rb_str_buf_cat(res, RSTRING(buf)->ptr, RSTRING(buf)->len);
890 }
891 else {
892 c = 0;
893 rb_str_buf_cat(res, &c, sizeof(char));
894 }
895 }
896 break;
897
898 default:
899 break;
900 }
901 }
902
903 if (associates) {
904 rb_str_associate(res, associates);
905 }
906 return res;
907 }
908
909 static char uu_table[] =
910 "`!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_";
911 static char b64_table[] =
912 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
913
914 static void
915 encodes(str, s, len, type)
916 VALUE str;
917 char *s;
918 long len;
919 int type;
920 {
921 char *buff = ALLOCA_N(char, len * 4 / 3 + 6);
922 long i = 0;
923 char *trans = type == 'u' ? uu_table : b64_table;
924 int padding;
925
926 if (type == 'u') {
927 buff[i++] = len + ' ';
928 padding = '`';
929 }
930 else {
931 padding = '=';
932 }
933 while (len >= 3) {
934 buff[i++] = trans[077 & (*s >> 2)];
935 buff[i++] = trans[077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017))];
936 buff[i++] = trans[077 & (((s[1] << 2) & 074) | ((s[2] >> 6) & 03))];
937 buff[i++] = trans[077 & s[2]];
938 s += 3;
939 len -= 3;
940 }
941 if (len == 2) {
942 buff[i++] = trans[077 & (*s >> 2)];
943 buff[i++] = trans[077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017))];
944 buff[i++] = trans[077 & (((s[1] << 2) & 074) | (('\0' >> 6) & 03))];
945 buff[i++] = padding;
946 }
947 else if (len == 1) {
948 buff[i++] = trans[077 & (*s >> 2)];
949 buff[i++] = trans[077 & (((*s << 4) & 060) | (('\0' >> 4) & 017))];
950 buff[i++] = padding;
951 buff[i++] = padding;
952 }
953 buff[i++] = '\n';
954 rb_str_buf_cat(str, buff, i);
955 }
956
957 static char hex_table[] = "0123456789ABCDEF";
958
959 static void
960 qpencode(str, from, len)
961 VALUE str, from;
962 long len;
963 {
964 char buff[1024];
965 long i = 0, n = 0, prev = EOF;
966 unsigned char *s = (unsigned char*)RSTRING(from)->ptr;
967 unsigned char *send = s + RSTRING(from)->len;
968
969 while (s < send) {
970 if ((*s > 126) ||
971 (*s < 32 && *s != '\n' && *s != '\t') ||
972 (*s == '=')) {
973 buff[i++] = '=';
974 buff[i++] = hex_table[*s >> 4];
975 buff[i++] = hex_table[*s & 0x0f];
976 n += 3;
977 prev = EOF;
978 }
979 else if (*s == '\n') {
980 if (prev == ' ' || prev == '\t') {
981 buff[i++] = '=';
982 buff[i++] = *s;
983 }
984 buff[i++] = *s;
985 n = 0;
986 prev = *s;
987 }
988 else {
989 buff[i++] = *s;
990 n++;
991 prev = *s;
992 }
993 if (n > len) {
994 buff[i++] = '=';
995 buff[i++] = '\n';
996 n = 0;
997 prev = '\n';
998 }
999 if (i > 1024 - 5) {
1000 rb_str_buf_cat(str, buff, i);
1001 i = 0;
1002 }
1003 s++;
1004 }
1005 if (n > 0) {
1006 buff[i++] = '=';
1007 buff[i++] = '\n';
1008 }
1009 if (i > 0) {
1010 rb_str_buf_cat(str, buff, i);
1011 }
1012 }
1013
1014 static inline int
1015 hex2num(c)
1016 char c;
1017 {
1018 switch (c) {
1019 case '0': case '1': case '2': case '3': case '4':
1020 case '5': case '6': case '7': case '8': case '9':
1021 return c - '0';
1022 case 'a': case 'b': case 'c':
1023 case 'd': case 'e': case 'f':
1024 return c - 'a' + 10;
1025 case 'A': case 'B': case 'C':
1026 case 'D': case 'E': case 'F':
1027 return c - 'A' + 10;
1028 default:
1029 return -1;
1030 }
1031 }
1032
1033 #define PACK_LENGTH_ADJUST_SIZE(sz) do { \
1034 tmp = 0; \
1035 if (len > (send-s)/sz) { \
1036 if (!star) { \
1037 tmp = len-(send-s)/sz; \
1038 } \
1039 len = (send-s)/sz; \
1040 } \
1041 } while (0)
1042
1043 #ifdef NATINT_PACK
1044 #define PACK_LENGTH_ADJUST(type,sz) do { \
1045 int t__len = NATINT_LEN(type,(sz)); \
1046 PACK_LENGTH_ADJUST_SIZE(t__len); \
1047 } while (0)
1048 #else
1049 #define PACK_LENGTH_ADJUST(type,sz) \
1050 PACK_LENGTH_ADJUST_SIZE(sizeof(type))
1051 #endif
1052
1053 #define PACK_ITEM_ADJUST() while (tmp--) rb_ary_push(ary, Qnil)
1054
1055 static VALUE
1056 infected_str_new(ptr, len, str)
1057 const char *ptr;
1058 long len;
1059 VALUE str;
1060 {
1061 VALUE s = rb_str_new(ptr, len);
1062
1063 OBJ_INFECT(s, str);
1064 return s;
1065 }
1066
1067 static VALUE
1068 pack_unpack(str, fmt)
1069 VALUE str, fmt;
1070 {
1071 static char *hexdigits = "0123456789abcdef0123456789ABCDEFx";
1072 char *s, *send;
1073 char *p, *pend;
1074 VALUE ary;
1075 char type;
1076 long len;
1077 int tmp, star;
1078 #ifdef NATINT_PACK
1079 int natint;
1080 #endif
1081
1082 StringValue(str);
1083 s = RSTRING(str)->ptr;
1084 send = s + RSTRING(str)->len;
1085 StringValue(fmt);
1086 p = RSTRING(fmt)->ptr;
1087 pend = p + RSTRING(fmt)->len;
1088
1089 ary = rb_ary_new();
1090 while (p < pend) {
1091 type = *p++;
1092 #ifdef NATINT_PACK
1093 natint = 0;
1094 #endif
1095
1096 if (ISSPACE(type)) continue;
1097 if (type == '#') {
1098 while ((p < pend) && (*p != '\n')) {
1099 p++;
1100 }
1101 continue;
1102 }
1103 star = 0;
1104 if (*p == '_' || *p == '!') {
1105 char *natstr = "sSiIlL";
1106
1107 if (strchr(natstr, type)) {
1108 #ifdef NATINT_PACK
1109 natint = 1;
1110 #endif
1111 p++;
1112 }
1113 else {
1114 rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, natstr);
1115 }
1116 }
1117 if (p >= pend)
1118 len = 1;
1119 else if (*p == '*') {
1120 star = 1;
1121 len = send - s;
1122 p++;
1123 }
1124 else if (ISDIGIT(*p)) {
1125 len = strtoul(p, (char**)&p, 10);
1126 }
1127 else {
1128 len = (type != '@');
1129 }
1130
1131 switch (type) {
1132 case '%':
1133 rb_raise(rb_eArgError, "%% is not supported");
1134 break;
1135
1136 case 'A':
1137 if (len > send - s) len = send - s;
1138 {
1139 long end = len;
1140 char *t = s + len - 1;
1141
1142 while (t >= s) {
1143 if (*t != ' ' && *t != '\0') break;
1144 t--; len--;
1145 }
1146 rb_ary_push(ary, infected_str_new(s, len, str));
1147 s += end;
1148 }
1149 break;
1150
1151 case 'Z':
1152 if (len > send - s) len = send - s;
1153 {
1154 long end = len;
1155 char *t = s + len - 1;
1156
1157 while (t >= s) {
1158 if (*t) break;
1159 t--; len--;
1160 }
1161 rb_ary_push(ary, infected_str_new(s, len, str));
1162 s += end;
1163 }
1164 break;
1165
1166 case 'a':
1167 if (len > send - s) len = send - s;
1168 rb_ary_push(ary, infected_str_new(s, len, str));
1169 s += len;
1170 break;
1171
1172
1173 case 'b':
1174 {
1175 VALUE bitstr;
1176 char *t;
1177 int bits;
1178 long i;
1179
1180 if (p[-1] == '*' || len > (send - s) * 8)
1181 len = (send - s) * 8;
1182 bits = 0;
1183 rb_ary_push(ary, bitstr = rb_str_new(0, len));
1184 t = RSTRING(bitstr)->ptr;
1185 for (i=0; i<len; i++) {
1186 if (i & 7) bits >>= 1;
1187 else bits = *s++;
1188 *t++ = (bits & 1) ? '1' : '0';
1189 }
1190 }
1191 break;
1192
1193 case 'B':
1194 {
1195 VALUE bitstr;
1196 char *t;
1197 int bits;
1198 long i;
1199
1200 if (p[-1] == '*' || len > (send - s) * 8)
1201 len = (send - s) * 8;
1202 bits = 0;
1203 rb_ary_push(ary, bitstr = rb_str_new(0, len));
1204 t = RSTRING(bitstr)->ptr;
1205 for (i=0; i<len; i++) {
1206 if (i & 7) bits <<= 1;
1207 else bits = *s++;
1208 *t++ = (bits & 128) ? '1' : '0';
1209 }
1210 }
1211 break;
1212
1213 case 'h':
1214 {
1215 VALUE bitstr;
1216 char *t;
1217 int bits;
1218 long i;
1219
1220 if (p[-1] == '*' || len > (send - s) * 2)
1221 len = (send - s) * 2;
1222 bits = 0;
1223 rb_ary_push(ary, bitstr = rb_str_new(0, len));
1224 t = RSTRING(bitstr)->ptr;
1225 for (i=0; i<len; i++) {
1226 if (i & 1)
1227 bits >>= 4;
1228 else
1229 bits = *s++;
1230 *t++ = hexdigits[bits & 15];
1231 }
1232 }
1233 break;
1234
1235 case 'H':
1236 {
1237 VALUE bitstr;
1238 char *t;
1239 int bits;
1240 long i;
1241
1242 if (p[-1] == '*' || len > (send - s) * 2)
1243 len = (send - s) * 2;
1244 bits = 0;
1245 rb_ary_push(ary, bitstr = rb_str_new(0, len));
1246 t = RSTRING(bitstr)->ptr;
1247 for (i=0; i<len; i++) {
1248 if (i & 1)
1249 bits <<= 4;
1250 else
1251 bits = *s++;
1252 *t++ = hexdigits[(bits >> 4) & 15];
1253 }
1254 }
1255 break;
1256
1257 case 'c':
1258 PACK_LENGTH_ADJUST(char,sizeof(char));
1259 while (len-- > 0) {
1260 int c = *s++;
1261 if (c > (char)127) c-=256;
1262 rb_ary_push(ary, INT2FIX(c));
1263 }
1264 PACK_ITEM_ADJUST();
1265 break;
1266
1267 case 'C':
1268 PACK_LENGTH_ADJUST(unsigned char,sizeof(unsigned char));
1269 while (len-- > 0) {
1270 unsigned char c = *s++;
1271 rb_ary_push(ary, INT2FIX(c));
1272 }
1273 PACK_ITEM_ADJUST();
1274 break;
1275
1276 case 's':
1277 PACK_LENGTH_ADJUST(short,2);
1278 while (len-- > 0) {
1279 short tmp = 0;
1280 memcpy(OFF16(&tmp), s, NATINT_LEN(short,2));
1281 s += NATINT_LEN(short,2);
1282 rb_ary_push(ary, INT2FIX(tmp));
1283 }
1284 PACK_ITEM_ADJUST();
1285 break;
1286
1287 case 'S':
1288 PACK_LENGTH_ADJUST(unsigned short,2);
1289 while (len-- > 0) {
1290 unsigned short tmp = 0;
1291 memcpy(OFF16(&tmp), s, NATINT_LEN(unsigned short,2));
1292 s += NATINT_LEN(unsigned short,2);
1293 rb_ary_push(ary, INT2FIX(tmp));
1294 }
1295 PACK_ITEM_ADJUST();
1296 break;
1297
1298 case 'i':
1299 PACK_LENGTH_ADJUST(int,sizeof(int));
1300 while (len-- > 0) {
1301 int tmp;
1302 memcpy(&tmp, s, sizeof(int));
1303 s += sizeof(int);
1304 rb_ary_push(ary, INT2NUM(tmp));
1305 }
1306 PACK_ITEM_ADJUST();
1307 break;
1308
1309 case 'I':
1310 PACK_LENGTH_ADJUST(unsigned int,sizeof(unsigned int));
1311 while (len-- > 0) {
1312 unsigned int tmp;
1313 memcpy(&tmp, s, sizeof(unsigned int));
1314 s += sizeof(unsigned int);
1315 rb_ary_push(ary, UINT2NUM(tmp));
1316 }
1317 PACK_ITEM_ADJUST();
1318 break;
1319
1320 case 'l':
1321 PACK_LENGTH_ADJUST(long,4);
1322 while (len-- > 0) {
1323 long tmp = 0;
1324 memcpy(OFF32(&tmp), s, NATINT_LEN(long,4));
1325 s += NATINT_LEN(long,4);
1326 rb_ary_push(ary, LONG2NUM(tmp));
1327 }
1328 PACK_ITEM_ADJUST();
1329 break;
1330
1331 case 'L':
1332 PACK_LENGTH_ADJUST(unsigned long,4);
1333 while (len-- > 0) {
1334 unsigned long tmp = 0;
1335 memcpy(OFF32(&tmp), s, NATINT_LEN(unsigned long,4));
1336 s += NATINT_LEN(unsigned long,4);
1337 rb_ary_push(ary, ULONG2NUM(tmp));
1338 }
1339 PACK_ITEM_ADJUST();
1340 break;
1341
1342 case 'q':
1343 PACK_LENGTH_ADJUST_SIZE(QUAD_SIZE);
1344 while (len-- > 0) {
1345 char *tmp = (char*)s;
1346 s += QUAD_SIZE;
1347 rb_ary_push(ary, rb_quad_unpack(tmp, 1));
1348 }
1349 PACK_ITEM_ADJUST();
1350 break;
1351 case 'Q':
1352 PACK_LENGTH_ADJUST_SIZE(QUAD_SIZE);
1353 while (len-- > 0) {
1354 char *tmp = (char*)s;
1355 s += QUAD_SIZE;
1356 rb_ary_push(ary, rb_quad_unpack(tmp, 0));
1357 }
1358 break;
1359
1360 case 'n':
1361 PACK_LENGTH_ADJUST(unsigned short,2);
1362 while (len-- > 0) {
1363 unsigned short tmp = 0;
1364 memcpy(OFF16B(&tmp), s, NATINT_LEN(unsigned short,2));
1365 s += NATINT_LEN(unsigned short,2);
1366 rb_ary_push(ary, UINT2NUM(ntohs(tmp)));
1367 }
1368 PACK_ITEM_ADJUST();
1369 break;
1370
1371 case 'N':
1372 PACK_LENGTH_ADJUST(unsigned long,4);
1373 while (len-- > 0) {
1374 unsigned long tmp = 0;
1375 memcpy(OFF32B(&tmp), s, NATINT_LEN(unsigned long,4));
1376 s += NATINT_LEN(unsigned long,4);
1377 rb_ary_push(ary, ULONG2NUM(ntohl(tmp)));
1378 }
1379 PACK_ITEM_ADJUST();
1380 break;
1381
1382 case 'v':
1383 PACK_LENGTH_ADJUST(unsigned short,2);
1384 while (len-- > 0) {
1385 unsigned short tmp = 0;
1386 memcpy(OFF16(&tmp), s, NATINT_LEN(unsigned short,2));
1387 s += NATINT_LEN(unsigned short,2);
1388 rb_ary_push(ary, UINT2NUM(vtohs(tmp)));
1389 }
1390 PACK_ITEM_ADJUST();
1391 break;
1392
1393 case 'V':
1394 PACK_LENGTH_ADJUST(unsigned long,4);
1395 while (len-- > 0) {
1396 unsigned long tmp = 0;
1397 memcpy(OFF32(&tmp), s, NATINT_LEN(long,4));
1398 s += NATINT_LEN(long,4);
1399 rb_ary_push(ary, ULONG2NUM(vtohl(tmp)));
1400 }
1401 PACK_ITEM_ADJUST();
1402 break;
1403
1404 case 'f':
1405 case 'F':
1406 PACK_LENGTH_ADJUST(float,sizeof(float));
1407 while (len-- > 0) {
1408 float tmp;
1409 memcpy(&tmp, s, sizeof(float));
1410 s += sizeof(float);
1411 rb_ary_push(ary, rb_float_new((double)tmp));
1412 }
1413 PACK_ITEM_ADJUST();
1414 break;
1415
1416 case 'e':
1417 PACK_LENGTH_ADJUST(float,sizeof(float));
1418 while (len-- > 0) {
1419 float tmp;
1420 FLOAT_CONVWITH(ftmp);
1421
1422 memcpy(&tmp, s, sizeof(float));
1423 s += sizeof(float);
1424 tmp = VTOHF(tmp,ftmp);
1425 rb_ary_push(ary, rb_float_new((double)tmp));
1426 }
1427 PACK_ITEM_ADJUST();
1428 break;
1429
1430 case 'E':
1431 PACK_LENGTH_ADJUST(double,sizeof(double));
1432 while (len-- > 0) {
1433 double tmp;
1434 DOUBLE_CONVWITH(dtmp);
1435
1436 memcpy(&tmp, s, sizeof(double));
1437 s += sizeof(double);
1438 tmp = VTOHD(tmp,dtmp);
1439 rb_ary_push(ary, rb_float_new(tmp));
1440 }
1441 PACK_ITEM_ADJUST();
1442 break;
1443
1444 case 'D':
1445 case 'd':
1446 PACK_LENGTH_ADJUST(double,sizeof(double));
1447 while (len-- > 0) {
1448 double tmp;
1449 memcpy(&tmp, s, sizeof(double));
1450 s += sizeof(double);
1451 rb_ary_push(ary, rb_float_new(tmp));
1452 }
1453 PACK_ITEM_ADJUST();
1454 break;
1455
1456 case 'g':
1457 PACK_LENGTH_ADJUST(float,sizeof(float));
1458 while (len-- > 0) {
1459 float tmp;
1460 FLOAT_CONVWITH(ftmp;)
1461
1462 memcpy(&tmp, s, sizeof(float));
1463 s += sizeof(float);
1464 tmp = NTOHF(tmp,ftmp);
1465 rb_ary_push(ary, rb_float_new((double)tmp));
1466 }
1467 PACK_ITEM_ADJUST();
1468 break;
1469
1470 case 'G':
1471 PACK_LENGTH_ADJUST(double,sizeof(double));
1472 while (len-- > 0) {
1473 double tmp;
1474 DOUBLE_CONVWITH(dtmp);
1475
1476 memcpy(&tmp, s, sizeof(double));
1477 s += sizeof(double);
1478 tmp = NTOHD(tmp,dtmp);
1479 rb_ary_push(ary, rb_float_new(tmp));
1480 }
1481 PACK_ITEM_ADJUST();
1482 break;
1483
1484 case 'U':
1485 if (len > send - s) len = send - s;
1486 while (len > 0 && s < send) {
1487 long alen = send - s;
1488 unsigned long l;
1489
1490 l = utf8_to_uv(s, &alen);
1491 s += alen; len--;
1492 rb_ary_push(ary, ULONG2NUM(l));
1493 }
1494 break;
1495
1496 case 'u':
1497 {
1498 VALUE buf = infected_str_new(0, (send - s)*3/4, str);
1499 char *ptr = RSTRING(buf)->ptr;
1500 long total = 0;
1501
1502 while (s < send && *s > ' ' && *s < 'a') {
1503 long a,b,c,d;
1504 char hunk[4];
1505
1506 hunk[3] = '\0';
1507 len = (*s++ - ' ') & 077;
1508 total += len;
1509 if (total > RSTRING(buf)->len) {
1510 len -= total - RSTRING(buf)->len;
1511 total = RSTRING(buf)->len;
1512 }
1513
1514 while (len > 0) {
1515 long mlen = len > 3 ? 3 : len;
1516
1517 if (s < send && *s >= ' ')
1518 a = (*s++ - ' ') & 077;
1519 else
1520 a = 0;
1521 if (s < send && *s >= ' ')
1522 b = (*s++ - ' ') & 077;
1523 else
1524 b = 0;
1525 if (s < send && *s >= ' ')
1526 c = (*s++ - ' ') & 077;
1527 else
1528 c = 0;
1529 if (s < send && *s >= ' ')
1530 d = (*s++ - ' ') & 077;
1531 else
1532 d = 0;
1533 hunk[0] = a << 2 | b >> 4;
1534 hunk[1] = b << 4 | c >> 2;
1535 hunk[2] = c << 6 | d;
1536 memcpy(ptr, hunk, mlen);
1537 ptr += mlen;
1538 len -= mlen;
1539 }
1540 if (*s == '\r') s++;
1541 if (*s == '\n') s++;
1542 else if (s < send && (s+1 == send || s[1] == '\n'))
1543 s += 2;
1544 }
1545
1546 RSTRING(buf)->ptr[total] = '\0';
1547 RSTRING(buf)->len = total;
1548 rb_ary_push(ary, buf);
1549 }
1550 break;
1551
1552 case 'm':
1553 {
1554 VALUE buf = infected_str_new(0, (send - s)*3/4, str);
1555 char *ptr = RSTRING(buf)->ptr;
1556 int a,b,c = 0,d;
1557 static int first = 1;
1558 static int b64_xtable[256];
1559
1560 if (first) {
1561 int i;
1562 first = 0;
1563
1564 for (i = 0; i < 256; i++) {
1565 b64_xtable[i] = -1;
1566 }
1567 for (i = 0; i < 64; i++) {
1568 b64_xtable[(int)b64_table[i]] = i;
1569 }
1570 }
1571 for (;;) {
1572 while (s[0] == '\r' || s[0] == '\n') { s++; }
1573 if ((a = b64_xtable[(int)s[0]]) == -1) break;
1574 if ((b = b64_xtable[(int)s[1]]) == -1) break;
1575 if ((c = b64_xtable[(int)s[2]]) == -1) break;
1576 if ((d = b64_xtable[(int)s[3]]) == -1) break;
1577 *ptr++ = a << 2 | b >> 4;
1578 *ptr++ = b << 4 | c >> 2;
1579 *ptr++ = c << 6 | d;
1580 s += 4;
1581 }
1582 if (a != -1 && b != -1 && s[2] == '=') {
1583 *ptr++ = a << 2 | b >> 4;
1584 }
1585 if (a != -1 && b != -1 && c != -1 && s[3] == '=') {
1586 *ptr++ = a << 2 | b >> 4;
1587 *ptr++ = b << 4 | c >> 2;
1588 }
1589 *ptr = '\0';
1590 RSTRING(buf)->len = ptr - RSTRING(buf)->ptr;
1591 rb_ary_push(ary, buf);
1592 }
1593 break;
1594
1595 case 'M':
1596 {
1597 VALUE buf = infected_str_new(0, send - s, str);
1598 char *ptr = RSTRING(buf)->ptr;
1599 int c1, c2;
1600
1601 while (s < send) {
1602 if (*s == '=') {
1603 if (++s == send) break;
1604 if (*s != '\n') {
1605 if ((c1 = hex2num(*s)) == -1) break;
1606 if (++s == send) break;
1607 if ((c2 = hex2num(*s)) == -1) break;
1608 *ptr++ = c1 << 4 | c2;
1609 }
1610 }
1611 else {
1612 *ptr++ = *s;
1613 }
1614 s++;
1615 }
1616 *ptr = '\0';
1617 RSTRING(buf)->len = ptr - RSTRING(buf)->ptr;
1618 rb_ary_push(ary, buf);
1619 }
1620 break;
1621
1622 case '@':
1623 s = RSTRING(str)->ptr + len;
1624 break;
1625
1626 case 'X':
1627 if (len > s - RSTRING(str)->ptr)
1628 rb_raise(rb_eArgError, "X outside of string");
1629 s -= len;
1630 break;
1631
1632 case 'x':
1633 if (len > send - s)
1634 rb_raise(rb_eArgError, "x outside of string");
1635 s += len;
1636 break;
1637
1638 case 'P':
1639 if (sizeof(char *) <= send - s) {
1640 char *t;
1641 VALUE tmp;
1642
1643 memcpy(&t, s, sizeof(char *));
1644 s += sizeof(char *);
1645
1646 if (t) {
1647 VALUE a, *p, *pend;
1648
1649 if (!(a = rb_str_associated(str))) {
1650 rb_raise(rb_eArgError, "no associated pointer");
1651 }
1652 p = RARRAY(a)->ptr;
1653 pend = p + RARRAY(a)->len;
1654 while (p < pend) {
1655 if (TYPE(*p) == T_STRING && RSTRING(*p)->ptr == t) {
1656 if (len > RSTRING(*p)->len) {
1657 len = RSTRING(*p)->len;
1658 }
1659 break;
1660 }
1661 p++;
1662 }
1663 if (p == pend) {
1664 rb_raise(rb_eArgError, "non associated pointer");
1665 }
1666 tmp = rb_tainted_str_new(t, len);
1667 }
1668 else {
1669 tmp = Qnil;
1670 }
1671 rb_ary_push(ary, tmp);
1672 }
1673 break;
1674
1675 case 'p':
1676 if (len > (send - s) / sizeof(char *))
1677 len = (send - s) / sizeof(char *);
1678 while (len-- > 0) {
1679 if (send - s < sizeof(char *))
1680 break;
1681 else {
1682 VALUE tmp;
1683 char *t;
1684
1685 memcpy(&t, s, sizeof(char *));
1686 s += sizeof(char *);
1687
1688 if (t) {
1689 VALUE a, *p, *pend;
1690
1691 if (!(a = rb_str_associated(str))) {
1692 rb_raise(rb_eArgError, "no associated pointer");
1693 }
1694 p = RARRAY(a)->ptr;
1695 pend = p + RARRAY(a)->len;
1696 while (p < pend) {
1697 if (TYPE(*p) == T_STRING && RSTRING(*p)->ptr == t) {
1698 break;
1699 }
1700 p++;
1701 }
1702 if (p == pend) {
1703 rb_raise(rb_eArgError, "non associated pointer");
1704 }
1705 tmp = rb_str_new2(t);
1706 OBJ_INFECT(tmp, str);
1707 }
1708 else {
1709 tmp = Qnil;
1710 }
1711 rb_ary_push(ary, tmp);
1712 }
1713 }
1714 break;
1715
1716 case 'w':
1717 {
1718 unsigned long ul = 0;
1719 unsigned long ulmask = 0xfeL << ((sizeof(unsigned long) - 1) * 8);
1720
1721 while (len > 0 && s < send) {
1722 ul <<= 7;
1723 ul |= (*s & 0x7f);
1724 if (!(*s++ & 0x80)) {
1725 rb_ary_push(ary, ULONG2NUM(ul));
1726 len--;
1727 ul = 0;
1728 }
1729 else if (ul & ulmask) {
1730 VALUE big = rb_uint2big(ul);
1731 VALUE big128 = rb_uint2big(128);
1732 while (s < send) {
1733 big = rb_big_mul(big, big128);
1734 big = rb_big_plus(big, rb_uint2big(*s & 0x7f));
1735 if (!(*s++ & 0x80)) {
1736 rb_ary_push(ary, big);
1737 len--;
1738 ul = 0;
1739 break;
1740 }
1741 }
1742 }
1743 }
1744 }
1745 break;
1746
1747 default:
1748 break;
1749 }
1750 }
1751
1752 return ary;
1753 }
1754
1755 #define BYTEWIDTH 8
1756
1757 static int
1758 uv_to_utf8(buf, uv)
1759 char *buf;
1760 unsigned long uv;
1761 {
1762 if (uv <= 0x7f) {
1763 buf[0] = (char)uv;
1764 return 1;
1765 }
1766 if (uv <= 0x7ff) {
1767 buf[0] = ((uv>>6)&0xff)|0xc0;
1768 buf[1] = (uv&0x3f)|0x80;
1769 return 2;
1770 }
1771 if (uv <= 0xffff) {
1772 buf[0] = ((uv>>12)&0xff)|0xe0;
1773 buf[1] = ((uv>>6)&0x3f)|0x80;
1774 buf[2] = (uv&0x3f)|0x80;
1775 return 3;
1776 }
1777 if (uv <= 0x1fffff) {
1778 buf[0] = ((uv>>18)&0xff)|0xf0;
1779 buf[1] = ((uv>>12)&0x3f)|0x80;
1780 buf[2] = ((uv>>6)&0x3f)|0x80;
1781 buf[3] = (uv&0x3f)|0x80;
1782 return 4;
1783 }
1784 if (uv <= 0x3ffffff) {
1785 buf[0] = ((uv>>24)&0xff)|0xf8;
1786 buf[1] = ((uv>>18)&0x3f)|0x80;
1787 buf[2] = ((uv>>12)&0x3f)|0x80;
1788 buf[3] = ((uv>>6)&0x3f)|0x80;
1789 buf[4] = (uv&0x3f)|0x80;
1790 return 5;
1791 }
1792 if (uv <= 0x7fffffff) {
1793 buf[0] = ((uv>>30)&0xff)|0xfc;
1794 buf[1] = ((uv>>24)&0x3f)|0x80;
1795 buf[2] = ((uv>>18)&0x3f)|0x80;
1796 buf[3] = ((uv>>12)&0x3f)|0x80;
1797 buf[4] = ((uv>>6)&0x3f)|0x80;
1798 buf[5] = (uv&0x3f)|0x80;
1799 return 6;
1800 }
1801 #if SIZEOF_LONG > 4
1802 if (uv <= 0xfffffffff) {
1803 #endif
1804 buf[0] = 0xfe;
1805 buf[1] = ((uv>>30)&0x3f)|0x80;
1806 buf[2] = ((uv>>24)&0x3f)|0x80;
1807 buf[3] = ((uv>>18)&0x3f)|0x80;
1808 buf[4] = ((uv>>12)&0x3f)|0x80;
1809 buf[5] = ((uv>>6)&0x3f)|0x80;
1810 buf[6] = (uv&0x3f)|0x80;
1811 return 7;
1812 #if SIZEOF_LONG > 4
1813 }
1814 rb_raise(rb_eArgError, "uv_to_utf8(); too big value");
1815 #endif
1816 }
1817
1818 static unsigned long
1819 utf8_to_uv(p, lenp)
1820 char *p;
1821 long *lenp;
1822 {
1823 int c = (*p++)&0xff;
1824 unsigned long uv;
1825 long n = 1;
1826
1827 if (c < 0xc0) n = 1;
1828 else if (c < 0xe0) n = 2;
1829 else if (c < 0xf0) n = 3;
1830 else if (c < 0xf8) n = 4;
1831 else if (c < 0xfc) n = 5;
1832 else if (c < 0xfe) n = 6;
1833 else if (c == 0xfe) n = 7;
1834 if (n > *lenp) return 0;
1835 *lenp = n--;
1836
1837 uv = c;
1838 if (n != 0) {
1839 uv &= (1<<(BYTEWIDTH-2-n)) - 1;
1840 while (n--) {
1841 uv = uv << 6 | (*p++ & ((1<<6)-1));
1842 }
1843 }
1844 return uv;
1845 }
1846
1847 void
1848 Init_pack()
1849 {
1850 rb_define_method(rb_cArray, "pack", pack_pack, 1);
1851 rb_define_method(rb_cString, "unpack", pack_unpack, 1);
1852 }