Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# pack.c

Go to the documentation of this file.

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