Main Page | Modules | Alphabetical List | Data Structures | File List | Data Fields | Globals

pack.c

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