unpack
Related methods
- Class methods (3)
-
new
-
try_convert
-
yaml_new
(<= v1_9_1_378)
- Instance methods (148)
-
<<
-
<=>
-
=~
-
==
-
===
-
[]
-
[]=
-
*
-
%
-
+
-
ascii_only?
-
block_scanf
-
bytes
-
bytesize
-
byteslice
(>= v1_9_3_125)
-
capitalize
-
capitalize!
-
casecmp
-
center
-
chars
-
chomp
-
chomp!
-
chop
-
chop!
-
chr
-
clear
-
codepoints
-
concat
-
count
-
crypt
-
delete
-
delete!
-
downcase
-
downcase!
-
dump
-
each
(<= v1_8_7_330)
-
each_byte
-
each_char
-
each_codepoint
-
each_line
-
empty?
-
encode
-
encode!
-
encoding
-
end_regexp
(<= v1_8_7_330)
-
end_with?
-
eql?
-
_expand_ch
(<= v1_8_7_330)
-
expand_ch_hash
(<= v1_8_7_330)
-
ext
(>= v1_9_3_125)
-
force_encoding
-
getbyte
-
gsub
-
gsub!
-
hash
-
hex
-
include?
-
index
-
initialize_copy
-
insert
-
inspect
-
intern
-
is_binary_data?
(<= v1_9_1_378)
-
is_complex_yaml?
(<= v1_9_1_378)
-
iseuc
-
isjis
-
issjis
-
isutf8
-
jcount
(<= v1_8_7_330)
-
jlength
(<= v1_8_7_330)
-
jsize
(<= v1_8_7_330)
-
kconv
-
length
-
lines
-
ljust
-
lstrip
-
lstrip!
-
match
-
mbchar?
(<= v1_8_7_330)
-
next
-
next!
-
oct
-
ord
-
original_succ
(<= v1_8_7_330)
-
original_succ!
(<= v1_8_7_330)
-
parse_csv
-
partition
-
pathmap
(>= v1_9_3_125)
-
pathmap_explode
(>= v1_9_3_125)
-
pathmap_partial
(>= v1_9_3_125)
-
pathmap_replace
(>= v1_9_3_125)
-
prepend
(>= v1_9_3_125)
-
quote
(<= v1_8_6_287)
-
_regex_quote
(<= v1_8_7_330)
-
replace
-
reverse
-
reverse!
-
rindex
-
rjust
-
rpartition
-
rstrip
-
rstrip!
-
scan
-
scanf
-
setbyte
-
shellescape
-
shellsplit
-
size
-
slice
-
slice!
-
split
-
squeeze
-
squeeze!
-
start_with?
-
strip
-
strip!
-
sub
-
sub!
-
succ
-
succ!
-
sum
-
swapcase
-
swapcase!
-
to_c
-
to_d
-
toeuc
-
to_f
-
to_i
-
tojis
-
tolocale
-
to_r
-
to_s
-
tosjis
-
to_str
-
to_sym
-
toutf16
-
toutf32
-
toutf8
-
to_yaml
(<= v1_9_1_378)
-
tr
-
tr!
-
tr_s
-
tr_s!
-
unpack
-
upcase
-
upcase!
-
upto
-
valid_encoding?
= private
= protected
unpack(p1)
public
Decodes str (which may contain binary data) according to the format string, returning an array of each value extracted. The format string consists of a sequence of single-character directives, summarized in the table at the end of this entry. Each directive may be followed by a number, indicating the number of times to repeat with this directive. An asterisk (“*”) will use up all remaining elements. The directives sSiIlL may each be followed by an underscore (“_”) or exclamation mark (“!”) to use the underlying platform’s native size for the specified type; otherwise, it uses a platform-independent consistent size. Spaces are ignored in the format string. See also Array#pack.
"abc \0\0abc \0\0".unpack('A6Z6') #=> ["abc", "abc "] "abc \0\0".unpack('a3a3') #=> ["abc", " \000\000"] "abc \0abc \0".unpack('Z*Z*') #=> ["abc ", "abc "] "aa".unpack('b8B8') #=> ["10000110", "01100001"] "aaa".unpack('h2H2c') #=> ["16", "61", 97] "\xfe\xff\xfe\xff".unpack('sS') #=> [-2, 65534] "now=20is".unpack('M*') #=> ["now is"] "whole".unpack('xax2aX2aX1aX2a') #=> ["h", "e", "l", "l", "o"]
This table summarizes the various formats and the Ruby classes returned by each.
Integer | | Directive | Returns | Meaning
C | Integer | 8-bit unsigned integer (unsigned char) S | Integer | 16-bit unsigned integer, native endian (uint16_t) L | Integer | 32-bit unsigned integer, native endian (uint32_t) Q | Integer | 64-bit unsigned integer, native endian (uint64_t) | | c | Integer | 8-bit signed integer (signed char) s | Integer | 16-bit signed integer, native endian (int16_t) l | Integer | 32-bit signed integer, native endian (int32_t) q | Integer | 64-bit signed integer, native endian (int64_t) | | S_, S! | Integer | unsigned short, native endian I, I_, I! | Integer | unsigned int, native endian L_, L! | Integer | unsigned long, native endian | | s_, s! | Integer | signed short, native endian i, i_, i! | Integer | signed int, native endian l_, l! | Integer | signed long, native endian | | n | Integer | 16-bit unsigned integer, network (big-endian) byte order N | Integer | 32-bit unsigned integer, network (big-endian) byte order v | Integer | 16-bit unsigned integer, VAX (little-endian) byte order V | Integer | 32-bit unsigned integer, VAX (little-endian) byte order | | U | Integer | UTF-8 character w | Integer | BER-compressed integer (see Array.pack)
Float | | Directive | Returns | Meaning
D, d | Float | double-precision float, native format F, f | Float | single-precision float, native format E | Float | double-precision float, little-endian byte order e | Float | single-precision float, little-endian byte order G | Float | double-precision float, network (big-endian) byte order g | Float | single-precision float, network (big-endian) byte order
String | | Directive | Returns | Meaning
A | String | arbitrary binary string (remove trailing nulls and ASCII spaces) a | String | arbitrary binary string Z | String | null-terminated string B | String | bit string (MSB first) b | String | bit string (LSB first) H | String | hex string (high nibble first) h | String | hex string (low nibble first) u | String | UU-encoded string M | String | quoted-printable, MIME encoding (see RFC2045) m | String | base64 encoded string (RFC 2045) (default) | | base64 encoded string (RFC 4648) if followed by 0 P | String | pointer to a structure (fixed-length string) p | String | pointer to a null-terminated string
Misc. | | Directive | Returns | Meaning
@ | --- | skip to the offset given by the length argument X | --- | skip backward one byte x | --- | skip forward one byte
static VALUE pack_unpack(VALUE str, VALUE fmt) { static const char hexdigits[] = "0123456789abcdef"; char *s, *send; char *p, *pend; VALUE ary; char type; long len, tmp_len; int star; #ifdef NATINT_PACK int natint; /* native integer */ #endif int block_p = rb_block_given_p(); int signed_p, integer_size, bigendian_p; #define UNPACK_PUSH(item) do {\ VALUE item_val = (item);\ if (block_p) {\ rb_yield(item_val);\ }\ else {\ rb_ary_push(ary, item_val);\ }\ } while (0) StringValue(str); StringValue(fmt); s = RSTRING_PTR(str); send = s + RSTRING_LEN(str); p = RSTRING_PTR(fmt); pend = p + RSTRING_LEN(fmt); ary = block_p ? Qnil : rb_ary_new(); while (p < pend) { type = *p++; #ifdef NATINT_PACK natint = 0; #endif if (ISSPACE(type)) continue; if (type == '#') { while ((p < pend) && (*p != '\n')) { p++; } continue; } star = 0; if (*p == '_' || *p == '!') { static const char natstr[] = "sSiIlL"; if (strchr(natstr, type)) { #ifdef NATINT_PACK natint = 1; #endif p++; } else { rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, natstr); } } if (p >= pend) len = 1; else if (*p == '*') { star = 1; len = send - s; p++; } else if (ISDIGIT(*p)) { errno = 0; len = STRTOUL(p, (char**)&p, 10); if (errno) { rb_raise(rb_eRangeError, "pack length too big"); } } else { len = (type != '@'); } switch (type) { case '%': rb_raise(rb_eArgError, "%% is not supported"); break; case 'A': if (len > send - s) len = send - s; { long end = len; char *t = s + len - 1; while (t >= s) { if (*t != ' ' && *t != '\0') break; t--; len--; } UNPACK_PUSH(infected_str_new(s, len, str)); s += end; } break; case 'Z': { char *t = s; if (len > send-s) len = send-s; while (t < s+len && *t) t++; UNPACK_PUSH(infected_str_new(s, t-s, str)); if (t < send) t++; s = star ? t : s+len; } break; case 'a': if (len > send - s) len = send - s; UNPACK_PUSH(infected_str_new(s, len, str)); s += len; break; case 'b': { VALUE bitstr; char *t; int bits; long i; if (p[-1] == '*' || len > (send - s) * 8) len = (send - s) * 8; bits = 0; UNPACK_PUSH(bitstr = rb_str_new(0, len)); t = RSTRING_PTR(bitstr); for (i=0; i<len; i++) { if (i & 7) bits >>= 1; else bits = *s++; *t++ = (bits & 1) ? '1' : '0'; } } break; case 'B': { VALUE bitstr; char *t; int bits; long i; if (p[-1] == '*' || len > (send - s) * 8) len = (send - s) * 8; bits = 0; UNPACK_PUSH(bitstr = rb_str_new(0, len)); t = RSTRING_PTR(bitstr); for (i=0; i<len; i++) { if (i & 7) bits <<= 1; else bits = *s++; *t++ = (bits & 128) ? '1' : '0'; } } break; case 'h': { VALUE bitstr; char *t; int bits; long i; if (p[-1] == '*' || len > (send - s) * 2) len = (send - s) * 2; bits = 0; UNPACK_PUSH(bitstr = rb_str_new(0, len)); t = RSTRING_PTR(bitstr); for (i=0; i<len; i++) { if (i & 1) bits >>= 4; else bits = *s++; *t++ = hexdigits[bits & 15]; } } break; case 'H': { VALUE bitstr; char *t; int bits; long i; if (p[-1] == '*' || len > (send - s) * 2) len = (send - s) * 2; bits = 0; UNPACK_PUSH(bitstr = rb_str_new(0, len)); t = RSTRING_PTR(bitstr); for (i=0; i<len; i++) { if (i & 1) bits <<= 4; else bits = *s++; *t++ = hexdigits[(bits >> 4) & 15]; } } break; case 'c': PACK_LENGTH_ADJUST_SIZE(sizeof(char)); while (len-- > 0) { int c = *s++; if (c > (char)127) c-=256; UNPACK_PUSH(INT2FIX(c)); } PACK_ITEM_ADJUST(); break; case 'C': PACK_LENGTH_ADJUST_SIZE(sizeof(unsigned char)); while (len-- > 0) { unsigned char c = *s++; UNPACK_PUSH(INT2FIX(c)); } PACK_ITEM_ADJUST(); break; case 's': signed_p = 1; integer_size = NATINT_LEN(short, 2); bigendian_p = BIGENDIAN_P(); goto unpack_integer; case 'S': signed_p = 0; integer_size = NATINT_LEN(short, 2); bigendian_p = BIGENDIAN_P(); goto unpack_integer; case 'i': signed_p = 1; integer_size = (int)sizeof(int); bigendian_p = BIGENDIAN_P(); goto unpack_integer; case 'I': signed_p = 0; integer_size = (int)sizeof(int); bigendian_p = BIGENDIAN_P(); goto unpack_integer; case 'l': signed_p = 1; integer_size = NATINT_LEN(long, 4); bigendian_p = BIGENDIAN_P(); goto unpack_integer; case 'L': signed_p = 0; integer_size = NATINT_LEN(long, 4); bigendian_p = BIGENDIAN_P(); goto unpack_integer; case 'q': signed_p = 1; integer_size = QUAD_SIZE; bigendian_p = BIGENDIAN_P(); goto unpack_integer; case 'Q': signed_p = 0; integer_size = QUAD_SIZE; bigendian_p = BIGENDIAN_P(); goto unpack_integer; case 'n': signed_p = 0; integer_size = 2; bigendian_p = 1; goto unpack_integer; case 'N': signed_p = 0; integer_size = 4; bigendian_p = 1; goto unpack_integer; case 'v': signed_p = 0; integer_size = 2; bigendian_p = 0; goto unpack_integer; case 'V': signed_p = 0; integer_size = 4; bigendian_p = 0; goto unpack_integer; unpack_integer: switch (integer_size) { #if defined(HAVE_INT16_T) && !defined(FORCE_BIG_PACK) case SIZEOF_INT16_T: if (signed_p) { PACK_LENGTH_ADJUST_SIZE(sizeof(int16_t)); while (len-- > 0) { union { int16_t i; char a[sizeof(int16_t)]; } v; memcpy(v.a, s, sizeof(int16_t)); if (bigendian_p != BIGENDIAN_P()) v.i = swap16(v.i); s += sizeof(int16_t); UNPACK_PUSH(INT2FIX(v.i)); } PACK_ITEM_ADJUST(); } else { PACK_LENGTH_ADJUST_SIZE(sizeof(uint16_t)); while (len-- > 0) { union { uint16_t i; char a[sizeof(uint16_t)]; } v; memcpy(v.a, s, sizeof(uint16_t)); if (bigendian_p != BIGENDIAN_P()) v.i = swap16(v.i); s += sizeof(uint16_t); UNPACK_PUSH(INT2FIX(v.i)); } PACK_ITEM_ADJUST(); } break; #endif #if defined(HAVE_INT32_T) && !defined(FORCE_BIG_PACK) case SIZEOF_INT32_T: if (signed_p) { PACK_LENGTH_ADJUST_SIZE(sizeof(int32_t)); while (len-- > 0) { union { int32_t i; char a[sizeof(int32_t)]; } v; memcpy(v.a, s, sizeof(int32_t)); if (bigendian_p != BIGENDIAN_P()) v.i = swap32(v.i); s += sizeof(int32_t); UNPACK_PUSH(INT2NUM(v.i)); } PACK_ITEM_ADJUST(); } else { PACK_LENGTH_ADJUST_SIZE(sizeof(uint32_t)); while (len-- > 0) { union { uint32_t i; char a[sizeof(uint32_t)]; } v; memcpy(v.a, s, sizeof(uint32_t)); if (bigendian_p != BIGENDIAN_P()) v.i = swap32(v.i); s += sizeof(uint32_t); UNPACK_PUSH(UINT2NUM(v.i)); } PACK_ITEM_ADJUST(); } break; #endif #if defined(HAVE_INT64_T) && !defined(FORCE_BIG_PACK) case SIZEOF_INT64_T: if (signed_p) { PACK_LENGTH_ADJUST_SIZE(sizeof(int64_t)); while (len-- > 0) { union { int64_t i; char a[sizeof(int64_t)]; } v; memcpy(v.a, s, sizeof(int64_t)); if (bigendian_p != BIGENDIAN_P()) v.i = swap64(v.i); s += sizeof(int64_t); UNPACK_PUSH(INT64toNUM(v.i)); } PACK_ITEM_ADJUST(); } else { PACK_LENGTH_ADJUST_SIZE(sizeof(uint64_t)); while (len-- > 0) { union { uint64_t i; char a[sizeof(uint64_t)]; } v; memcpy(v.a, s, sizeof(uint64_t)); if (bigendian_p != BIGENDIAN_P()) v.i = swap64(v.i); s += sizeof(uint64_t); UNPACK_PUSH(UINT64toNUM(v.i)); } PACK_ITEM_ADJUST(); } break; #endif default: if (integer_size > MAX_INTEGER_PACK_SIZE) rb_bug("unexpected intger size for pack: %d", integer_size); PACK_LENGTH_ADJUST_SIZE(integer_size); while (len-- > 0) { union { unsigned long i[(MAX_INTEGER_PACK_SIZE+SIZEOF_LONG)/SIZEOF_LONG]; char a[(MAX_INTEGER_PACK_SIZE+SIZEOF_LONG)/SIZEOF_LONG*SIZEOF_LONG]; } v; int num_longs = (integer_size+SIZEOF_LONG)/SIZEOF_LONG; int i; if (signed_p && (signed char)s[bigendian_p ? 0 : (integer_size-1)] < 0) memset(v.a, 0xff, sizeof(long)*num_longs); else memset(v.a, 0, sizeof(long)*num_longs); if (bigendian_p) memcpy(v.a + sizeof(long)*num_longs - integer_size, s, integer_size); else memcpy(v.a, s, integer_size); if (bigendian_p) { for (i = 0; i < num_longs/2; i++) { unsigned long t = v.i[i]; v.i[i] = v.i[num_longs-1-i]; v.i[num_longs-1-i] = t; } } if (bigendian_p != BIGENDIAN_P()) { for (i = 0; i < num_longs; i++) v.i[i] = swapl(v.i[i]); } s += integer_size; UNPACK_PUSH(rb_big_unpack(v.i, num_longs)); } PACK_ITEM_ADJUST(); break; } break; case 'f': case 'F': PACK_LENGTH_ADJUST_SIZE(sizeof(float)); while (len-- > 0) { float tmp; memcpy(&tmp, s, sizeof(float)); s += sizeof(float); UNPACK_PUSH(DBL2NUM((double)tmp)); } PACK_ITEM_ADJUST(); break; case 'e': PACK_LENGTH_ADJUST_SIZE(sizeof(float)); while (len-- > 0) { float tmp; FLOAT_CONVWITH(ftmp); memcpy(&tmp, s, sizeof(float)); s += sizeof(float); tmp = VTOHF(tmp,ftmp); UNPACK_PUSH(DBL2NUM((double)tmp)); } PACK_ITEM_ADJUST(); break; case 'E': PACK_LENGTH_ADJUST_SIZE(sizeof(double)); while (len-- > 0) { double tmp; DOUBLE_CONVWITH(dtmp); memcpy(&tmp, s, sizeof(double)); s += sizeof(double); tmp = VTOHD(tmp,dtmp); UNPACK_PUSH(DBL2NUM(tmp)); } PACK_ITEM_ADJUST(); break; case 'D': case 'd': PACK_LENGTH_ADJUST_SIZE(sizeof(double)); while (len-- > 0) { double tmp; memcpy(&tmp, s, sizeof(double)); s += sizeof(double); UNPACK_PUSH(DBL2NUM(tmp)); } PACK_ITEM_ADJUST(); break; case 'g': PACK_LENGTH_ADJUST_SIZE(sizeof(float)); while (len-- > 0) { float tmp; FLOAT_CONVWITH(ftmp;) memcpy(&tmp, s, sizeof(float)); s += sizeof(float); tmp = NTOHF(tmp,ftmp); UNPACK_PUSH(DBL2NUM((double)tmp)); } PACK_ITEM_ADJUST(); break; case 'G': PACK_LENGTH_ADJUST_SIZE(sizeof(double)); while (len-- > 0) { double tmp; DOUBLE_CONVWITH(dtmp); memcpy(&tmp, s, sizeof(double)); s += sizeof(double); tmp = NTOHD(tmp,dtmp); UNPACK_PUSH(DBL2NUM(tmp)); } PACK_ITEM_ADJUST(); break; case 'U': if (len > send - s) len = send - s; while (len > 0 && s < send) { long alen = send - s; unsigned long l; l = utf8_to_uv(s, &alen); s += alen; len--; UNPACK_PUSH(ULONG2NUM(l)); } break; case 'u': { VALUE buf = infected_str_new(0, (send - s)*3/4, str); char *ptr = RSTRING_PTR(buf); long total = 0; while (s < send && *s > ' ' && *s < 'a') { long a,b,c,d; char hunk[4]; hunk[3] = '\0'; len = (*s++ - ' ') & 077; total += len; if (total > RSTRING_LEN(buf)) { len -= total - RSTRING_LEN(buf); total = RSTRING_LEN(buf); } while (len > 0) { long mlen = len > 3 ? 3 : len; if (s < send && *s >= ' ') a = (*s++ - ' ') & 077; else a = 0; if (s < send && *s >= ' ') b = (*s++ - ' ') & 077; else b = 0; if (s < send && *s >= ' ') c = (*s++ - ' ') & 077; else c = 0; if (s < send && *s >= ' ') d = (*s++ - ' ') & 077; else d = 0; hunk[0] = (char)(a << 2 | b >> 4); hunk[1] = (char)(b << 4 | c >> 2); hunk[2] = (char)(c << 6 | d); memcpy(ptr, hunk, mlen); ptr += mlen; len -= mlen; } if (*s == '\r') s++; if (*s == '\n') s++; else if (s < send && (s+1 == send || s[1] == '\n')) s += 2; /* possible checksum byte */ } rb_str_set_len(buf, total); UNPACK_PUSH(buf); } break; case 'm': { VALUE buf = infected_str_new(0, (send - s)*3/4, str); char *ptr = RSTRING_PTR(buf); int a = -1,b = -1,c = 0,d = 0; static signed char b64_xtable[256]; if (b64_xtable['/'] <= 0) { int i; for (i = 0; i < 256; i++) { b64_xtable[i] = -1; } for (i = 0; i < 64; i++) { b64_xtable[(unsigned char)b64_table[i]] = i; } } if (len == 0) { while (s < send) { a = b = c = d = -1; a = b64_xtable[(unsigned char)*s++]; if (s >= send || a == -1) rb_raise(rb_eArgError, "invalid base64"); b = b64_xtable[(unsigned char)*s++]; if (s >= send || b == -1) rb_raise(rb_eArgError, "invalid base64"); if (*s == '=') { if (s + 2 == send && *(s + 1) == '=') break; rb_raise(rb_eArgError, "invalid base64"); } c = b64_xtable[(unsigned char)*s++]; if (s >= send || c == -1) rb_raise(rb_eArgError, "invalid base64"); if (s + 1 == send && *s == '=') break; d = b64_xtable[(unsigned char)*s++]; if (d == -1) rb_raise(rb_eArgError, "invalid base64"); *ptr++ = a << 2 | b >> 4; *ptr++ = b << 4 | c >> 2; *ptr++ = c << 6 | d; } if (c == -1) { *ptr++ = a << 2 | b >> 4; if (b & 0xf) rb_raise(rb_eArgError, "invalid base64"); } else if (d == -1) { *ptr++ = a << 2 | b >> 4; *ptr++ = b << 4 | c >> 2; if (c & 0x3) rb_raise(rb_eArgError, "invalid base64"); } } else { while (s < send) { a = b = c = d = -1; while ((a = b64_xtable[(unsigned char)*s]) == -1 && s < send) {s++;} if (s >= send) break; s++; while ((b = b64_xtable[(unsigned char)*s]) == -1 && s < send) {s++;} if (s >= send) break; s++; while ((c = b64_xtable[(unsigned char)*s]) == -1 && s < send) {if (*s == '=') break; s++;} if (*s == '=' || s >= send) break; s++; while ((d = b64_xtable[(unsigned char)*s]) == -1 && s < send) {if (*s == '=') break; s++;} if (*s == '=' || s >= send) break; s++; *ptr++ = a << 2 | b >> 4; *ptr++ = b << 4 | c >> 2; *ptr++ = c << 6 | d; } if (a != -1 && b != -1) { if (c == -1 && *s == '=') *ptr++ = a << 2 | b >> 4; else if (c != -1 && *s == '=') { *ptr++ = a << 2 | b >> 4; *ptr++ = b << 4 | c >> 2; } } } rb_str_set_len(buf, ptr - RSTRING_PTR(buf)); UNPACK_PUSH(buf); } break; case 'M': { VALUE buf = infected_str_new(0, send - s, str); char *ptr = RSTRING_PTR(buf); int c1, c2; while (s < send) { if (*s == '=') { if (++s == send) break; if (s+1 < send && *s == '\r' && *(s+1) == '\n') s++; if (*s != '\n') { if ((c1 = hex2num(*s)) == -1) break; if (++s == send) break; if ((c2 = hex2num(*s)) == -1) break; *ptr++ = c1 << 4 | c2; } } else { *ptr++ = *s; } s++; } rb_str_set_len(buf, ptr - RSTRING_PTR(buf)); ENCODING_CODERANGE_SET(buf, rb_usascii_encindex(), ENC_CODERANGE_7BIT); UNPACK_PUSH(buf); } break; case '@': if (len > RSTRING_LEN(str)) rb_raise(rb_eArgError, "@ outside of string"); s = RSTRING_PTR(str) + len; break; case 'X': if (len > s - RSTRING_PTR(str)) rb_raise(rb_eArgError, "X outside of string"); s -= len; break; case 'x': if (len > send - s) rb_raise(rb_eArgError, "x outside of string"); s += len; break; case 'P': if (sizeof(char *) <= (size_t)(send - s)) { VALUE tmp = Qnil; char *t; memcpy(&t, s, sizeof(char *)); s += sizeof(char *); if (t) { VALUE a, *p, *pend; if (!(a = rb_str_associated(str))) { rb_raise(rb_eArgError, "no associated pointer"); } p = RARRAY_PTR(a); pend = p + RARRAY_LEN(a); while (p < pend) { if (TYPE(*p) == T_STRING && RSTRING_PTR(*p) == t) { if (len < RSTRING_LEN(*p)) { tmp = rb_tainted_str_new(t, len); rb_str_associate(tmp, a); } else { tmp = *p; } break; } p++; } if (p == pend) { rb_raise(rb_eArgError, "non associated pointer"); } } UNPACK_PUSH(tmp); } break; case 'p': if (len > (long)((send - s) / sizeof(char *))) len = (send - s) / sizeof(char *); while (len-- > 0) { if ((size_t)(send - s) < sizeof(char *)) break; else { VALUE tmp = Qnil; char *t; memcpy(&t, s, sizeof(char *)); s += sizeof(char *); if (t) { VALUE a, *p, *pend; if (!(a = rb_str_associated(str))) { rb_raise(rb_eArgError, "no associated pointer"); } p = RARRAY_PTR(a); pend = p + RARRAY_LEN(a); while (p < pend) { if (TYPE(*p) == T_STRING && RSTRING_PTR(*p) == t) { tmp = *p; break; } p++; } if (p == pend) { rb_raise(rb_eArgError, "non associated pointer"); } } UNPACK_PUSH(tmp); } } break; case 'w': { unsigned long ul = 0; unsigned long ulmask = 0xfeUL << ((sizeof(unsigned long) - 1) * 8); while (len > 0 && s < send) { ul <<= 7; ul |= (*s & 0x7f); if (!(*s++ & 0x80)) { UNPACK_PUSH(ULONG2NUM(ul)); len--; ul = 0; } else if (ul & ulmask) { VALUE big = rb_uint2big(ul); VALUE big128 = rb_uint2big(128); while (s < send) { big = rb_big_mul(big, big128); big = rb_big_plus(big, rb_uint2big(*s & 0x7f)); if (!(*s++ & 0x80)) { UNPACK_PUSH(big); len--; ul = 0; break; } } } } } break; default: break; } } return ary; }


