00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "ruby/ruby.h"
00013 #include "ruby/encoding.h"
00014 #include <sys/types.h>
00015 #include <ctype.h>
00016 #include <errno.h>
00017
00018 #define GCC_VERSION_SINCE(major, minor, patchlevel) \
00019 (defined(__GNUC__) && !defined(__INTEL_COMPILER) && \
00020 ((__GNUC__ > (major)) || \
00021 (__GNUC__ == (major) && __GNUC_MINOR__ > (minor)) || \
00022 (__GNUC__ == (major) && __GNUC_MINOR__ == (minor) && __GNUC_PATCHLEVEL__ >= (patchlevel))))
00023 #if SIZEOF_SHORT != 2 || SIZEOF_LONG != 4
00024 # define NATINT_PACK
00025 #endif
00026
00027 #ifdef DYNAMIC_ENDIAN
00028
00029
00030 static int
00031 is_bigendian(void)
00032 {
00033 static int init = 0;
00034 static int endian_value;
00035 char *p;
00036
00037 if (init) return endian_value;
00038 init = 1;
00039 p = (char*)&init;
00040 return endian_value = p[0]?0:1;
00041 }
00042 # define BIGENDIAN_P() (is_bigendian())
00043 #elif defined(WORDS_BIGENDIAN)
00044 # define BIGENDIAN_P() 1
00045 #else
00046 # define BIGENDIAN_P() 0
00047 #endif
00048
00049 #ifdef NATINT_PACK
00050 # define NATINT_LEN(type,len) (natint?(int)sizeof(type):(int)(len))
00051 #else
00052 # define NATINT_LEN(type,len) ((int)sizeof(type))
00053 #endif
00054
00055 #if SIZEOF_LONG == 8
00056 # define INT64toNUM(x) LONG2NUM(x)
00057 # define UINT64toNUM(x) ULONG2NUM(x)
00058 #elif defined(HAVE_LONG_LONG) && SIZEOF_LONG_LONG == 8
00059 # define INT64toNUM(x) LL2NUM(x)
00060 # define UINT64toNUM(x) ULL2NUM(x)
00061 #endif
00062
00063 #define define_swapx(x, xtype) \
00064 static xtype \
00065 TOKEN_PASTE(swap,x)(xtype z) \
00066 { \
00067 xtype r; \
00068 xtype *zp; \
00069 unsigned char *s, *t; \
00070 int i; \
00071 \
00072 zp = xmalloc(sizeof(xtype)); \
00073 *zp = z; \
00074 s = (unsigned char*)zp; \
00075 t = xmalloc(sizeof(xtype)); \
00076 for (i=0; i<sizeof(xtype); i++) { \
00077 t[sizeof(xtype)-i-1] = s[i]; \
00078 } \
00079 r = *(xtype *)t; \
00080 xfree(t); \
00081 xfree(zp); \
00082 return r; \
00083 }
00084
00085 #if GCC_VERSION_SINCE(4,3,0)
00086 # define swap32(x) __builtin_bswap32(x)
00087 # define swap64(x) __builtin_bswap64(x)
00088 #endif
00089
00090 #ifndef swap16
00091 # define swap16(x) ((uint16_t)((((x)&0xFF)<<8) | (((x)>>8)&0xFF)))
00092 #endif
00093
00094 #ifndef swap32
00095 # define swap32(x) ((uint32_t)((((x)&0xFF)<<24) \
00096 |(((x)>>24)&0xFF) \
00097 |(((x)&0x0000FF00)<<8) \
00098 |(((x)&0x00FF0000)>>8) ))
00099 #endif
00100
00101 #ifndef swap64
00102 # ifdef HAVE_INT64_T
00103 # define byte_in_64bit(n) ((uint64_t)0xff << (n))
00104 # define swap64(x) ((uint64_t)((((x)&byte_in_64bit(0))<<56) \
00105 |(((x)>>56)&0xFF) \
00106 |(((x)&byte_in_64bit(8))<<40) \
00107 |(((x)&byte_in_64bit(48))>>40) \
00108 |(((x)&byte_in_64bit(16))<<24) \
00109 |(((x)&byte_in_64bit(40))>>24) \
00110 |(((x)&byte_in_64bit(24))<<8) \
00111 |(((x)&byte_in_64bit(32))>>8)))
00112 # endif
00113 #endif
00114
00115 #if SIZEOF_SHORT == 2
00116 # define swaps(x) swap16(x)
00117 #elif SIZEOF_SHORT == 4
00118 # define swaps(x) swap32(x)
00119 #else
00120 define_swapx(s,short)
00121 #endif
00122
00123 #if SIZEOF_INT == 2
00124 # define swapi(x) swap16(x)
00125 #elif SIZEOF_INT == 4
00126 # define swapi(x) swap32(x)
00127 #else
00128 define_swapx(i,int)
00129 #endif
00130
00131 #if SIZEOF_LONG == 4
00132 # define swapl(x) swap32(x)
00133 #elif SIZEOF_LONG == 8
00134 # define swapl(x) swap64(x)
00135 #else
00136 define_swapx(l,long)
00137 #endif
00138
00139 #ifdef HAVE_LONG_LONG
00140 # if SIZEOF_LONG_LONG == 8
00141 # define swapll(x) swap64(x)
00142 # else
00143 define_swapx(ll,LONG_LONG)
00144 # endif
00145 #endif
00146
00147 #if SIZEOF_FLOAT == 4 && defined(HAVE_INT32_T)
00148 # define swapf(x) swap32(x)
00149 # define FLOAT_SWAPPER uint32_t
00150 #else
00151 define_swapx(f,float)
00152 #endif
00153
00154 #if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T)
00155 # define swapd(x) swap64(x)
00156 # define DOUBLE_SWAPPER uint64_t
00157 #elif SIZEOF_DOUBLE == 8 && defined(HAVE_INT32_T)
00158 static double
00159 swapd(const double d)
00160 {
00161 double dtmp = d;
00162 uint32_t utmp[2];
00163 uint32_t utmp0;
00164
00165 utmp[0] = 0; utmp[1] = 0;
00166 memcpy(utmp,&dtmp,sizeof(double));
00167 utmp0 = utmp[0];
00168 utmp[0] = swap32(utmp[1]);
00169 utmp[1] = swap32(utmp0);
00170 memcpy(&dtmp,utmp,sizeof(double));
00171 return dtmp;
00172 }
00173 #else
00174 define_swapx(d, double)
00175 #endif
00176
00177 #undef define_swapx
00178
00179 #define rb_ntohf(x) (BIGENDIAN_P()?(x):swapf(x))
00180 #define rb_ntohd(x) (BIGENDIAN_P()?(x):swapd(x))
00181 #define rb_htonf(x) (BIGENDIAN_P()?(x):swapf(x))
00182 #define rb_htond(x) (BIGENDIAN_P()?(x):swapd(x))
00183 #define rb_htovf(x) (BIGENDIAN_P()?swapf(x):(x))
00184 #define rb_htovd(x) (BIGENDIAN_P()?swapd(x):(x))
00185 #define rb_vtohf(x) (BIGENDIAN_P()?swapf(x):(x))
00186 #define rb_vtohd(x) (BIGENDIAN_P()?swapd(x):(x))
00187
00188 #ifdef FLOAT_SWAPPER
00189 # define FLOAT_CONVWITH(y) FLOAT_SWAPPER y;
00190 # define HTONF(x,y) (memcpy(&(y),&(x),sizeof(float)), \
00191 (y) = rb_htonf((FLOAT_SWAPPER)(y)), \
00192 memcpy(&(x),&(y),sizeof(float)), \
00193 (x))
00194 # define HTOVF(x,y) (memcpy(&(y),&(x),sizeof(float)), \
00195 (y) = rb_htovf((FLOAT_SWAPPER)(y)), \
00196 memcpy(&(x),&(y),sizeof(float)), \
00197 (x))
00198 # define NTOHF(x,y) (memcpy(&(y),&(x),sizeof(float)), \
00199 (y) = rb_ntohf((FLOAT_SWAPPER)(y)), \
00200 memcpy(&(x),&(y),sizeof(float)), \
00201 (x))
00202 # define VTOHF(x,y) (memcpy(&(y),&(x),sizeof(float)), \
00203 (y) = rb_vtohf((FLOAT_SWAPPER)(y)), \
00204 memcpy(&(x),&(y),sizeof(float)), \
00205 (x))
00206 #else
00207 # define FLOAT_CONVWITH(y)
00208 # define HTONF(x,y) rb_htonf(x)
00209 # define HTOVF(x,y) rb_htovf(x)
00210 # define NTOHF(x,y) rb_ntohf(x)
00211 # define VTOHF(x,y) rb_vtohf(x)
00212 #endif
00213
00214 #ifdef DOUBLE_SWAPPER
00215 # define DOUBLE_CONVWITH(y) DOUBLE_SWAPPER y;
00216 # define HTOND(x,y) (memcpy(&(y),&(x),sizeof(double)), \
00217 (y) = rb_htond((DOUBLE_SWAPPER)(y)), \
00218 memcpy(&(x),&(y),sizeof(double)), \
00219 (x))
00220 # define HTOVD(x,y) (memcpy(&(y),&(x),sizeof(double)), \
00221 (y) = rb_htovd((DOUBLE_SWAPPER)(y)), \
00222 memcpy(&(x),&(y),sizeof(double)), \
00223 (x))
00224 # define NTOHD(x,y) (memcpy(&(y),&(x),sizeof(double)), \
00225 (y) = rb_ntohd((DOUBLE_SWAPPER)(y)), \
00226 memcpy(&(x),&(y),sizeof(double)), \
00227 (x))
00228 # define VTOHD(x,y) (memcpy(&(y),&(x),sizeof(double)), \
00229 (y) = rb_vtohd((DOUBLE_SWAPPER)(y)), \
00230 memcpy(&(x),&(y),sizeof(double)), \
00231 (x))
00232 #else
00233 # define DOUBLE_CONVWITH(y)
00234 # define HTOND(x,y) rb_htond(x)
00235 # define HTOVD(x,y) rb_htovd(x)
00236 # define NTOHD(x,y) rb_ntohd(x)
00237 # define VTOHD(x,y) rb_vtohd(x)
00238 #endif
00239
00240 static unsigned long
00241 num2i32(VALUE x)
00242 {
00243 x = rb_to_int(x);
00244
00245 if (FIXNUM_P(x)) return FIX2LONG(x);
00246 if (RB_TYPE_P(x, T_BIGNUM)) {
00247 return rb_big2ulong_pack(x);
00248 }
00249 rb_raise(rb_eTypeError, "can't convert %s to `integer'", rb_obj_classname(x));
00250
00251 UNREACHABLE;
00252 }
00253
00254 #define MAX_INTEGER_PACK_SIZE 8
00255
00256
00257 static const char toofew[] = "too few arguments";
00258
00259 static void encodes(VALUE,const char*,long,int,int);
00260 static void qpencode(VALUE,VALUE,long);
00261
00262 static unsigned long utf8_to_uv(const char*,long*);
00263
00264 static ID id_associated;
00265
00266 static void
00267 str_associate(VALUE str, VALUE add)
00268 {
00269 VALUE assoc;
00270
00271 assoc = rb_attr_get(str, id_associated);
00272 if (RB_TYPE_P(assoc, T_ARRAY)) {
00273
00274 rb_ary_concat(assoc, add);
00275 }
00276 else {
00277 rb_ivar_set(str, id_associated, add);
00278 }
00279 }
00280
00281 static VALUE
00282 str_associated(VALUE str)
00283 {
00284 VALUE assoc = rb_attr_get(str, id_associated);
00285 if (NIL_P(assoc)) assoc = Qfalse;
00286 return assoc;
00287 }
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393 static VALUE
00394 pack_pack(VALUE ary, VALUE fmt)
00395 {
00396 static const char nul10[] = "\0\0\0\0\0\0\0\0\0\0";
00397 static const char spc10[] = " ";
00398 const char *p, *pend;
00399 VALUE res, from, associates = 0;
00400 char type;
00401 long items, len, idx, plen;
00402 const char *ptr;
00403 int enc_info = 1;
00404 #ifdef NATINT_PACK
00405 int natint;
00406 #endif
00407 int integer_size, bigendian_p;
00408
00409 StringValue(fmt);
00410 p = RSTRING_PTR(fmt);
00411 pend = p + RSTRING_LEN(fmt);
00412 res = rb_str_buf_new(0);
00413
00414 items = RARRAY_LEN(ary);
00415 idx = 0;
00416
00417 #define TOO_FEW (rb_raise(rb_eArgError, toofew), 0)
00418 #define THISFROM (items > 0 ? RARRAY_PTR(ary)[idx] : TOO_FEW)
00419 #define NEXTFROM (items-- > 0 ? RARRAY_PTR(ary)[idx++] : TOO_FEW)
00420
00421 while (p < pend) {
00422 int explicit_endian = 0;
00423 if (RSTRING_PTR(fmt) + RSTRING_LEN(fmt) != pend) {
00424 rb_raise(rb_eRuntimeError, "format string modified");
00425 }
00426 type = *p++;
00427 #ifdef NATINT_PACK
00428 natint = 0;
00429 #endif
00430
00431 if (ISSPACE(type)) continue;
00432 if (type == '#') {
00433 while ((p < pend) && (*p != '\n')) {
00434 p++;
00435 }
00436 continue;
00437 }
00438
00439 {
00440 static const char natstr[] = "sSiIlL";
00441 static const char endstr[] = "sSiIlLqQ";
00442
00443 modifiers:
00444 switch (*p) {
00445 case '_':
00446 case '!':
00447 if (strchr(natstr, type)) {
00448 #ifdef NATINT_PACK
00449 natint = 1;
00450 #endif
00451 p++;
00452 }
00453 else {
00454 rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, natstr);
00455 }
00456 goto modifiers;
00457
00458 case '<':
00459 case '>':
00460 if (!strchr(endstr, type)) {
00461 rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, endstr);
00462 }
00463 if (explicit_endian) {
00464 rb_raise(rb_eRangeError, "Can't use both '<' and '>'");
00465 }
00466 explicit_endian = *p++;
00467 goto modifiers;
00468 }
00469 }
00470
00471 if (*p == '*') {
00472 len = strchr("@Xxu", type) ? 0
00473 : strchr("PMm", type) ? 1
00474 : items;
00475 p++;
00476 }
00477 else if (ISDIGIT(*p)) {
00478 errno = 0;
00479 len = STRTOUL(p, (char**)&p, 10);
00480 if (errno) {
00481 rb_raise(rb_eRangeError, "pack length too big");
00482 }
00483 }
00484 else {
00485 len = 1;
00486 }
00487
00488 switch (type) {
00489 case 'U':
00490
00491 if (enc_info == 1) enc_info = 2;
00492 break;
00493 case 'm': case 'M': case 'u':
00494
00495 break;
00496 default:
00497
00498 enc_info = 0;
00499 break;
00500 }
00501 switch (type) {
00502 case 'A': case 'a': case 'Z':
00503 case 'B': case 'b':
00504 case 'H': case 'h':
00505 from = NEXTFROM;
00506 if (NIL_P(from)) {
00507 ptr = "";
00508 plen = 0;
00509 }
00510 else {
00511 StringValue(from);
00512 ptr = RSTRING_PTR(from);
00513 plen = RSTRING_LEN(from);
00514 OBJ_INFECT(res, from);
00515 }
00516
00517 if (p[-1] == '*')
00518 len = plen;
00519
00520 switch (type) {
00521 case 'a':
00522 case 'A':
00523 case 'Z':
00524 if (plen >= len) {
00525 rb_str_buf_cat(res, ptr, len);
00526 if (p[-1] == '*' && type == 'Z')
00527 rb_str_buf_cat(res, nul10, 1);
00528 }
00529 else {
00530 rb_str_buf_cat(res, ptr, plen);
00531 len -= plen;
00532 while (len >= 10) {
00533 rb_str_buf_cat(res, (type == 'A')?spc10:nul10, 10);
00534 len -= 10;
00535 }
00536 rb_str_buf_cat(res, (type == 'A')?spc10:nul10, len);
00537 }
00538 break;
00539
00540 #define castchar(from) (char)((from) & 0xff)
00541
00542 case 'b':
00543 {
00544 int byte = 0;
00545 long i, j = 0;
00546
00547 if (len > plen) {
00548 j = (len - plen + 1)/2;
00549 len = plen;
00550 }
00551 for (i=0; i++ < len; ptr++) {
00552 if (*ptr & 1)
00553 byte |= 128;
00554 if (i & 7)
00555 byte >>= 1;
00556 else {
00557 char c = castchar(byte);
00558 rb_str_buf_cat(res, &c, 1);
00559 byte = 0;
00560 }
00561 }
00562 if (len & 7) {
00563 char c;
00564 byte >>= 7 - (len & 7);
00565 c = castchar(byte);
00566 rb_str_buf_cat(res, &c, 1);
00567 }
00568 len = j;
00569 goto grow;
00570 }
00571 break;
00572
00573 case 'B':
00574 {
00575 int byte = 0;
00576 long i, j = 0;
00577
00578 if (len > plen) {
00579 j = (len - plen + 1)/2;
00580 len = plen;
00581 }
00582 for (i=0; i++ < len; ptr++) {
00583 byte |= *ptr & 1;
00584 if (i & 7)
00585 byte <<= 1;
00586 else {
00587 char c = castchar(byte);
00588 rb_str_buf_cat(res, &c, 1);
00589 byte = 0;
00590 }
00591 }
00592 if (len & 7) {
00593 char c;
00594 byte <<= 7 - (len & 7);
00595 c = castchar(byte);
00596 rb_str_buf_cat(res, &c, 1);
00597 }
00598 len = j;
00599 goto grow;
00600 }
00601 break;
00602
00603 case 'h':
00604 {
00605 int byte = 0;
00606 long i, j = 0;
00607
00608 if (len > plen) {
00609 j = (len + 1) / 2 - (plen + 1) / 2;
00610 len = plen;
00611 }
00612 for (i=0; i++ < len; ptr++) {
00613 if (ISALPHA(*ptr))
00614 byte |= (((*ptr & 15) + 9) & 15) << 4;
00615 else
00616 byte |= (*ptr & 15) << 4;
00617 if (i & 1)
00618 byte >>= 4;
00619 else {
00620 char c = castchar(byte);
00621 rb_str_buf_cat(res, &c, 1);
00622 byte = 0;
00623 }
00624 }
00625 if (len & 1) {
00626 char c = castchar(byte);
00627 rb_str_buf_cat(res, &c, 1);
00628 }
00629 len = j;
00630 goto grow;
00631 }
00632 break;
00633
00634 case 'H':
00635 {
00636 int byte = 0;
00637 long i, j = 0;
00638
00639 if (len > plen) {
00640 j = (len + 1) / 2 - (plen + 1) / 2;
00641 len = plen;
00642 }
00643 for (i=0; i++ < len; ptr++) {
00644 if (ISALPHA(*ptr))
00645 byte |= ((*ptr & 15) + 9) & 15;
00646 else
00647 byte |= *ptr & 15;
00648 if (i & 1)
00649 byte <<= 4;
00650 else {
00651 char c = castchar(byte);
00652 rb_str_buf_cat(res, &c, 1);
00653 byte = 0;
00654 }
00655 }
00656 if (len & 1) {
00657 char c = castchar(byte);
00658 rb_str_buf_cat(res, &c, 1);
00659 }
00660 len = j;
00661 goto grow;
00662 }
00663 break;
00664 }
00665 break;
00666
00667 case 'c':
00668 case 'C':
00669 while (len-- > 0) {
00670 char c;
00671
00672 from = NEXTFROM;
00673 c = (char)num2i32(from);
00674 rb_str_buf_cat(res, &c, sizeof(char));
00675 }
00676 break;
00677
00678 case 's':
00679 integer_size = NATINT_LEN(short, 2);
00680 bigendian_p = BIGENDIAN_P();
00681 goto pack_integer;
00682
00683 case 'S':
00684 integer_size = NATINT_LEN(short, 2);
00685 bigendian_p = BIGENDIAN_P();
00686 goto pack_integer;
00687
00688 case 'i':
00689 integer_size = (int)sizeof(int);
00690 bigendian_p = BIGENDIAN_P();
00691 goto pack_integer;
00692
00693 case 'I':
00694 integer_size = (int)sizeof(int);
00695 bigendian_p = BIGENDIAN_P();
00696 goto pack_integer;
00697
00698 case 'l':
00699 integer_size = NATINT_LEN(long, 4);
00700 bigendian_p = BIGENDIAN_P();
00701 goto pack_integer;
00702
00703 case 'L':
00704 integer_size = NATINT_LEN(long, 4);
00705 bigendian_p = BIGENDIAN_P();
00706 goto pack_integer;
00707
00708 case 'q':
00709 integer_size = 8;
00710 bigendian_p = BIGENDIAN_P();
00711 goto pack_integer;
00712
00713 case 'Q':
00714 integer_size = 8;
00715 bigendian_p = BIGENDIAN_P();
00716 goto pack_integer;
00717
00718 case 'n':
00719 integer_size = 2;
00720 bigendian_p = 1;
00721 goto pack_integer;
00722
00723 case 'N':
00724 integer_size = 4;
00725 bigendian_p = 1;
00726 goto pack_integer;
00727
00728 case 'v':
00729 integer_size = 2;
00730 bigendian_p = 0;
00731 goto pack_integer;
00732
00733 case 'V':
00734 integer_size = 4;
00735 bigendian_p = 0;
00736 goto pack_integer;
00737
00738 pack_integer:
00739 if (explicit_endian) {
00740 bigendian_p = explicit_endian == '>';
00741 }
00742
00743 switch (integer_size) {
00744 #if defined(HAVE_INT16_T) && !defined(FORCE_BIG_PACK)
00745 case SIZEOF_INT16_T:
00746 while (len-- > 0) {
00747 union {
00748 int16_t i;
00749 char a[sizeof(int16_t)];
00750 } v;
00751
00752 from = NEXTFROM;
00753 v.i = (int16_t)num2i32(from);
00754 if (bigendian_p != BIGENDIAN_P()) v.i = swap16(v.i);
00755 rb_str_buf_cat(res, v.a, sizeof(int16_t));
00756 }
00757 break;
00758 #endif
00759
00760 #if defined(HAVE_INT32_T) && !defined(FORCE_BIG_PACK)
00761 case SIZEOF_INT32_T:
00762 while (len-- > 0) {
00763 union {
00764 int32_t i;
00765 char a[sizeof(int32_t)];
00766 } v;
00767
00768 from = NEXTFROM;
00769 v.i = (int32_t)num2i32(from);
00770 if (bigendian_p != BIGENDIAN_P()) v.i = swap32(v.i);
00771 rb_str_buf_cat(res, v.a, sizeof(int32_t));
00772 }
00773 break;
00774 #endif
00775
00776 #if defined(HAVE_INT64_T) && SIZEOF_LONG == SIZEOF_INT64_T && !defined(FORCE_BIG_PACK)
00777 case SIZEOF_INT64_T:
00778 while (len-- > 0) {
00779 union {
00780 int64_t i;
00781 char a[sizeof(int64_t)];
00782 } v;
00783
00784 from = NEXTFROM;
00785 v.i = num2i32(from);
00786 if (bigendian_p != BIGENDIAN_P()) v.i = swap64(v.i);
00787 rb_str_buf_cat(res, v.a, sizeof(int64_t));
00788 }
00789 break;
00790 #endif
00791
00792 default:
00793 if (integer_size > MAX_INTEGER_PACK_SIZE)
00794 rb_bug("unexpected intger size for pack: %d", integer_size);
00795 while (len-- > 0) {
00796 union {
00797 unsigned long i[(MAX_INTEGER_PACK_SIZE+SIZEOF_LONG-1)/SIZEOF_LONG];
00798 char a[(MAX_INTEGER_PACK_SIZE+SIZEOF_LONG-1)/SIZEOF_LONG*SIZEOF_LONG];
00799 } v;
00800 int num_longs = (integer_size+SIZEOF_LONG-1)/SIZEOF_LONG;
00801 int i;
00802
00803 from = NEXTFROM;
00804 rb_big_pack(from, v.i, num_longs);
00805 if (bigendian_p) {
00806 for (i = 0; i < num_longs/2; i++) {
00807 unsigned long t = v.i[i];
00808 v.i[i] = v.i[num_longs-1-i];
00809 v.i[num_longs-1-i] = t;
00810 }
00811 }
00812 if (bigendian_p != BIGENDIAN_P()) {
00813 for (i = 0; i < num_longs; i++)
00814 v.i[i] = swapl(v.i[i]);
00815 }
00816 rb_str_buf_cat(res,
00817 bigendian_p ?
00818 v.a + sizeof(long)*num_longs - integer_size :
00819 v.a,
00820 integer_size);
00821 }
00822 break;
00823 }
00824 break;
00825
00826 case 'f':
00827 case 'F':
00828 while (len-- > 0) {
00829 float f;
00830
00831 from = NEXTFROM;
00832 f = (float)RFLOAT_VALUE(rb_to_float(from));
00833 rb_str_buf_cat(res, (char*)&f, sizeof(float));
00834 }
00835 break;
00836
00837 case 'e':
00838 while (len-- > 0) {
00839 float f;
00840 FLOAT_CONVWITH(ftmp);
00841
00842 from = NEXTFROM;
00843 f = (float)RFLOAT_VALUE(rb_to_float(from));
00844 f = HTOVF(f,ftmp);
00845 rb_str_buf_cat(res, (char*)&f, sizeof(float));
00846 }
00847 break;
00848
00849 case 'E':
00850 while (len-- > 0) {
00851 double d;
00852 DOUBLE_CONVWITH(dtmp);
00853
00854 from = NEXTFROM;
00855 d = RFLOAT_VALUE(rb_to_float(from));
00856 d = HTOVD(d,dtmp);
00857 rb_str_buf_cat(res, (char*)&d, sizeof(double));
00858 }
00859 break;
00860
00861 case 'd':
00862 case 'D':
00863 while (len-- > 0) {
00864 double d;
00865
00866 from = NEXTFROM;
00867 d = RFLOAT_VALUE(rb_to_float(from));
00868 rb_str_buf_cat(res, (char*)&d, sizeof(double));
00869 }
00870 break;
00871
00872 case 'g':
00873 while (len-- > 0) {
00874 float f;
00875 FLOAT_CONVWITH(ftmp);
00876
00877 from = NEXTFROM;
00878 f = (float)RFLOAT_VALUE(rb_to_float(from));
00879 f = HTONF(f,ftmp);
00880 rb_str_buf_cat(res, (char*)&f, sizeof(float));
00881 }
00882 break;
00883
00884 case 'G':
00885 while (len-- > 0) {
00886 double d;
00887 DOUBLE_CONVWITH(dtmp);
00888
00889 from = NEXTFROM;
00890 d = RFLOAT_VALUE(rb_to_float(from));
00891 d = HTOND(d,dtmp);
00892 rb_str_buf_cat(res, (char*)&d, sizeof(double));
00893 }
00894 break;
00895
00896 case 'x':
00897 grow:
00898 while (len >= 10) {
00899 rb_str_buf_cat(res, nul10, 10);
00900 len -= 10;
00901 }
00902 rb_str_buf_cat(res, nul10, len);
00903 break;
00904
00905 case 'X':
00906 shrink:
00907 plen = RSTRING_LEN(res);
00908 if (plen < len)
00909 rb_raise(rb_eArgError, "X outside of string");
00910 rb_str_set_len(res, plen - len);
00911 break;
00912
00913 case '@':
00914 len -= RSTRING_LEN(res);
00915 if (len > 0) goto grow;
00916 len = -len;
00917 if (len > 0) goto shrink;
00918 break;
00919
00920 case '%':
00921 rb_raise(rb_eArgError, "%% is not supported");
00922 break;
00923
00924 case 'U':
00925 while (len-- > 0) {
00926 SIGNED_VALUE l;
00927 char buf[8];
00928 int le;
00929
00930 from = NEXTFROM;
00931 from = rb_to_int(from);
00932 l = NUM2LONG(from);
00933 if (l < 0) {
00934 rb_raise(rb_eRangeError, "pack(U): value out of range");
00935 }
00936 le = rb_uv_to_utf8(buf, l);
00937 rb_str_buf_cat(res, (char*)buf, le);
00938 }
00939 break;
00940
00941 case 'u':
00942 case 'm':
00943 from = NEXTFROM;
00944 StringValue(from);
00945 ptr = RSTRING_PTR(from);
00946 plen = RSTRING_LEN(from);
00947
00948 if (len == 0 && type == 'm') {
00949 encodes(res, ptr, plen, type, 0);
00950 ptr += plen;
00951 break;
00952 }
00953 if (len <= 2)
00954 len = 45;
00955 else if (len > 63 && type == 'u')
00956 len = 63;
00957 else
00958 len = len / 3 * 3;
00959 while (plen > 0) {
00960 long todo;
00961
00962 if (plen > len)
00963 todo = len;
00964 else
00965 todo = plen;
00966 encodes(res, ptr, todo, type, 1);
00967 plen -= todo;
00968 ptr += todo;
00969 }
00970 break;
00971
00972 case 'M':
00973 from = rb_obj_as_string(NEXTFROM);
00974 if (len <= 1)
00975 len = 72;
00976 qpencode(res, from, len);
00977 break;
00978
00979 case 'P':
00980 from = THISFROM;
00981 if (!NIL_P(from)) {
00982 StringValue(from);
00983 if (RSTRING_LEN(from) < len) {
00984 rb_raise(rb_eArgError, "too short buffer for P(%ld for %ld)",
00985 RSTRING_LEN(from), len);
00986 }
00987 }
00988 len = 1;
00989
00990 case 'p':
00991 while (len-- > 0) {
00992 char *t;
00993 from = NEXTFROM;
00994 if (NIL_P(from)) {
00995 t = 0;
00996 }
00997 else {
00998 t = StringValuePtr(from);
00999 }
01000 if (!associates) {
01001 associates = rb_ary_new();
01002 }
01003 rb_ary_push(associates, from);
01004 rb_obj_taint(from);
01005 rb_str_buf_cat(res, (char*)&t, sizeof(char*));
01006 }
01007 break;
01008
01009 case 'w':
01010 while (len-- > 0) {
01011 unsigned long ul;
01012 VALUE buf = rb_str_new(0, 0);
01013 char c, *bufs, *bufe;
01014
01015 from = NEXTFROM;
01016 if (RB_TYPE_P(from, T_BIGNUM)) {
01017 VALUE big128 = rb_uint2big(128);
01018 while (RB_TYPE_P(from, T_BIGNUM)) {
01019 from = rb_big_divmod(from, big128);
01020 c = castchar(NUM2INT(RARRAY_PTR(from)[1]) | 0x80);
01021 rb_str_buf_cat(buf, &c, sizeof(char));
01022 from = RARRAY_PTR(from)[0];
01023 }
01024 }
01025
01026 {
01027 long l = NUM2LONG(from);
01028 if (l < 0) {
01029 rb_raise(rb_eArgError, "can't compress negative numbers");
01030 }
01031 ul = l;
01032 }
01033
01034 while (ul) {
01035 c = castchar((ul & 0x7f) | 0x80);
01036 rb_str_buf_cat(buf, &c, sizeof(char));
01037 ul >>= 7;
01038 }
01039
01040 if (RSTRING_LEN(buf)) {
01041 bufs = RSTRING_PTR(buf);
01042 bufe = bufs + RSTRING_LEN(buf) - 1;
01043 *bufs &= 0x7f;
01044 while (bufs < bufe) {
01045 c = *bufs;
01046 *bufs++ = *bufe;
01047 *bufe-- = c;
01048 }
01049 rb_str_buf_cat(res, RSTRING_PTR(buf), RSTRING_LEN(buf));
01050 }
01051 else {
01052 c = 0;
01053 rb_str_buf_cat(res, &c, sizeof(char));
01054 }
01055 }
01056 break;
01057
01058 default:
01059 rb_warning("unknown pack directive '%c' in '%s'",
01060 type, RSTRING_PTR(fmt));
01061 break;
01062 }
01063 }
01064
01065 if (associates) {
01066 str_associate(res, associates);
01067 }
01068 OBJ_INFECT(res, fmt);
01069 switch (enc_info) {
01070 case 1:
01071 ENCODING_CODERANGE_SET(res, rb_usascii_encindex(), ENC_CODERANGE_7BIT);
01072 break;
01073 case 2:
01074 rb_enc_set_index(res, rb_utf8_encindex());
01075 break;
01076 default:
01077
01078 break;
01079 }
01080 return res;
01081 }
01082
01083 static const char uu_table[] =
01084 "`!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_";
01085 static const char b64_table[] =
01086 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
01087
01088 static void
01089 encodes(VALUE str, const char *s, long len, int type, int tail_lf)
01090 {
01091 char buff[4096];
01092 long i = 0;
01093 const char *trans = type == 'u' ? uu_table : b64_table;
01094 char padding;
01095
01096 if (type == 'u') {
01097 buff[i++] = (char)len + ' ';
01098 padding = '`';
01099 }
01100 else {
01101 padding = '=';
01102 }
01103 while (len >= 3) {
01104 while (len >= 3 && sizeof(buff)-i >= 4) {
01105 buff[i++] = trans[077 & (*s >> 2)];
01106 buff[i++] = trans[077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017))];
01107 buff[i++] = trans[077 & (((s[1] << 2) & 074) | ((s[2] >> 6) & 03))];
01108 buff[i++] = trans[077 & s[2]];
01109 s += 3;
01110 len -= 3;
01111 }
01112 if (sizeof(buff)-i < 4) {
01113 rb_str_buf_cat(str, buff, i);
01114 i = 0;
01115 }
01116 }
01117
01118 if (len == 2) {
01119 buff[i++] = trans[077 & (*s >> 2)];
01120 buff[i++] = trans[077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017))];
01121 buff[i++] = trans[077 & (((s[1] << 2) & 074) | (('\0' >> 6) & 03))];
01122 buff[i++] = padding;
01123 }
01124 else if (len == 1) {
01125 buff[i++] = trans[077 & (*s >> 2)];
01126 buff[i++] = trans[077 & (((*s << 4) & 060) | (('\0' >> 4) & 017))];
01127 buff[i++] = padding;
01128 buff[i++] = padding;
01129 }
01130 if (tail_lf) buff[i++] = '\n';
01131 rb_str_buf_cat(str, buff, i);
01132 }
01133
01134 static const char hex_table[] = "0123456789ABCDEF";
01135
01136 static void
01137 qpencode(VALUE str, VALUE from, long len)
01138 {
01139 char buff[1024];
01140 long i = 0, n = 0, prev = EOF;
01141 unsigned char *s = (unsigned char*)RSTRING_PTR(from);
01142 unsigned char *send = s + RSTRING_LEN(from);
01143
01144 while (s < send) {
01145 if ((*s > 126) ||
01146 (*s < 32 && *s != '\n' && *s != '\t') ||
01147 (*s == '=')) {
01148 buff[i++] = '=';
01149 buff[i++] = hex_table[*s >> 4];
01150 buff[i++] = hex_table[*s & 0x0f];
01151 n += 3;
01152 prev = EOF;
01153 }
01154 else if (*s == '\n') {
01155 if (prev == ' ' || prev == '\t') {
01156 buff[i++] = '=';
01157 buff[i++] = *s;
01158 }
01159 buff[i++] = *s;
01160 n = 0;
01161 prev = *s;
01162 }
01163 else {
01164 buff[i++] = *s;
01165 n++;
01166 prev = *s;
01167 }
01168 if (n > len) {
01169 buff[i++] = '=';
01170 buff[i++] = '\n';
01171 n = 0;
01172 prev = '\n';
01173 }
01174 if (i > 1024 - 5) {
01175 rb_str_buf_cat(str, buff, i);
01176 i = 0;
01177 }
01178 s++;
01179 }
01180 if (n > 0) {
01181 buff[i++] = '=';
01182 buff[i++] = '\n';
01183 }
01184 if (i > 0) {
01185 rb_str_buf_cat(str, buff, i);
01186 }
01187 }
01188
01189 static inline int
01190 hex2num(char c)
01191 {
01192 switch (c) {
01193 case '0': case '1': case '2': case '3': case '4':
01194 case '5': case '6': case '7': case '8': case '9':
01195 return c - '0';
01196 case 'a': case 'b': case 'c':
01197 case 'd': case 'e': case 'f':
01198 return c - 'a' + 10;
01199 case 'A': case 'B': case 'C':
01200 case 'D': case 'E': case 'F':
01201 return c - 'A' + 10;
01202 default:
01203 return -1;
01204 }
01205 }
01206
01207 #define PACK_LENGTH_ADJUST_SIZE(sz) do { \
01208 tmp_len = 0; \
01209 if (len > (long)((send-s)/(sz))) { \
01210 if (!star) { \
01211 tmp_len = len-(send-s)/(sz); \
01212 } \
01213 len = (send-s)/(sz); \
01214 } \
01215 } while (0)
01216
01217 #define PACK_ITEM_ADJUST() do { \
01218 if (tmp_len > 0 && !block_p) \
01219 rb_ary_store(ary, RARRAY_LEN(ary)+tmp_len-1, Qnil); \
01220 } while (0)
01221
01222 static VALUE
01223 infected_str_new(const char *ptr, long len, VALUE str)
01224 {
01225 VALUE s = rb_str_new(ptr, len);
01226
01227 OBJ_INFECT(s, str);
01228 return s;
01229 }
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338
01339 static VALUE
01340 pack_unpack(VALUE str, VALUE fmt)
01341 {
01342 static const char hexdigits[] = "0123456789abcdef";
01343 char *s, *send;
01344 char *p, *pend;
01345 VALUE ary;
01346 char type;
01347 long len, tmp_len;
01348 int star;
01349 #ifdef NATINT_PACK
01350 int natint;
01351 #endif
01352 int block_p = rb_block_given_p();
01353 int signed_p, integer_size, bigendian_p;
01354 #define UNPACK_PUSH(item) do {\
01355 VALUE item_val = (item);\
01356 if (block_p) {\
01357 rb_yield(item_val);\
01358 }\
01359 else {\
01360 rb_ary_push(ary, item_val);\
01361 }\
01362 } while (0)
01363
01364 StringValue(str);
01365 StringValue(fmt);
01366 s = RSTRING_PTR(str);
01367 send = s + RSTRING_LEN(str);
01368 p = RSTRING_PTR(fmt);
01369 pend = p + RSTRING_LEN(fmt);
01370
01371 ary = block_p ? Qnil : rb_ary_new();
01372 while (p < pend) {
01373 int explicit_endian = 0;
01374 type = *p++;
01375 #ifdef NATINT_PACK
01376 natint = 0;
01377 #endif
01378
01379 if (ISSPACE(type)) continue;
01380 if (type == '#') {
01381 while ((p < pend) && (*p != '\n')) {
01382 p++;
01383 }
01384 continue;
01385 }
01386
01387 star = 0;
01388 {
01389 static const char natstr[] = "sSiIlL";
01390 static const char endstr[] = "sSiIlLqQ";
01391
01392 modifiers:
01393 switch (*p) {
01394 case '_':
01395 case '!':
01396
01397 if (strchr(natstr, type)) {
01398 #ifdef NATINT_PACK
01399 natint = 1;
01400 #endif
01401 p++;
01402 }
01403 else {
01404 rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, natstr);
01405 }
01406 goto modifiers;
01407
01408 case '<':
01409 case '>':
01410 if (!strchr(endstr, type)) {
01411 rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, endstr);
01412 }
01413 if (explicit_endian) {
01414 rb_raise(rb_eRangeError, "Can't use both '<' and '>'");
01415 }
01416 explicit_endian = *p++;
01417 goto modifiers;
01418 }
01419 }
01420
01421 if (p >= pend)
01422 len = 1;
01423 else if (*p == '*') {
01424 star = 1;
01425 len = send - s;
01426 p++;
01427 }
01428 else if (ISDIGIT(*p)) {
01429 errno = 0;
01430 len = STRTOUL(p, (char**)&p, 10);
01431 if (errno) {
01432 rb_raise(rb_eRangeError, "pack length too big");
01433 }
01434 }
01435 else {
01436 len = (type != '@');
01437 }
01438
01439 switch (type) {
01440 case '%':
01441 rb_raise(rb_eArgError, "%% is not supported");
01442 break;
01443
01444 case 'A':
01445 if (len > send - s) len = send - s;
01446 {
01447 long end = len;
01448 char *t = s + len - 1;
01449
01450 while (t >= s) {
01451 if (*t != ' ' && *t != '\0') break;
01452 t--; len--;
01453 }
01454 UNPACK_PUSH(infected_str_new(s, len, str));
01455 s += end;
01456 }
01457 break;
01458
01459 case 'Z':
01460 {
01461 char *t = s;
01462
01463 if (len > send-s) len = send-s;
01464 while (t < s+len && *t) t++;
01465 UNPACK_PUSH(infected_str_new(s, t-s, str));
01466 if (t < send) t++;
01467 s = star ? t : s+len;
01468 }
01469 break;
01470
01471 case 'a':
01472 if (len > send - s) len = send - s;
01473 UNPACK_PUSH(infected_str_new(s, len, str));
01474 s += len;
01475 break;
01476
01477 case 'b':
01478 {
01479 VALUE bitstr;
01480 char *t;
01481 int bits;
01482 long i;
01483
01484 if (p[-1] == '*' || len > (send - s) * 8)
01485 len = (send - s) * 8;
01486 bits = 0;
01487 UNPACK_PUSH(bitstr = rb_usascii_str_new(0, len));
01488 t = RSTRING_PTR(bitstr);
01489 for (i=0; i<len; i++) {
01490 if (i & 7) bits >>= 1;
01491 else bits = *s++;
01492 *t++ = (bits & 1) ? '1' : '0';
01493 }
01494 }
01495 break;
01496
01497 case 'B':
01498 {
01499 VALUE bitstr;
01500 char *t;
01501 int bits;
01502 long i;
01503
01504 if (p[-1] == '*' || len > (send - s) * 8)
01505 len = (send - s) * 8;
01506 bits = 0;
01507 UNPACK_PUSH(bitstr = rb_usascii_str_new(0, len));
01508 t = RSTRING_PTR(bitstr);
01509 for (i=0; i<len; i++) {
01510 if (i & 7) bits <<= 1;
01511 else bits = *s++;
01512 *t++ = (bits & 128) ? '1' : '0';
01513 }
01514 }
01515 break;
01516
01517 case 'h':
01518 {
01519 VALUE bitstr;
01520 char *t;
01521 int bits;
01522 long i;
01523
01524 if (p[-1] == '*' || len > (send - s) * 2)
01525 len = (send - s) * 2;
01526 bits = 0;
01527 UNPACK_PUSH(bitstr = rb_usascii_str_new(0, len));
01528 t = RSTRING_PTR(bitstr);
01529 for (i=0; i<len; i++) {
01530 if (i & 1)
01531 bits >>= 4;
01532 else
01533 bits = *s++;
01534 *t++ = hexdigits[bits & 15];
01535 }
01536 }
01537 break;
01538
01539 case 'H':
01540 {
01541 VALUE bitstr;
01542 char *t;
01543 int bits;
01544 long i;
01545
01546 if (p[-1] == '*' || len > (send - s) * 2)
01547 len = (send - s) * 2;
01548 bits = 0;
01549 UNPACK_PUSH(bitstr = rb_usascii_str_new(0, len));
01550 t = RSTRING_PTR(bitstr);
01551 for (i=0; i<len; i++) {
01552 if (i & 1)
01553 bits <<= 4;
01554 else
01555 bits = *s++;
01556 *t++ = hexdigits[(bits >> 4) & 15];
01557 }
01558 }
01559 break;
01560
01561 case 'c':
01562 PACK_LENGTH_ADJUST_SIZE(sizeof(char));
01563 while (len-- > 0) {
01564 int c = *s++;
01565 if (c > (char)127) c-=256;
01566 UNPACK_PUSH(INT2FIX(c));
01567 }
01568 PACK_ITEM_ADJUST();
01569 break;
01570
01571 case 'C':
01572 PACK_LENGTH_ADJUST_SIZE(sizeof(unsigned char));
01573 while (len-- > 0) {
01574 unsigned char c = *s++;
01575 UNPACK_PUSH(INT2FIX(c));
01576 }
01577 PACK_ITEM_ADJUST();
01578 break;
01579
01580 case 's':
01581 signed_p = 1;
01582 integer_size = NATINT_LEN(short, 2);
01583 bigendian_p = BIGENDIAN_P();
01584 goto unpack_integer;
01585
01586 case 'S':
01587 signed_p = 0;
01588 integer_size = NATINT_LEN(short, 2);
01589 bigendian_p = BIGENDIAN_P();
01590 goto unpack_integer;
01591
01592 case 'i':
01593 signed_p = 1;
01594 integer_size = (int)sizeof(int);
01595 bigendian_p = BIGENDIAN_P();
01596 goto unpack_integer;
01597
01598 case 'I':
01599 signed_p = 0;
01600 integer_size = (int)sizeof(int);
01601 bigendian_p = BIGENDIAN_P();
01602 goto unpack_integer;
01603
01604 case 'l':
01605 signed_p = 1;
01606 integer_size = NATINT_LEN(long, 4);
01607 bigendian_p = BIGENDIAN_P();
01608 goto unpack_integer;
01609
01610 case 'L':
01611 signed_p = 0;
01612 integer_size = NATINT_LEN(long, 4);
01613 bigendian_p = BIGENDIAN_P();
01614 goto unpack_integer;
01615
01616 case 'q':
01617 signed_p = 1;
01618 integer_size = 8;
01619 bigendian_p = BIGENDIAN_P();
01620 goto unpack_integer;
01621
01622 case 'Q':
01623 signed_p = 0;
01624 integer_size = 8;
01625 bigendian_p = BIGENDIAN_P();
01626 goto unpack_integer;
01627
01628 case 'n':
01629 signed_p = 0;
01630 integer_size = 2;
01631 bigendian_p = 1;
01632 goto unpack_integer;
01633
01634 case 'N':
01635 signed_p = 0;
01636 integer_size = 4;
01637 bigendian_p = 1;
01638 goto unpack_integer;
01639
01640 case 'v':
01641 signed_p = 0;
01642 integer_size = 2;
01643 bigendian_p = 0;
01644 goto unpack_integer;
01645
01646 case 'V':
01647 signed_p = 0;
01648 integer_size = 4;
01649 bigendian_p = 0;
01650 goto unpack_integer;
01651
01652 unpack_integer:
01653 if (explicit_endian) {
01654 bigendian_p = explicit_endian == '>';
01655 }
01656
01657 switch (integer_size) {
01658 #if defined(HAVE_INT16_T) && !defined(FORCE_BIG_PACK)
01659 case SIZEOF_INT16_T:
01660 if (signed_p) {
01661 PACK_LENGTH_ADJUST_SIZE(sizeof(int16_t));
01662 while (len-- > 0) {
01663 union {
01664 int16_t i;
01665 char a[sizeof(int16_t)];
01666 } v;
01667 memcpy(v.a, s, sizeof(int16_t));
01668 if (bigendian_p != BIGENDIAN_P()) v.i = swap16(v.i);
01669 s += sizeof(int16_t);
01670 UNPACK_PUSH(INT2FIX(v.i));
01671 }
01672 PACK_ITEM_ADJUST();
01673 }
01674 else {
01675 PACK_LENGTH_ADJUST_SIZE(sizeof(uint16_t));
01676 while (len-- > 0) {
01677 union {
01678 uint16_t i;
01679 char a[sizeof(uint16_t)];
01680 } v;
01681 memcpy(v.a, s, sizeof(uint16_t));
01682 if (bigendian_p != BIGENDIAN_P()) v.i = swap16(v.i);
01683 s += sizeof(uint16_t);
01684 UNPACK_PUSH(INT2FIX(v.i));
01685 }
01686 PACK_ITEM_ADJUST();
01687 }
01688 break;
01689 #endif
01690
01691 #if defined(HAVE_INT32_T) && !defined(FORCE_BIG_PACK)
01692 case SIZEOF_INT32_T:
01693 if (signed_p) {
01694 PACK_LENGTH_ADJUST_SIZE(sizeof(int32_t));
01695 while (len-- > 0) {
01696 union {
01697 int32_t i;
01698 char a[sizeof(int32_t)];
01699 } v;
01700 memcpy(v.a, s, sizeof(int32_t));
01701 if (bigendian_p != BIGENDIAN_P()) v.i = swap32(v.i);
01702 s += sizeof(int32_t);
01703 UNPACK_PUSH(INT2NUM(v.i));
01704 }
01705 PACK_ITEM_ADJUST();
01706 }
01707 else {
01708 PACK_LENGTH_ADJUST_SIZE(sizeof(uint32_t));
01709 while (len-- > 0) {
01710 union {
01711 uint32_t i;
01712 char a[sizeof(uint32_t)];
01713 } v;
01714 memcpy(v.a, s, sizeof(uint32_t));
01715 if (bigendian_p != BIGENDIAN_P()) v.i = swap32(v.i);
01716 s += sizeof(uint32_t);
01717 UNPACK_PUSH(UINT2NUM(v.i));
01718 }
01719 PACK_ITEM_ADJUST();
01720 }
01721 break;
01722 #endif
01723
01724 #if defined(HAVE_INT64_T) && !defined(FORCE_BIG_PACK)
01725 case SIZEOF_INT64_T:
01726 if (signed_p) {
01727 PACK_LENGTH_ADJUST_SIZE(sizeof(int64_t));
01728 while (len-- > 0) {
01729 union {
01730 int64_t i;
01731 char a[sizeof(int64_t)];
01732 } v;
01733 memcpy(v.a, s, sizeof(int64_t));
01734 if (bigendian_p != BIGENDIAN_P()) v.i = swap64(v.i);
01735 s += sizeof(int64_t);
01736 UNPACK_PUSH(INT64toNUM(v.i));
01737 }
01738 PACK_ITEM_ADJUST();
01739 }
01740 else {
01741 PACK_LENGTH_ADJUST_SIZE(sizeof(uint64_t));
01742 while (len-- > 0) {
01743 union {
01744 uint64_t i;
01745 char a[sizeof(uint64_t)];
01746 } v;
01747 memcpy(v.a, s, sizeof(uint64_t));
01748 if (bigendian_p != BIGENDIAN_P()) v.i = swap64(v.i);
01749 s += sizeof(uint64_t);
01750 UNPACK_PUSH(UINT64toNUM(v.i));
01751 }
01752 PACK_ITEM_ADJUST();
01753 }
01754 break;
01755 #endif
01756
01757 default:
01758 if (integer_size > MAX_INTEGER_PACK_SIZE)
01759 rb_bug("unexpected integer size for pack: %d", integer_size);
01760 PACK_LENGTH_ADJUST_SIZE(integer_size);
01761 while (len-- > 0) {
01762 union {
01763 unsigned long i[(MAX_INTEGER_PACK_SIZE+SIZEOF_LONG)/SIZEOF_LONG];
01764 char a[(MAX_INTEGER_PACK_SIZE+SIZEOF_LONG)/SIZEOF_LONG*SIZEOF_LONG];
01765 } v;
01766 int num_longs = (integer_size+SIZEOF_LONG)/SIZEOF_LONG;
01767 int i;
01768
01769 if (signed_p && (signed char)s[bigendian_p ? 0 : (integer_size-1)] < 0)
01770 memset(v.a, 0xff, sizeof(long)*num_longs);
01771 else
01772 memset(v.a, 0, sizeof(long)*num_longs);
01773 if (bigendian_p)
01774 memcpy(v.a + sizeof(long)*num_longs - integer_size, s, integer_size);
01775 else
01776 memcpy(v.a, s, integer_size);
01777 if (bigendian_p) {
01778 for (i = 0; i < num_longs/2; i++) {
01779 unsigned long t = v.i[i];
01780 v.i[i] = v.i[num_longs-1-i];
01781 v.i[num_longs-1-i] = t;
01782 }
01783 }
01784 if (bigendian_p != BIGENDIAN_P()) {
01785 for (i = 0; i < num_longs; i++)
01786 v.i[i] = swapl(v.i[i]);
01787 }
01788 s += integer_size;
01789 UNPACK_PUSH(rb_big_unpack(v.i, num_longs));
01790 }
01791 PACK_ITEM_ADJUST();
01792 break;
01793 }
01794 break;
01795
01796 case 'f':
01797 case 'F':
01798 PACK_LENGTH_ADJUST_SIZE(sizeof(float));
01799 while (len-- > 0) {
01800 float tmp;
01801 memcpy(&tmp, s, sizeof(float));
01802 s += sizeof(float);
01803 UNPACK_PUSH(DBL2NUM((double)tmp));
01804 }
01805 PACK_ITEM_ADJUST();
01806 break;
01807
01808 case 'e':
01809 PACK_LENGTH_ADJUST_SIZE(sizeof(float));
01810 while (len-- > 0) {
01811 float tmp;
01812 FLOAT_CONVWITH(ftmp);
01813
01814 memcpy(&tmp, s, sizeof(float));
01815 s += sizeof(float);
01816 tmp = VTOHF(tmp,ftmp);
01817 UNPACK_PUSH(DBL2NUM((double)tmp));
01818 }
01819 PACK_ITEM_ADJUST();
01820 break;
01821
01822 case 'E':
01823 PACK_LENGTH_ADJUST_SIZE(sizeof(double));
01824 while (len-- > 0) {
01825 double tmp;
01826 DOUBLE_CONVWITH(dtmp);
01827
01828 memcpy(&tmp, s, sizeof(double));
01829 s += sizeof(double);
01830 tmp = VTOHD(tmp,dtmp);
01831 UNPACK_PUSH(DBL2NUM(tmp));
01832 }
01833 PACK_ITEM_ADJUST();
01834 break;
01835
01836 case 'D':
01837 case 'd':
01838 PACK_LENGTH_ADJUST_SIZE(sizeof(double));
01839 while (len-- > 0) {
01840 double tmp;
01841 memcpy(&tmp, s, sizeof(double));
01842 s += sizeof(double);
01843 UNPACK_PUSH(DBL2NUM(tmp));
01844 }
01845 PACK_ITEM_ADJUST();
01846 break;
01847
01848 case 'g':
01849 PACK_LENGTH_ADJUST_SIZE(sizeof(float));
01850 while (len-- > 0) {
01851 float tmp;
01852 FLOAT_CONVWITH(ftmp);
01853
01854 memcpy(&tmp, s, sizeof(float));
01855 s += sizeof(float);
01856 tmp = NTOHF(tmp,ftmp);
01857 UNPACK_PUSH(DBL2NUM((double)tmp));
01858 }
01859 PACK_ITEM_ADJUST();
01860 break;
01861
01862 case 'G':
01863 PACK_LENGTH_ADJUST_SIZE(sizeof(double));
01864 while (len-- > 0) {
01865 double tmp;
01866 DOUBLE_CONVWITH(dtmp);
01867
01868 memcpy(&tmp, s, sizeof(double));
01869 s += sizeof(double);
01870 tmp = NTOHD(tmp,dtmp);
01871 UNPACK_PUSH(DBL2NUM(tmp));
01872 }
01873 PACK_ITEM_ADJUST();
01874 break;
01875
01876 case 'U':
01877 if (len > send - s) len = send - s;
01878 while (len > 0 && s < send) {
01879 long alen = send - s;
01880 unsigned long l;
01881
01882 l = utf8_to_uv(s, &alen);
01883 s += alen; len--;
01884 UNPACK_PUSH(ULONG2NUM(l));
01885 }
01886 break;
01887
01888 case 'u':
01889 {
01890 VALUE buf = infected_str_new(0, (send - s)*3/4, str);
01891 char *ptr = RSTRING_PTR(buf);
01892 long total = 0;
01893
01894 while (s < send && *s > ' ' && *s < 'a') {
01895 long a,b,c,d;
01896 char hunk[4];
01897
01898 hunk[3] = '\0';
01899 len = (*s++ - ' ') & 077;
01900 total += len;
01901 if (total > RSTRING_LEN(buf)) {
01902 len -= total - RSTRING_LEN(buf);
01903 total = RSTRING_LEN(buf);
01904 }
01905
01906 while (len > 0) {
01907 long mlen = len > 3 ? 3 : len;
01908
01909 if (s < send && *s >= ' ')
01910 a = (*s++ - ' ') & 077;
01911 else
01912 a = 0;
01913 if (s < send && *s >= ' ')
01914 b = (*s++ - ' ') & 077;
01915 else
01916 b = 0;
01917 if (s < send && *s >= ' ')
01918 c = (*s++ - ' ') & 077;
01919 else
01920 c = 0;
01921 if (s < send && *s >= ' ')
01922 d = (*s++ - ' ') & 077;
01923 else
01924 d = 0;
01925 hunk[0] = (char)(a << 2 | b >> 4);
01926 hunk[1] = (char)(b << 4 | c >> 2);
01927 hunk[2] = (char)(c << 6 | d);
01928 memcpy(ptr, hunk, mlen);
01929 ptr += mlen;
01930 len -= mlen;
01931 }
01932 if (*s == '\r') s++;
01933 if (*s == '\n') s++;
01934 else if (s < send && (s+1 == send || s[1] == '\n'))
01935 s += 2;
01936 }
01937
01938 rb_str_set_len(buf, total);
01939 UNPACK_PUSH(buf);
01940 }
01941 break;
01942
01943 case 'm':
01944 {
01945 VALUE buf = infected_str_new(0, (send - s)*3/4, str);
01946 char *ptr = RSTRING_PTR(buf);
01947 int a = -1,b = -1,c = 0,d = 0;
01948 static signed char b64_xtable[256];
01949
01950 if (b64_xtable['/'] <= 0) {
01951 int i;
01952
01953 for (i = 0; i < 256; i++) {
01954 b64_xtable[i] = -1;
01955 }
01956 for (i = 0; i < 64; i++) {
01957 b64_xtable[(unsigned char)b64_table[i]] = (char)i;
01958 }
01959 }
01960 if (len == 0) {
01961 while (s < send) {
01962 a = b = c = d = -1;
01963 a = b64_xtable[(unsigned char)*s++];
01964 if (s >= send || a == -1) rb_raise(rb_eArgError, "invalid base64");
01965 b = b64_xtable[(unsigned char)*s++];
01966 if (s >= send || b == -1) rb_raise(rb_eArgError, "invalid base64");
01967 if (*s == '=') {
01968 if (s + 2 == send && *(s + 1) == '=') break;
01969 rb_raise(rb_eArgError, "invalid base64");
01970 }
01971 c = b64_xtable[(unsigned char)*s++];
01972 if (s >= send || c == -1) rb_raise(rb_eArgError, "invalid base64");
01973 if (s + 1 == send && *s == '=') break;
01974 d = b64_xtable[(unsigned char)*s++];
01975 if (d == -1) rb_raise(rb_eArgError, "invalid base64");
01976 *ptr++ = castchar(a << 2 | b >> 4);
01977 *ptr++ = castchar(b << 4 | c >> 2);
01978 *ptr++ = castchar(c << 6 | d);
01979 }
01980 if (c == -1) {
01981 *ptr++ = castchar(a << 2 | b >> 4);
01982 if (b & 0xf) rb_raise(rb_eArgError, "invalid base64");
01983 }
01984 else if (d == -1) {
01985 *ptr++ = castchar(a << 2 | b >> 4);
01986 *ptr++ = castchar(b << 4 | c >> 2);
01987 if (c & 0x3) rb_raise(rb_eArgError, "invalid base64");
01988 }
01989 }
01990 else {
01991 while (s < send) {
01992 a = b = c = d = -1;
01993 while ((a = b64_xtable[(unsigned char)*s]) == -1 && s < send) {s++;}
01994 if (s >= send) break;
01995 s++;
01996 while ((b = b64_xtable[(unsigned char)*s]) == -1 && s < send) {s++;}
01997 if (s >= send) break;
01998 s++;
01999 while ((c = b64_xtable[(unsigned char)*s]) == -1 && s < send) {if (*s == '=') break; s++;}
02000 if (*s == '=' || s >= send) break;
02001 s++;
02002 while ((d = b64_xtable[(unsigned char)*s]) == -1 && s < send) {if (*s == '=') break; s++;}
02003 if (*s == '=' || s >= send) break;
02004 s++;
02005 *ptr++ = castchar(a << 2 | b >> 4);
02006 *ptr++ = castchar(b << 4 | c >> 2);
02007 *ptr++ = castchar(c << 6 | d);
02008 }
02009 if (a != -1 && b != -1) {
02010 if (c == -1 && *s == '=')
02011 *ptr++ = castchar(a << 2 | b >> 4);
02012 else if (c != -1 && *s == '=') {
02013 *ptr++ = castchar(a << 2 | b >> 4);
02014 *ptr++ = castchar(b << 4 | c >> 2);
02015 }
02016 }
02017 }
02018 rb_str_set_len(buf, ptr - RSTRING_PTR(buf));
02019 UNPACK_PUSH(buf);
02020 }
02021 break;
02022
02023 case 'M':
02024 {
02025 VALUE buf = infected_str_new(0, send - s, str);
02026 char *ptr = RSTRING_PTR(buf), *ss = s;
02027 int c1, c2;
02028
02029 while (s < send) {
02030 if (*s == '=') {
02031 if (++s == send) break;
02032 if (s+1 < send && *s == '\r' && *(s+1) == '\n')
02033 s++;
02034 if (*s != '\n') {
02035 if ((c1 = hex2num(*s)) == -1) break;
02036 if (++s == send) break;
02037 if ((c2 = hex2num(*s)) == -1) break;
02038 *ptr++ = castchar(c1 << 4 | c2);
02039 }
02040 }
02041 else {
02042 *ptr++ = *s;
02043 }
02044 s++;
02045 ss = s;
02046 }
02047 rb_str_set_len(buf, ptr - RSTRING_PTR(buf));
02048 rb_str_buf_cat(buf, ss, send-ss);
02049 ENCODING_CODERANGE_SET(buf, rb_ascii8bit_encindex(), ENC_CODERANGE_VALID);
02050 UNPACK_PUSH(buf);
02051 }
02052 break;
02053
02054 case '@':
02055 if (len > RSTRING_LEN(str))
02056 rb_raise(rb_eArgError, "@ outside of string");
02057 s = RSTRING_PTR(str) + len;
02058 break;
02059
02060 case 'X':
02061 if (len > s - RSTRING_PTR(str))
02062 rb_raise(rb_eArgError, "X outside of string");
02063 s -= len;
02064 break;
02065
02066 case 'x':
02067 if (len > send - s)
02068 rb_raise(rb_eArgError, "x outside of string");
02069 s += len;
02070 break;
02071
02072 case 'P':
02073 if (sizeof(char *) <= (size_t)(send - s)) {
02074 VALUE tmp = Qnil;
02075 char *t;
02076
02077 memcpy(&t, s, sizeof(char *));
02078 s += sizeof(char *);
02079
02080 if (t) {
02081 VALUE a, *p, *pend;
02082
02083 if (!(a = str_associated(str))) {
02084 rb_raise(rb_eArgError, "no associated pointer");
02085 }
02086 p = RARRAY_PTR(a);
02087 pend = p + RARRAY_LEN(a);
02088 while (p < pend) {
02089 if (RB_TYPE_P(*p, T_STRING) && RSTRING_PTR(*p) == t) {
02090 if (len < RSTRING_LEN(*p)) {
02091 tmp = rb_tainted_str_new(t, len);
02092 str_associate(tmp, a);
02093 }
02094 else {
02095 tmp = *p;
02096 }
02097 break;
02098 }
02099 p++;
02100 }
02101 if (p == pend) {
02102 rb_raise(rb_eArgError, "non associated pointer");
02103 }
02104 }
02105 UNPACK_PUSH(tmp);
02106 }
02107 break;
02108
02109 case 'p':
02110 if (len > (long)((send - s) / sizeof(char *)))
02111 len = (send - s) / sizeof(char *);
02112 while (len-- > 0) {
02113 if ((size_t)(send - s) < sizeof(char *))
02114 break;
02115 else {
02116 VALUE tmp = Qnil;
02117 char *t;
02118
02119 memcpy(&t, s, sizeof(char *));
02120 s += sizeof(char *);
02121
02122 if (t) {
02123 VALUE a, *p, *pend;
02124
02125 if (!(a = str_associated(str))) {
02126 rb_raise(rb_eArgError, "no associated pointer");
02127 }
02128 p = RARRAY_PTR(a);
02129 pend = p + RARRAY_LEN(a);
02130 while (p < pend) {
02131 if (RB_TYPE_P(*p, T_STRING) && RSTRING_PTR(*p) == t) {
02132 tmp = *p;
02133 break;
02134 }
02135 p++;
02136 }
02137 if (p == pend) {
02138 rb_raise(rb_eArgError, "non associated pointer");
02139 }
02140 }
02141 UNPACK_PUSH(tmp);
02142 }
02143 }
02144 break;
02145
02146 case 'w':
02147 {
02148 unsigned long ul = 0;
02149 unsigned long ulmask = 0xfeUL << ((sizeof(unsigned long) - 1) * 8);
02150
02151 while (len > 0 && s < send) {
02152 ul <<= 7;
02153 ul |= (*s & 0x7f);
02154 if (!(*s++ & 0x80)) {
02155 UNPACK_PUSH(ULONG2NUM(ul));
02156 len--;
02157 ul = 0;
02158 }
02159 else if (ul & ulmask) {
02160 VALUE big = rb_uint2big(ul);
02161 VALUE big128 = rb_uint2big(128);
02162 while (s < send) {
02163 big = rb_big_mul(big, big128);
02164 big = rb_big_plus(big, rb_uint2big(*s & 0x7f));
02165 if (!(*s++ & 0x80)) {
02166 UNPACK_PUSH(big);
02167 len--;
02168 ul = 0;
02169 break;
02170 }
02171 }
02172 }
02173 }
02174 }
02175 break;
02176
02177 default:
02178 rb_warning("unknown unpack directive '%c' in '%s'",
02179 type, RSTRING_PTR(fmt));
02180 break;
02181 }
02182 }
02183
02184 return ary;
02185 }
02186
02187 #define BYTEWIDTH 8
02188
02189 int
02190 rb_uv_to_utf8(char buf[6], unsigned long uv)
02191 {
02192 if (uv <= 0x7f) {
02193 buf[0] = (char)uv;
02194 return 1;
02195 }
02196 if (uv <= 0x7ff) {
02197 buf[0] = castchar(((uv>>6)&0xff)|0xc0);
02198 buf[1] = castchar((uv&0x3f)|0x80);
02199 return 2;
02200 }
02201 if (uv <= 0xffff) {
02202 buf[0] = castchar(((uv>>12)&0xff)|0xe0);
02203 buf[1] = castchar(((uv>>6)&0x3f)|0x80);
02204 buf[2] = castchar((uv&0x3f)|0x80);
02205 return 3;
02206 }
02207 if (uv <= 0x1fffff) {
02208 buf[0] = castchar(((uv>>18)&0xff)|0xf0);
02209 buf[1] = castchar(((uv>>12)&0x3f)|0x80);
02210 buf[2] = castchar(((uv>>6)&0x3f)|0x80);
02211 buf[3] = castchar((uv&0x3f)|0x80);
02212 return 4;
02213 }
02214 if (uv <= 0x3ffffff) {
02215 buf[0] = castchar(((uv>>24)&0xff)|0xf8);
02216 buf[1] = castchar(((uv>>18)&0x3f)|0x80);
02217 buf[2] = castchar(((uv>>12)&0x3f)|0x80);
02218 buf[3] = castchar(((uv>>6)&0x3f)|0x80);
02219 buf[4] = castchar((uv&0x3f)|0x80);
02220 return 5;
02221 }
02222 if (uv <= 0x7fffffff) {
02223 buf[0] = castchar(((uv>>30)&0xff)|0xfc);
02224 buf[1] = castchar(((uv>>24)&0x3f)|0x80);
02225 buf[2] = castchar(((uv>>18)&0x3f)|0x80);
02226 buf[3] = castchar(((uv>>12)&0x3f)|0x80);
02227 buf[4] = castchar(((uv>>6)&0x3f)|0x80);
02228 buf[5] = castchar((uv&0x3f)|0x80);
02229 return 6;
02230 }
02231 rb_raise(rb_eRangeError, "pack(U): value out of range");
02232
02233 UNREACHABLE;
02234 }
02235
02236 static const unsigned long utf8_limits[] = {
02237 0x0,
02238 0x80,
02239 0x800,
02240 0x10000,
02241 0x200000,
02242 0x4000000,
02243 0x80000000,
02244 };
02245
02246 static unsigned long
02247 utf8_to_uv(const char *p, long *lenp)
02248 {
02249 int c = *p++ & 0xff;
02250 unsigned long uv = c;
02251 long n;
02252
02253 if (!(uv & 0x80)) {
02254 *lenp = 1;
02255 return uv;
02256 }
02257 if (!(uv & 0x40)) {
02258 *lenp = 1;
02259 rb_raise(rb_eArgError, "malformed UTF-8 character");
02260 }
02261
02262 if (!(uv & 0x20)) { n = 2; uv &= 0x1f; }
02263 else if (!(uv & 0x10)) { n = 3; uv &= 0x0f; }
02264 else if (!(uv & 0x08)) { n = 4; uv &= 0x07; }
02265 else if (!(uv & 0x04)) { n = 5; uv &= 0x03; }
02266 else if (!(uv & 0x02)) { n = 6; uv &= 0x01; }
02267 else {
02268 *lenp = 1;
02269 rb_raise(rb_eArgError, "malformed UTF-8 character");
02270 }
02271 if (n > *lenp) {
02272 rb_raise(rb_eArgError, "malformed UTF-8 character (expected %ld bytes, given %ld bytes)",
02273 n, *lenp);
02274 }
02275 *lenp = n--;
02276 if (n != 0) {
02277 while (n--) {
02278 c = *p++ & 0xff;
02279 if ((c & 0xc0) != 0x80) {
02280 *lenp -= n + 1;
02281 rb_raise(rb_eArgError, "malformed UTF-8 character");
02282 }
02283 else {
02284 c &= 0x3f;
02285 uv = uv << 6 | c;
02286 }
02287 }
02288 }
02289 n = *lenp - 1;
02290 if (uv < utf8_limits[n]) {
02291 rb_raise(rb_eArgError, "redundant UTF-8 sequence");
02292 }
02293 return uv;
02294 }
02295
02296 void
02297 Init_pack(void)
02298 {
02299 rb_define_method(rb_cArray, "pack", pack_pack, 1);
02300 rb_define_method(rb_cString, "unpack", pack_unpack, 1);
02301
02302 id_associated = rb_intern_const("__pack_associated__");
02303 }
02304