pack.c


DEFINITIONS

This source file includes following functions.
  1. OFF16B
  2. OFF32B
  3. NATINT_I32
  4. NATINT_U32
  5. NATINT_LEN
  6. OFF16
  7. OFF32
  8. NATINT_I32
  9. NATINT_U32
  10. NATINT_LEN
  11. OFF16
  12. OFF32
  13. OFF16B
  14. OFF32B
  15. swapd
  16. swapd
  17. endian
  18. pack_pack
  19. encodes
  20. qpencode
  21. hex2num
  22. infected_str_new
  23. pack_unpack
  24. uv_to_utf8
  25. utf8_to_uv
  26. Init_pack


   1  /**********************************************************************
   2  
   3    pack.c -
   4  
   5    $Author: michal $
   6    $Date: 2002/08/28 08:05:23 $
   7    created at: Thu Feb 10 15:17:05 JST 1994
   8  
   9    Copyright (C) 1993-2002 Yukihiro Matsumoto
  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    /* SIZEOF_FLOAT == 4 == SIZEOF_LONG */
 108  #define swapf(x)        swapl(x)
 109  #define FLOAT_SWAPPER   unsigned long
 110  #else
 111  #if SIZEOF_SHORT == 4   /* SIZEOF_FLOAT == 4 == SIZEOF_SHORT */
 112  #define swapf(x)        swaps(x)
 113  #define FLOAT_SWAPPER   unsigned short
 114  #else   /* SIZEOF_FLOAT == 4 but undivide by known size of int */
 115  define_swapx(f,float);
 116  #endif  /* #if SIZEOF_SHORT == 4 */
 117  #endif  /* #if SIZEOF_LONG == 4 */
 118  #else   /* SIZEOF_FLOAT != 4 */
 119  define_swapx(f,float);
 120  #endif  /* #if SIZEOF_FLOAT == 4 */
 121  
 122  #if SIZEOF_DOUBLE == 8
 123  #if SIZEOF_LONG == 8    /* SIZEOF_DOUBLE == 8 == SIZEOF_LONG */
 124  #define swapd(x)        swapl(x)
 125  #define DOUBLE_SWAPPER  unsigned long
 126  #else
 127  #if SIZEOF_LONG == 4    /* SIZEOF_DOUBLE == 8 && 4 == SIZEOF_LONG */
 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   /* SIZEOF_DOUBLE == 8 && 4 == SIZEOF_SHORT */
 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   /* SIZEOF_DOUBLE == 8 but undivied by known size of int */
 163  define_swapx(d, double);
 164  #endif  /* #if SIZEOF_SHORT == 4 */
 165  #endif  /* #if SIZEOF_LONG == 4 */
 166  #endif  /* #if SIZEOF_LONG == 8 */
 167  #else   /* SIZEOF_DOUBLE != 8 */
 168  define_swapx(d, double);
 169  #endif  /* #if SIZEOF_DPOUBLE == 8 */
 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 /* LITTLE ENDIAN */
 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;         /* native integer */
 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++;            /* get data type */
 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 == '*') {        /* set data length */
 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              /* FALL THROUGH */
 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; /* mod */
 864                          rb_str_buf_cat(buf, &c, sizeof(char));
 865                          from = RARRAY(from)->ptr[0]; /* div */
 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; /* clear continue bit */
 884                      while (bufs < bufe) { /* reverse */
 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;                 /* native integer */
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; /* possible checksum byte */
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  }