00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "ruby.h"
00014 #include <sys/types.h>
00015 #include <ctype.h>
00016
00017 #define SIZE16 2
00018 #define SIZE32 4
00019
00020 #if SIZEOF_SHORT != 2 || SIZEOF_LONG != 4
00021 # define NATINT_PACK
00022 #endif
00023
00024 #ifdef NATINT_PACK
00025 # define OFF16B(p) ((char*)(p) + (natint?0:(sizeof(short) - SIZE16)))
00026 # define OFF32B(p) ((char*)(p) + (natint?0:(sizeof(long) - SIZE32)))
00027 # define NATINT_LEN(type,len) (natint?sizeof(type):(len))
00028 # ifdef WORDS_BIGENDIAN
00029 # define OFF16(p) OFF16B(p)
00030 # define OFF32(p) OFF32B(p)
00031 # endif
00032 # define NATINT_HTOVS(x) (natint?htovs(x):htov16(x))
00033 # define NATINT_HTOVL(x) (natint?htovl(x):htov32(x))
00034 # define NATINT_HTONS(x) (natint?htons(x):hton16(x))
00035 # define NATINT_HTONL(x) (natint?htonl(x):hton32(x))
00036 #else
00037 # define NATINT_LEN(type,len) sizeof(type)
00038 # define NATINT_HTOVS(x) htovs(x)
00039 # define NATINT_HTOVL(x) htovl(x)
00040 # define NATINT_HTONS(x) htons(x)
00041 # define NATINT_HTONL(x) htonl(x)
00042 #endif
00043
00044 #ifndef OFF16
00045 # define OFF16(p) (char*)(p)
00046 # define OFF32(p) (char*)(p)
00047 #endif
00048 #ifndef OFF16B
00049 # define OFF16B(p) (char*)(p)
00050 # define OFF32B(p) (char*)(p)
00051 #endif
00052
00053 #define define_swapx(x, xtype) \
00054 static xtype \
00055 TOKEN_PASTE(swap,x)(z) \
00056 xtype z; \
00057 { \
00058 xtype r; \
00059 xtype *zp; \
00060 unsigned char *s, *t; \
00061 int i; \
00062 \
00063 zp = malloc(sizeof(xtype)); \
00064 *zp = z; \
00065 s = (unsigned char*)zp; \
00066 t = malloc(sizeof(xtype)); \
00067 for (i=0; i<sizeof(xtype); i++) { \
00068 t[sizeof(xtype)-i-1] = s[i]; \
00069 } \
00070 r = *(xtype *)t; \
00071 free(t); \
00072 free(zp); \
00073 return r; \
00074 }
00075
00076 #ifndef swap16
00077 #define swap16(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
00078 #endif
00079 #if SIZEOF_SHORT == 2
00080 #define swaps(x) swap16(x)
00081 #else
00082 #if SIZEOF_SHORT == 4
00083 #define swaps(x) ((((x)&0xFF)<<24) \
00084 |(((x)>>24)&0xFF) \
00085 |(((x)&0x0000FF00)<<8) \
00086 |(((x)&0x00FF0000)>>8) )
00087 #else
00088 define_swapx(s,short)
00089 #endif
00090 #endif
00091
00092 #ifndef swap32
00093 #define swap32(x) ((((x)&0xFF)<<24) \
00094 |(((x)>>24)&0xFF) \
00095 |(((x)&0x0000FF00)<<8) \
00096 |(((x)&0x00FF0000)>>8) )
00097 #endif
00098 #if SIZEOF_LONG == 4
00099 #define swapl(x) swap32(x)
00100 #else
00101 #if SIZEOF_LONG == 8
00102 #define swapl(x) ((((x)&0x00000000000000FF)<<56) \
00103 |(((x)&0xFF00000000000000)>>56) \
00104 |(((x)&0x000000000000FF00)<<40) \
00105 |(((x)&0x00FF000000000000)>>40) \
00106 |(((x)&0x0000000000FF0000)<<24) \
00107 |(((x)&0x0000FF0000000000)>>24) \
00108 |(((x)&0x00000000FF000000)<<8) \
00109 |(((x)&0x000000FF00000000)>>8))
00110 #else
00111 define_swapx(l,long)
00112 #endif
00113 #endif
00114
00115 #if SIZEOF_FLOAT == 4
00116 #if SIZEOF_LONG == 4
00117 #define swapf(x) swapl(x)
00118 #define FLOAT_SWAPPER unsigned long
00119 #else
00120 #if SIZEOF_SHORT == 4
00121 #define swapf(x) swaps(x)
00122 #define FLOAT_SWAPPER unsigned short
00123 #else
00124 define_swapx(f,float)
00125 #endif
00126 #endif
00127 #else
00128 define_swapx(f,float)
00129 #endif
00130
00131 #if SIZEOF_DOUBLE == 8
00132 #if SIZEOF_LONG == 8
00133 #define swapd(x) swapl(x)
00134 #define DOUBLE_SWAPPER unsigned long
00135 #else
00136 #if SIZEOF_LONG == 4
00137 static double
00138 swapd(d)
00139 const double d;
00140 {
00141 double dtmp = d;
00142 unsigned long utmp[2];
00143 unsigned long utmp0;
00144
00145 utmp[0] = 0; utmp[1] = 0;
00146 memcpy(utmp,&dtmp,sizeof(double));
00147 utmp0 = utmp[0];
00148 utmp[0] = swapl(utmp[1]);
00149 utmp[1] = swapl(utmp0);
00150 memcpy(&dtmp,utmp,sizeof(double));
00151 return dtmp;
00152 }
00153 #else
00154 #if SIZEOF_SHORT == 4
00155 static double
00156 swapd(d)
00157 const double d;
00158 {
00159 double dtmp = d;
00160 unsigned short utmp[2];
00161 unsigned short utmp0;
00162
00163 utmp[0] = 0; utmp[1] = 0;
00164 memcpy(utmp,&dtmp,sizeof(double));
00165 utmp0 = utmp[0];
00166 utmp[0] = swaps(utmp[1]);
00167 utmp[1] = swaps(utmp0);
00168 memcpy(&dtmp,utmp,sizeof(double));
00169 return dtmp;
00170 }
00171 #else
00172 define_swapx(d, double)
00173 #endif
00174 #endif
00175 #endif
00176 #else
00177 define_swapx(d, double)
00178 #endif
00179
00180 #undef define_swapx
00181
00182 #ifdef DYNAMIC_ENDIAN
00183 #ifdef ntohs
00184 #undef ntohs
00185 #undef ntohl
00186 #undef htons
00187 #undef htonl
00188 #endif
00189 static int
00190 endian()
00191 {
00192 static int init = 0;
00193 static int endian_value;
00194 char *p;
00195
00196 if (init) return endian_value;
00197 init = 1;
00198 p = (char*)&init;
00199 return endian_value = p[0]?0:1;
00200 }
00201
00202 #define ntohs(x) (endian()?(x):swaps(x))
00203 #define ntohl(x) (endian()?(x):swapl(x))
00204 #define ntohf(x) (endian()?(x):swapf(x))
00205 #define ntohd(x) (endian()?(x):swapd(x))
00206 #define htons(x) (endian()?(x):swaps(x))
00207 #define htonl(x) (endian()?(x):swapl(x))
00208 #define htonf(x) (endian()?(x):swapf(x))
00209 #define htond(x) (endian()?(x):swapd(x))
00210 #define htovs(x) (endian()?swaps(x):(x))
00211 #define htovl(x) (endian()?swapl(x):(x))
00212 #define htovf(x) (endian()?swapf(x):(x))
00213 #define htovd(x) (endian()?swapd(x):(x))
00214 #define vtohs(x) (endian()?swaps(x):(x))
00215 #define vtohl(x) (endian()?swapl(x):(x))
00216 #define vtohf(x) (endian()?swapf(x):(x))
00217 #define vtohd(x) (endian()?swapd(x):(x))
00218 # ifdef NATINT_PACK
00219 #define htov16(x) (endian()?swap16(x):(x))
00220 #define htov32(x) (endian()?swap32(x):(x))
00221 #define hton16(x) (endian()?(x):swap16(x))
00222 #define hton32(x) (endian()?(x):swap32(x))
00223 # endif
00224 #else
00225 #ifdef WORDS_BIGENDIAN
00226 #ifndef ntohs
00227 #define ntohs(x) (x)
00228 #define ntohl(x) (x)
00229 #define htons(x) (x)
00230 #define htonl(x) (x)
00231 #endif
00232 #define ntohf(x) (x)
00233 #define ntohd(x) (x)
00234 #define htonf(x) (x)
00235 #define htond(x) (x)
00236 #define htovs(x) swaps(x)
00237 #define htovl(x) swapl(x)
00238 #define htovf(x) swapf(x)
00239 #define htovd(x) swapd(x)
00240 #define vtohs(x) swaps(x)
00241 #define vtohl(x) swapl(x)
00242 #define vtohf(x) swapf(x)
00243 #define vtohd(x) swapd(x)
00244 # ifdef NATINT_PACK
00245 #define htov16(x) swap16(x)
00246 #define htov32(x) swap32(x)
00247 #define hton16(x) (x)
00248 #define hton32(x) (x)
00249 # endif
00250 #else
00251 #ifdef ntohs
00252 #undef ntohs
00253 #undef ntohl
00254 #undef htons
00255 #undef htonl
00256 #endif
00257 #define ntohs(x) swaps(x)
00258 #define ntohl(x) swapl(x)
00259 #define htons(x) swaps(x)
00260 #define htonl(x) swapl(x)
00261 #define ntohf(x) swapf(x)
00262 #define ntohd(x) swapd(x)
00263 #define htonf(x) swapf(x)
00264 #define htond(x) swapd(x)
00265 #define htovs(x) (x)
00266 #define htovl(x) (x)
00267 #define htovf(x) (x)
00268 #define htovd(x) (x)
00269 #define vtohs(x) (x)
00270 #define vtohl(x) (x)
00271 #define vtohf(x) (x)
00272 #define vtohd(x) (x)
00273 # ifdef NATINT_PACK
00274 #define htov16(x) (x)
00275 #define htov32(x) (x)
00276 #define hton16(x) swap16(x)
00277 #define hton32(x) swap32(x)
00278 # endif
00279 #endif
00280 #endif
00281
00282 #ifdef FLOAT_SWAPPER
00283 #define FLOAT_CONVWITH(y) FLOAT_SWAPPER y;
00284 #define HTONF(x,y) (memcpy(&y,&x,sizeof(float)), \
00285 y = htonf((FLOAT_SWAPPER)y), \
00286 memcpy(&x,&y,sizeof(float)), \
00287 x)
00288 #define HTOVF(x,y) (memcpy(&y,&x,sizeof(float)), \
00289 y = htovf((FLOAT_SWAPPER)y), \
00290 memcpy(&x,&y,sizeof(float)), \
00291 x)
00292 #define NTOHF(x,y) (memcpy(&y,&x,sizeof(float)), \
00293 y = ntohf((FLOAT_SWAPPER)y), \
00294 memcpy(&x,&y,sizeof(float)), \
00295 x)
00296 #define VTOHF(x,y) (memcpy(&y,&x,sizeof(float)), \
00297 y = vtohf((FLOAT_SWAPPER)y), \
00298 memcpy(&x,&y,sizeof(float)), \
00299 x)
00300 #else
00301 #define FLOAT_CONVWITH(y)
00302 #define HTONF(x,y) htonf(x)
00303 #define HTOVF(x,y) htovf(x)
00304 #define NTOHF(x,y) ntohf(x)
00305 #define VTOHF(x,y) vtohf(x)
00306 #endif
00307
00308 #ifdef DOUBLE_SWAPPER
00309 #define DOUBLE_CONVWITH(y) DOUBLE_SWAPPER y;
00310 #define HTOND(x,y) (memcpy(&y,&x,sizeof(double)), \
00311 y = htond((DOUBLE_SWAPPER)y), \
00312 memcpy(&x,&y,sizeof(double)), \
00313 x)
00314 #define HTOVD(x,y) (memcpy(&y,&x,sizeof(double)), \
00315 y = htovd((DOUBLE_SWAPPER)y), \
00316 memcpy(&x,&y,sizeof(double)), \
00317 x)
00318 #define NTOHD(x,y) (memcpy(&y,&x,sizeof(double)), \
00319 y = ntohd((DOUBLE_SWAPPER)y), \
00320 memcpy(&x,&y,sizeof(double)), \
00321 x)
00322 #define VTOHD(x,y) (memcpy(&y,&x,sizeof(double)), \
00323 y = vtohd((DOUBLE_SWAPPER)y), \
00324 memcpy(&x,&y,sizeof(double)), \
00325 x)
00326 #else
00327 #define DOUBLE_CONVWITH(y)
00328 #define HTOND(x,y) htond(x)
00329 #define HTOVD(x,y) htovd(x)
00330 #define NTOHD(x,y) ntohd(x)
00331 #define VTOHD(x,y) vtohd(x)
00332 #endif
00333
00334 unsigned long rb_big2ulong_pack (VALUE x);
00335
00336 static unsigned long
00337 num2i32(x)
00338 VALUE x;
00339 {
00340 x = rb_to_int(x);
00341
00342 if (FIXNUM_P(x)) return FIX2LONG(x);
00343 if (TYPE(x) == T_BIGNUM) {
00344 return rb_big2ulong_pack(x);
00345 }
00346 rb_raise(rb_eTypeError, "can't convert %s to `integer'", rb_obj_classname(x));
00347 return 0;
00348 }
00349
00350 #if SIZEOF_LONG == SIZE32 || SIZEOF_INT == SIZE32
00351 # define EXTEND32(x)
00352 #else
00353
00354 # define EXTEND32(x) do {if (!natint) {(x) = (I32)(((1<<31)-1-(x))^~(~0<<31));}} while(0)
00355 #endif
00356 #if SIZEOF_SHORT == SIZE16
00357 # define EXTEND16(x)
00358 #else
00359 # define EXTEND16(x) do { if (!natint) {(x) = (short)(((1<<15)-1-(x))^~(~0<<15));}} while(0)
00360 #endif
00361
00362 #ifdef HAVE_LONG_LONG
00363 # define QUAD_SIZE sizeof(LONG_LONG)
00364 #else
00365 # define QUAD_SIZE 8
00366 #endif
00367 static char *toofew = "too few arguments";
00368
00369 static void encodes (VALUE,char*,long,int);
00370 static void qpencode (VALUE,VALUE,long);
00371
00372 static int uv_to_utf8 (char*,unsigned long);
00373 static unsigned long utf8_to_uv (char*,long*);
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440 static VALUE
00441 pack_pack(ary, fmt)
00442 VALUE ary, fmt;
00443 {
00444 static char *nul10 = "\0\0\0\0\0\0\0\0\0\0";
00445 static char *spc10 = " ";
00446 char *p, *pend;
00447 VALUE res, from, associates = 0;
00448 char type;
00449 long items, len, idx, plen;
00450 char *ptr;
00451 #ifdef NATINT_PACK
00452 int natint;
00453 #endif
00454
00455 StringValue(fmt);
00456 p = RSTRING(fmt)->ptr;
00457 pend = p + RSTRING(fmt)->len;
00458 res = rb_str_buf_new(0);
00459
00460 items = RARRAY(ary)->len;
00461 idx = 0;
00462
00463 #define THISFROM RARRAY(ary)->ptr[idx]
00464 #define NEXTFROM (items-- > 0 ? RARRAY(ary)->ptr[idx++] : (rb_raise(rb_eArgError, toofew),0))
00465
00466 while (p < pend) {
00467 if (RSTRING(fmt)->ptr + RSTRING(fmt)->len != pend) {
00468 rb_raise(rb_eRuntimeError, "format string modified");
00469 }
00470 type = *p++;
00471 #ifdef NATINT_PACK
00472 natint = 0;
00473 #endif
00474
00475 if (ISSPACE(type)) continue;
00476 if (type == '#') {
00477 while ((p < pend) && (*p != '\n')) {
00478 p++;
00479 }
00480 continue;
00481 }
00482 if (*p == '_' || *p == '!') {
00483 const char *natstr = "sSiIlL";
00484
00485 if (strchr(natstr, type)) {
00486 #ifdef NATINT_PACK
00487 natint = 1;
00488 #endif
00489 p++;
00490 }
00491 else {
00492 rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, natstr);
00493 }
00494 }
00495 if (*p == '*') {
00496 len = strchr("@Xxu", type) ? 0 : items;
00497 p++;
00498 }
00499 else if (ISDIGIT(*p)) {
00500 len = strtoul(p, (char**)&p, 10);
00501 }
00502 else {
00503 len = 1;
00504 }
00505
00506 switch (type) {
00507 case 'A': case 'a': case 'Z':
00508 case 'B': case 'b':
00509 case 'H': case 'h':
00510 from = NEXTFROM;
00511 if (NIL_P(from)) {
00512 ptr = "";
00513 plen = 0;
00514 }
00515 else {
00516 StringValue(from);
00517 ptr = RSTRING(from)->ptr;
00518 plen = RSTRING(from)->len;
00519 OBJ_INFECT(res, from);
00520 }
00521
00522 if (p[-1] == '*')
00523 len = plen;
00524
00525 switch (type) {
00526 case 'a':
00527 case 'A':
00528 case 'Z':
00529 if (plen >= len) {
00530 rb_str_buf_cat(res, ptr, len);
00531 if (p[-1] == '*' && type == 'Z')
00532 rb_str_buf_cat(res, nul10, 1);
00533 }
00534 else {
00535 rb_str_buf_cat(res, ptr, plen);
00536 len -= plen;
00537 while (len >= 10) {
00538 rb_str_buf_cat(res, (type == 'A')?spc10:nul10, 10);
00539 len -= 10;
00540 }
00541 rb_str_buf_cat(res, (type == 'A')?spc10:nul10, len);
00542 }
00543 break;
00544
00545 case 'b':
00546 {
00547 int byte = 0;
00548 long i, j = 0;
00549
00550 if (len > plen) {
00551 j = (len - plen + 1)/2;
00552 len = plen;
00553 }
00554 for (i=0; i++ < len; ptr++) {
00555 if (*ptr & 1)
00556 byte |= 128;
00557 if (i & 7)
00558 byte >>= 1;
00559 else {
00560 char c = byte & 0xff;
00561 rb_str_buf_cat(res, &c, 1);
00562 byte = 0;
00563 }
00564 }
00565 if (len & 7) {
00566 char c;
00567 byte >>= 7 - (len & 7);
00568 c = byte & 0xff;
00569 rb_str_buf_cat(res, &c, 1);
00570 }
00571 len = j;
00572 goto grow;
00573 }
00574 break;
00575
00576 case 'B':
00577 {
00578 int byte = 0;
00579 long i, j = 0;
00580
00581 if (len > plen) {
00582 j = (len - plen + 1)/2;
00583 len = plen;
00584 }
00585 for (i=0; i++ < len; ptr++) {
00586 byte |= *ptr & 1;
00587 if (i & 7)
00588 byte <<= 1;
00589 else {
00590 char c = byte & 0xff;
00591 rb_str_buf_cat(res, &c, 1);
00592 byte = 0;
00593 }
00594 }
00595 if (len & 7) {
00596 char c;
00597 byte <<= 7 - (len & 7);
00598 c = byte & 0xff;
00599 rb_str_buf_cat(res, &c, 1);
00600 }
00601 len = j;
00602 goto grow;
00603 }
00604 break;
00605
00606 case 'h':
00607 {
00608 int byte = 0;
00609 long i, j = 0;
00610
00611 if (len > plen) {
00612 j = (len - plen + 1)/2;
00613 len = plen;
00614 }
00615 for (i=0; i++ < len; ptr++) {
00616 if (ISALPHA(*ptr))
00617 byte |= (((*ptr & 15) + 9) & 15) << 4;
00618 else
00619 byte |= (*ptr & 15) << 4;
00620 if (i & 1)
00621 byte >>= 4;
00622 else {
00623 char c = byte & 0xff;
00624 rb_str_buf_cat(res, &c, 1);
00625 byte = 0;
00626 }
00627 }
00628 if (len & 1) {
00629 char c = byte & 0xff;
00630 rb_str_buf_cat(res, &c, 1);
00631 }
00632 len = j;
00633 goto grow;
00634 }
00635 break;
00636
00637 case 'H':
00638 {
00639 int byte = 0;
00640 long i, j = 0;
00641
00642 if (len > plen) {
00643 j = (len - plen + 1)/2;
00644 len = plen;
00645 }
00646 for (i=0; i++ < len; ptr++) {
00647 if (ISALPHA(*ptr))
00648 byte |= ((*ptr & 15) + 9) & 15;
00649 else
00650 byte |= *ptr & 15;
00651 if (i & 1)
00652 byte <<= 4;
00653 else {
00654 char c = byte & 0xff;
00655 rb_str_buf_cat(res, &c, 1);
00656 byte = 0;
00657 }
00658 }
00659 if (len & 1) {
00660 char c = byte & 0xff;
00661 rb_str_buf_cat(res, &c, 1);
00662 }
00663 len = j;
00664 goto grow;
00665 }
00666 break;
00667 }
00668 break;
00669
00670 case 'c':
00671 case 'C':
00672 while (len-- > 0) {
00673 char c;
00674
00675 from = NEXTFROM;
00676 c = num2i32(from);
00677 rb_str_buf_cat(res, &c, sizeof(char));
00678 }
00679 break;
00680
00681 case 's':
00682 case 'S':
00683 while (len-- > 0) {
00684 short s;
00685
00686 from = NEXTFROM;
00687 s = num2i32(from);
00688 rb_str_buf_cat(res, OFF16(&s), NATINT_LEN(short,2));
00689 }
00690 break;
00691
00692 case 'i':
00693 case 'I':
00694 while (len-- > 0) {
00695 long i;
00696
00697 from = NEXTFROM;
00698 i = num2i32(from);
00699 rb_str_buf_cat(res, OFF32(&i), NATINT_LEN(int,4));
00700 }
00701 break;
00702
00703 case 'l':
00704 case 'L':
00705 while (len-- > 0) {
00706 long l;
00707
00708 from = NEXTFROM;
00709 l = num2i32(from);
00710 rb_str_buf_cat(res, OFF32(&l), NATINT_LEN(long,4));
00711 }
00712 break;
00713
00714 case 'q':
00715 case 'Q':
00716 while (len-- > 0) {
00717 char tmp[QUAD_SIZE];
00718
00719 from = NEXTFROM;
00720 rb_quad_pack(tmp, from);
00721 rb_str_buf_cat(res, (char*)&tmp, QUAD_SIZE);
00722 }
00723 break;
00724
00725 case 'n':
00726 while (len-- > 0) {
00727 unsigned short s;
00728
00729 from = NEXTFROM;
00730 s = num2i32(from);
00731 s = NATINT_HTONS(s);
00732 rb_str_buf_cat(res, OFF16(&s), NATINT_LEN(short,2));
00733 }
00734 break;
00735
00736 case 'N':
00737 while (len-- > 0) {
00738 unsigned long l;
00739
00740 from = NEXTFROM;
00741 l = num2i32(from);
00742 l = NATINT_HTONL(l);
00743 rb_str_buf_cat(res, OFF32(&l), NATINT_LEN(long,4));
00744 }
00745 break;
00746
00747 case 'v':
00748 while (len-- > 0) {
00749 unsigned short s;
00750
00751 from = NEXTFROM;
00752 s = num2i32(from);
00753 s = NATINT_HTOVS(s);
00754 rb_str_buf_cat(res, OFF16(&s), NATINT_LEN(short,2));
00755 }
00756 break;
00757
00758 case 'V':
00759 while (len-- > 0) {
00760 unsigned long l;
00761
00762 from = NEXTFROM;
00763 l = num2i32(from);
00764 l = NATINT_HTOVL(l);
00765 rb_str_buf_cat(res, OFF32(&l), NATINT_LEN(long,4));
00766 }
00767 break;
00768
00769 case 'f':
00770 case 'F':
00771 while (len-- > 0) {
00772 float f;
00773
00774 from = NEXTFROM;
00775 f = RFLOAT(rb_Float(from))->value;
00776 rb_str_buf_cat(res, (char*)&f, sizeof(float));
00777 }
00778 break;
00779
00780 case 'e':
00781 while (len-- > 0) {
00782 float f;
00783 FLOAT_CONVWITH(ftmp);
00784
00785 from = NEXTFROM;
00786 f = RFLOAT(rb_Float(from))->value;
00787 f = HTOVF(f,ftmp);
00788 rb_str_buf_cat(res, (char*)&f, sizeof(float));
00789 }
00790 break;
00791
00792 case 'E':
00793 while (len-- > 0) {
00794 double d;
00795 DOUBLE_CONVWITH(dtmp);
00796
00797 from = NEXTFROM;
00798 d = RFLOAT(rb_Float(from))->value;
00799 d = HTOVD(d,dtmp);
00800 rb_str_buf_cat(res, (char*)&d, sizeof(double));
00801 }
00802 break;
00803
00804 case 'd':
00805 case 'D':
00806 while (len-- > 0) {
00807 double d;
00808
00809 from = NEXTFROM;
00810 d = RFLOAT(rb_Float(from))->value;
00811 rb_str_buf_cat(res, (char*)&d, sizeof(double));
00812 }
00813 break;
00814
00815 case 'g':
00816 while (len-- > 0) {
00817 float f;
00818 FLOAT_CONVWITH(ftmp);
00819
00820 from = NEXTFROM;
00821 f = RFLOAT(rb_Float(from))->value;
00822 f = HTONF(f,ftmp);
00823 rb_str_buf_cat(res, (char*)&f, sizeof(float));
00824 }
00825 break;
00826
00827 case 'G':
00828 while (len-- > 0) {
00829 double d;
00830 DOUBLE_CONVWITH(dtmp);
00831
00832 from = NEXTFROM;
00833 d = RFLOAT(rb_Float(from))->value;
00834 d = HTOND(d,dtmp);
00835 rb_str_buf_cat(res, (char*)&d, sizeof(double));
00836 }
00837 break;
00838
00839 case 'x':
00840 grow:
00841 while (len >= 10) {
00842 rb_str_buf_cat(res, nul10, 10);
00843 len -= 10;
00844 }
00845 rb_str_buf_cat(res, nul10, len);
00846 break;
00847
00848 case 'X':
00849 shrink:
00850 plen = RSTRING(res)->len;
00851 if (plen < len)
00852 rb_raise(rb_eArgError, "X outside of string");
00853 RSTRING(res)->len = plen - len;
00854 RSTRING(res)->ptr[plen - len] = '\0';
00855 break;
00856
00857 case '@':
00858 len -= RSTRING(res)->len;
00859 if (len > 0) goto grow;
00860 len = -len;
00861 if (len > 0) goto shrink;
00862 break;
00863
00864 case '%':
00865 rb_raise(rb_eArgError, "%% is not supported");
00866 break;
00867
00868 case 'U':
00869 while (len-- > 0) {
00870 long l;
00871 char buf[8];
00872 int le;
00873
00874 from = NEXTFROM;
00875 from = rb_to_int(from);
00876 l = NUM2INT(from);
00877 if (l < 0) {
00878 rb_raise(rb_eRangeError, "pack(U): value out of range");
00879 }
00880 le = uv_to_utf8(buf, l);
00881 rb_str_buf_cat(res, (char*)buf, le);
00882 }
00883 break;
00884
00885 case 'u':
00886 case 'm':
00887 from = NEXTFROM;
00888 StringValue(from);
00889 ptr = RSTRING(from)->ptr;
00890 plen = RSTRING(from)->len;
00891
00892 if (len <= 2)
00893 len = 45;
00894 else
00895 len = len / 3 * 3;
00896 while (plen > 0) {
00897 long todo;
00898
00899 if (plen > len)
00900 todo = len;
00901 else
00902 todo = plen;
00903 encodes(res, ptr, todo, type);
00904 plen -= todo;
00905 ptr += todo;
00906 }
00907 break;
00908
00909 case 'M':
00910 from = rb_obj_as_string(NEXTFROM);
00911 if (len <= 1)
00912 len = 72;
00913 qpencode(res, from, len);
00914 break;
00915
00916 case 'P':
00917 from = THISFROM;
00918 if (!NIL_P(from)) {
00919 StringValue(from);
00920 if (RSTRING(from)->len < len) {
00921 rb_raise(rb_eArgError, "too short buffer for P(%ld for %ld)",
00922 RSTRING(from)->len, len);
00923 }
00924 }
00925 len = 1;
00926
00927 case 'p':
00928 while (len-- > 0) {
00929 char *t;
00930 from = NEXTFROM;
00931 if (NIL_P(from)) {
00932 t = 0;
00933 }
00934 else {
00935 t = StringValuePtr(from);
00936 }
00937 if (!associates) {
00938 associates = rb_ary_new();
00939 }
00940 rb_ary_push(associates, from);
00941 rb_str_buf_cat(res, (char*)&t, sizeof(char*));
00942 }
00943 break;
00944
00945 case 'w':
00946 while (len-- > 0) {
00947 unsigned long ul;
00948 VALUE buf = rb_str_new(0, 0);
00949 char c, *bufs, *bufe;
00950
00951 from = NEXTFROM;
00952 if (TYPE(from) == T_BIGNUM) {
00953 VALUE big128 = rb_uint2big(128);
00954 while (TYPE(from) == T_BIGNUM) {
00955 from = rb_big_divmod(from, big128);
00956 c = NUM2INT(RARRAY(from)->ptr[1]) | 0x80;
00957 rb_str_buf_cat(buf, &c, sizeof(char));
00958 from = RARRAY(from)->ptr[0];
00959 }
00960 }
00961
00962 {
00963 long l = NUM2LONG(from);
00964 if (l < 0) {
00965 rb_raise(rb_eArgError, "can't compress negative numbers");
00966 }
00967 ul = l;
00968 }
00969
00970 while (ul) {
00971 c = ((ul & 0x7f) | 0x80);
00972 rb_str_buf_cat(buf, &c, sizeof(char));
00973 ul >>= 7;
00974 }
00975
00976 if (RSTRING(buf)->len) {
00977 bufs = RSTRING(buf)->ptr;
00978 bufe = bufs + RSTRING(buf)->len - 1;
00979 *bufs &= 0x7f;
00980 while (bufs < bufe) {
00981 c = *bufs;
00982 *bufs++ = *bufe;
00983 *bufe-- = c;
00984 }
00985 rb_str_buf_cat(res, RSTRING(buf)->ptr, RSTRING(buf)->len);
00986 }
00987 else {
00988 c = 0;
00989 rb_str_buf_cat(res, &c, sizeof(char));
00990 }
00991 }
00992 break;
00993
00994 default:
00995 break;
00996 }
00997 }
00998
00999 if (associates) {
01000 rb_str_associate(res, associates);
01001 }
01002 return res;
01003 }
01004
01005 static char uu_table[] =
01006 "`!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_";
01007 static char b64_table[] =
01008 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
01009
01010 static void
01011 encodes(str, s, len, type)
01012 VALUE str;
01013 char *s;
01014 long len;
01015 int type;
01016 {
01017 char *buff = ALLOCA_N(char, len * 4 / 3 + 6);
01018 long i = 0;
01019 char *trans = type == 'u' ? uu_table : b64_table;
01020 int padding;
01021
01022 if (type == 'u') {
01023 buff[i++] = len + ' ';
01024 padding = '`';
01025 }
01026 else {
01027 padding = '=';
01028 }
01029 while (len >= 3) {
01030 buff[i++] = trans[077 & (*s >> 2)];
01031 buff[i++] = trans[077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017))];
01032 buff[i++] = trans[077 & (((s[1] << 2) & 074) | ((s[2] >> 6) & 03))];
01033 buff[i++] = trans[077 & s[2]];
01034 s += 3;
01035 len -= 3;
01036 }
01037 if (len == 2) {
01038 buff[i++] = trans[077 & (*s >> 2)];
01039 buff[i++] = trans[077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017))];
01040 buff[i++] = trans[077 & (((s[1] << 2) & 074) | (('\0' >> 6) & 03))];
01041 buff[i++] = padding;
01042 }
01043 else if (len == 1) {
01044 buff[i++] = trans[077 & (*s >> 2)];
01045 buff[i++] = trans[077 & (((*s << 4) & 060) | (('\0' >> 4) & 017))];
01046 buff[i++] = padding;
01047 buff[i++] = padding;
01048 }
01049 buff[i++] = '\n';
01050 rb_str_buf_cat(str, buff, i);
01051 }
01052
01053 static char hex_table[] = "0123456789ABCDEF";
01054
01055 static void
01056 qpencode(str, from, len)
01057 VALUE str, from;
01058 long len;
01059 {
01060 char buff[1024];
01061 long i = 0, n = 0, prev = EOF;
01062 unsigned char *s = (unsigned char*)RSTRING(from)->ptr;
01063 unsigned char *send = s + RSTRING(from)->len;
01064
01065 while (s < send) {
01066 if ((*s > 126) ||
01067 (*s < 32 && *s != '\n' && *s != '\t') ||
01068 (*s == '=')) {
01069 buff[i++] = '=';
01070 buff[i++] = hex_table[*s >> 4];
01071 buff[i++] = hex_table[*s & 0x0f];
01072 n += 3;
01073 prev = EOF;
01074 }
01075 else if (*s == '\n') {
01076 if (prev == ' ' || prev == '\t') {
01077 buff[i++] = '=';
01078 buff[i++] = *s;
01079 }
01080 buff[i++] = *s;
01081 n = 0;
01082 prev = *s;
01083 }
01084 else {
01085 buff[i++] = *s;
01086 n++;
01087 prev = *s;
01088 }
01089 if (n > len) {
01090 buff[i++] = '=';
01091 buff[i++] = '\n';
01092 n = 0;
01093 prev = '\n';
01094 }
01095 if (i > 1024 - 5) {
01096 rb_str_buf_cat(str, buff, i);
01097 i = 0;
01098 }
01099 s++;
01100 }
01101 if (n > 0) {
01102 buff[i++] = '=';
01103 buff[i++] = '\n';
01104 }
01105 if (i > 0) {
01106 rb_str_buf_cat(str, buff, i);
01107 }
01108 }
01109
01110 static inline int
01111 hex2num(c)
01112 char c;
01113 {
01114 switch (c) {
01115 case '0': case '1': case '2': case '3': case '4':
01116 case '5': case '6': case '7': case '8': case '9':
01117 return c - '0';
01118 case 'a': case 'b': case 'c':
01119 case 'd': case 'e': case 'f':
01120 return c - 'a' + 10;
01121 case 'A': case 'B': case 'C':
01122 case 'D': case 'E': case 'F':
01123 return c - 'A' + 10;
01124 default:
01125 return -1;
01126 }
01127 }
01128
01129 #define PACK_LENGTH_ADJUST_SIZE(sz) do { \
01130 tmp = 0; \
01131 if (len > (send-s)/sz) { \
01132 if (!star) { \
01133 tmp = len-(send-s)/sz; \
01134 } \
01135 len = (send-s)/sz; \
01136 } \
01137 } while (0)
01138
01139 #ifdef NATINT_PACK
01140 #define PACK_LENGTH_ADJUST(type,sz) do { \
01141 int t__len = NATINT_LEN(type,(sz)); \
01142 PACK_LENGTH_ADJUST_SIZE(t__len); \
01143 } while (0)
01144 #else
01145 #define PACK_LENGTH_ADJUST(type,sz) \
01146 PACK_LENGTH_ADJUST_SIZE(sizeof(type))
01147 #endif
01148
01149 #define PACK_ITEM_ADJUST() while (tmp--) rb_ary_push(ary, Qnil)
01150
01151 static VALUE
01152 infected_str_new(ptr, len, str)
01153 const char *ptr;
01154 long len;
01155 VALUE str;
01156 {
01157 VALUE s = rb_str_new(ptr, len);
01158
01159 OBJ_INFECT(s, str);
01160 return s;
01161 }
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228
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 static VALUE
01302 pack_unpack(str, fmt)
01303 VALUE str, fmt;
01304 {
01305 static char *hexdigits = "0123456789abcdef0123456789ABCDEFx";
01306 char *s, *send;
01307 char *p, *pend;
01308 VALUE ary;
01309 char type;
01310 long len;
01311 int tmp, star;
01312 #ifdef NATINT_PACK
01313 int natint;
01314 #endif
01315
01316 StringValue(str);
01317 StringValue(fmt);
01318 s = RSTRING(str)->ptr;
01319 send = s + RSTRING(str)->len;
01320 p = RSTRING(fmt)->ptr;
01321 pend = p + RSTRING(fmt)->len;
01322
01323 ary = rb_ary_new();
01324 while (p < pend) {
01325 type = *p++;
01326 #ifdef NATINT_PACK
01327 natint = 0;
01328 #endif
01329
01330 if (ISSPACE(type)) continue;
01331 if (type == '#') {
01332 while ((p < pend) && (*p != '\n')) {
01333 p++;
01334 }
01335 continue;
01336 }
01337 star = 0;
01338 if (*p == '_' || *p == '!') {
01339 char *natstr = "sSiIlL";
01340
01341 if (strchr(natstr, type)) {
01342 #ifdef NATINT_PACK
01343 natint = 1;
01344 #endif
01345 p++;
01346 }
01347 else {
01348 rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, natstr);
01349 }
01350 }
01351 if (p >= pend)
01352 len = 1;
01353 else if (*p == '*') {
01354 star = 1;
01355 len = send - s;
01356 p++;
01357 }
01358 else if (ISDIGIT(*p)) {
01359 len = strtoul(p, (char**)&p, 10);
01360 }
01361 else {
01362 len = (type != '@');
01363 }
01364
01365 switch (type) {
01366 case '%':
01367 rb_raise(rb_eArgError, "%% is not supported");
01368 break;
01369
01370 case 'A':
01371 if (len > send - s) len = send - s;
01372 {
01373 long end = len;
01374 char *t = s + len - 1;
01375
01376 while (t >= s) {
01377 if (*t != ' ' && *t != '\0') break;
01378 t--; len--;
01379 }
01380 rb_ary_push(ary, infected_str_new(s, len, str));
01381 s += end;
01382 }
01383 break;
01384
01385 case 'Z':
01386 {
01387 char *t = s;
01388
01389 if (len > send-s) len = send-s;
01390 while (t < s+len && *t) t++;
01391 rb_ary_push(ary, infected_str_new(s, t-s, str));
01392 if (t < send) t++;
01393 s = star ? t : s+len;
01394 }
01395 break;
01396
01397 case 'a':
01398 if (len > send - s) len = send - s;
01399 rb_ary_push(ary, infected_str_new(s, len, str));
01400 s += len;
01401 break;
01402
01403
01404 case 'b':
01405 {
01406 VALUE bitstr;
01407 char *t;
01408 int bits;
01409 long i;
01410
01411 if (p[-1] == '*' || len > (send - s) * 8)
01412 len = (send - s) * 8;
01413 bits = 0;
01414 rb_ary_push(ary, bitstr = rb_str_new(0, len));
01415 t = RSTRING(bitstr)->ptr;
01416 for (i=0; i<len; i++) {
01417 if (i & 7) bits >>= 1;
01418 else bits = *s++;
01419 *t++ = (bits & 1) ? '1' : '0';
01420 }
01421 }
01422 break;
01423
01424 case 'B':
01425 {
01426 VALUE bitstr;
01427 char *t;
01428 int bits;
01429 long i;
01430
01431 if (p[-1] == '*' || len > (send - s) * 8)
01432 len = (send - s) * 8;
01433 bits = 0;
01434 rb_ary_push(ary, bitstr = rb_str_new(0, len));
01435 t = RSTRING(bitstr)->ptr;
01436 for (i=0; i<len; i++) {
01437 if (i & 7) bits <<= 1;
01438 else bits = *s++;
01439 *t++ = (bits & 128) ? '1' : '0';
01440 }
01441 }
01442 break;
01443
01444 case 'h':
01445 {
01446 VALUE bitstr;
01447 char *t;
01448 int bits;
01449 long i;
01450
01451 if (p[-1] == '*' || len > (send - s) * 2)
01452 len = (send - s) * 2;
01453 bits = 0;
01454 rb_ary_push(ary, bitstr = rb_str_new(0, len));
01455 t = RSTRING(bitstr)->ptr;
01456 for (i=0; i<len; i++) {
01457 if (i & 1)
01458 bits >>= 4;
01459 else
01460 bits = *s++;
01461 *t++ = hexdigits[bits & 15];
01462 }
01463 }
01464 break;
01465
01466 case 'H':
01467 {
01468 VALUE bitstr;
01469 char *t;
01470 int bits;
01471 long i;
01472
01473 if (p[-1] == '*' || len > (send - s) * 2)
01474 len = (send - s) * 2;
01475 bits = 0;
01476 rb_ary_push(ary, bitstr = rb_str_new(0, len));
01477 t = RSTRING(bitstr)->ptr;
01478 for (i=0; i<len; i++) {
01479 if (i & 1)
01480 bits <<= 4;
01481 else
01482 bits = *s++;
01483 *t++ = hexdigits[(bits >> 4) & 15];
01484 }
01485 }
01486 break;
01487
01488 case 'c':
01489 PACK_LENGTH_ADJUST(char,sizeof(char));
01490 while (len-- > 0) {
01491 int c = *s++;
01492 if (c > (char)127) c-=256;
01493 rb_ary_push(ary, INT2FIX(c));
01494 }
01495 PACK_ITEM_ADJUST();
01496 break;
01497
01498 case 'C':
01499 PACK_LENGTH_ADJUST(unsigned char,sizeof(unsigned char));
01500 while (len-- > 0) {
01501 unsigned char c = *s++;
01502 rb_ary_push(ary, INT2FIX(c));
01503 }
01504 PACK_ITEM_ADJUST();
01505 break;
01506
01507 case 's':
01508 PACK_LENGTH_ADJUST(short,2);
01509 while (len-- > 0) {
01510 short tmp = 0;
01511 memcpy(OFF16(&tmp), s, NATINT_LEN(short,2));
01512 EXTEND16(tmp);
01513 s += NATINT_LEN(short,2);
01514 rb_ary_push(ary, INT2FIX(tmp));
01515 }
01516 PACK_ITEM_ADJUST();
01517 break;
01518
01519 case 'S':
01520 PACK_LENGTH_ADJUST(unsigned short,2);
01521 while (len-- > 0) {
01522 unsigned short tmp = 0;
01523 memcpy(OFF16(&tmp), s, NATINT_LEN(unsigned short,2));
01524 s += NATINT_LEN(unsigned short,2);
01525 rb_ary_push(ary, INT2FIX(tmp));
01526 }
01527 PACK_ITEM_ADJUST();
01528 break;
01529
01530 case 'i':
01531 PACK_LENGTH_ADJUST(int,sizeof(int));
01532 while (len-- > 0) {
01533 int tmp;
01534 memcpy(&tmp, s, sizeof(int));
01535 s += sizeof(int);
01536 rb_ary_push(ary, INT2NUM(tmp));
01537 }
01538 PACK_ITEM_ADJUST();
01539 break;
01540
01541 case 'I':
01542 PACK_LENGTH_ADJUST(unsigned int,sizeof(unsigned int));
01543 while (len-- > 0) {
01544 unsigned int tmp;
01545 memcpy(&tmp, s, sizeof(unsigned int));
01546 s += sizeof(unsigned int);
01547 rb_ary_push(ary, UINT2NUM(tmp));
01548 }
01549 PACK_ITEM_ADJUST();
01550 brea