Ruby 4.1.0dev (2026-10-27 revision db563a357875d4efbadec58b0fd8695ac9a82f42)
pack.c (db563a357875d4efbadec58b0fd8695ac9a82f42)
1/**********************************************************************
2
3 pack.c -
4
5 $Author$
6 created at: Thu Feb 10 15:17:05 JST 1994
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9
10**********************************************************************/
11
12#include "ruby/internal/config.h"
13
14#include <ctype.h>
15#include <errno.h>
16#include <float.h>
17#include <sys/types.h>
18
19#include "internal.h"
20#include "internal/array.h"
21#include "internal/bits.h"
22#include "internal/numeric.h"
23#include "internal/string.h"
24#include "internal/symbol.h"
25#include "internal/variable.h"
26#include "ruby/util.h"
27
28#include "builtin.h"
29
30/*
31 * It is intentional that the condition for natstr is HAVE_TRUE_LONG_LONG
32 * instead of HAVE_LONG_LONG or LONG_LONG.
33 * This means q! and Q! means always the standard long long type and
34 * causes ArgumentError for platforms which has no long long type,
35 * even if the platform has an implementation specific 64bit type.
36 * This behavior is consistent with the document of pack/unpack.
37 */
38#ifdef HAVE_TRUE_LONG_LONG
39static const char natstr[] = "sSiIlLqQjJ";
40# define endstr natstr
41#else
42static const char natstr[] = "sSiIlLjJ";
43static const char endstr[] = "sSiIlLqQjJ";
44#endif
45
46#ifdef HAVE_TRUE_LONG_LONG
47/* It is intentional to use long long instead of LONG_LONG. */
48# define NATINT_LEN_Q NATINT_LEN(long long, 8)
49#else
50# define NATINT_LEN_Q 8
51#endif
52
53#if SIZEOF_SHORT != 2 || SIZEOF_LONG != 4 || (defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG != 8)
54# define NATINT_PACK
55#endif
56
57#ifdef DYNAMIC_ENDIAN
58/* for universal binary of MacOS X */
59/* useless since autoconf 2.63? */
60static int
61is_bigendian(void)
62{
63 static const union {int i; char b[1];} endian_value = {1};
64 return !endian_value.b[0];
65}
66# define BIGENDIAN_P() (is_bigendian())
67#elif defined(WORDS_BIGENDIAN)
68# define BIGENDIAN_P() 1
69#else
70# define BIGENDIAN_P() 0
71#endif
72
73#ifdef NATINT_PACK
74# define NATINT_LEN(type,len) (natint?(int)sizeof(type):(int)(len))
75# define NATINT_ALIGN(type,len) (natint?(int)RUBY_ALIGNOF(type):(int)(len))
76# define USING_NATINT(expr) expr
77#else
78# define NATINT_LEN(type,len) ((int)sizeof(type))
79# define NATINT_ALIGN(type,len) ((int)RUBY_ALIGNOF(type))
80# define USING_NATINT(expr) /* void */
81#endif
82
83typedef union {
84 float f;
85 uint32_t u;
86 char buf[4];
88typedef union {
89 double d;
90 uint64_t u;
91 char buf[8];
93#define swapf(x) swap32(x)
94#define swapd(x) swap64(x)
95
96#define rb_ntohf(x) (BIGENDIAN_P()?(x):swapf(x))
97#define rb_ntohd(x) (BIGENDIAN_P()?(x):swapd(x))
98#define rb_htonf(x) (BIGENDIAN_P()?(x):swapf(x))
99#define rb_htond(x) (BIGENDIAN_P()?(x):swapd(x))
100#define rb_htovf(x) (BIGENDIAN_P()?swapf(x):(x))
101#define rb_htovd(x) (BIGENDIAN_P()?swapd(x):(x))
102#define rb_vtohf(x) (BIGENDIAN_P()?swapf(x):(x))
103#define rb_vtohd(x) (BIGENDIAN_P()?swapd(x):(x))
104
105#define FLOAT_CONVWITH(x) FLOAT_SWAPPER x;
106#define HTONF(x) ((x).u = rb_htonf((x).u))
107#define HTOVF(x) ((x).u = rb_htovf((x).u))
108#define NTOHF(x) ((x).u = rb_ntohf((x).u))
109#define VTOHF(x) ((x).u = rb_vtohf((x).u))
110
111#define DOUBLE_CONVWITH(x) DOUBLE_SWAPPER x;
112#define HTOND(x) ((x).u = rb_htond((x).u))
113#define HTOVD(x) ((x).u = rb_htovd((x).u))
114#define NTOHD(x) ((x).u = rb_ntohd((x).u))
115#define VTOHD(x) ((x).u = rb_vtohd((x).u))
116
117#define MAX_INTEGER_PACK_SIZE 8
118
119static const char toofew[] = "too few arguments";
120static const char intoitself[] = "cannot pack buffer object into itself";
121
122static void encodes(VALUE,const char*,rb_len_t,int,int);
123static void qpencode(VALUE,VALUE,rb_len_t);
124
125static unsigned long utf8_to_uv(const char*,rb_len_t*);
126
127static ID id_associated;
128
129static void
130str_associate(VALUE str, VALUE add)
131{
132 /* assert(NIL_P(rb_attr_get(str, id_associated))); */
133 rb_ivar_set(str, id_associated, add);
134}
135
136static VALUE
137str_associated(VALUE str)
138{
139 VALUE associates = rb_ivar_lookup(str, id_associated, Qfalse);
140 if (!associates)
141 rb_raise(rb_eArgError, "no associated pointer");
142 return associates;
143}
144
145static VALUE
146associated_pointer(VALUE associates, const char *t)
147{
148 const VALUE *p = RARRAY_CONST_PTR(associates);
149 const VALUE *pend = p + RARRAY_LEN(associates);
150 for (; p < pend; p++) {
151 VALUE tmp = *p;
152 if (RB_TYPE_P(tmp, T_STRING) && RSTRING_PTR(tmp) == t) return tmp;
153 }
154 rb_raise(rb_eArgError, "non associated pointer");
156}
157
159static void
160unknown_directive(const char *mode, char type, VALUE fmt)
161{
162 char unknown[5];
163
164 if (ISPRINT(type)) {
165 unknown[0] = type;
166 unknown[1] = '\0';
167 }
168 else {
169 snprintf(unknown, sizeof(unknown), "\\x%.2x", type & 0xff);
170 }
171 fmt = rb_str_quote_unprintable(fmt);
172 rb_raise(rb_eArgError, "unknown %s directive '%s' in '%"PRIsVALUE"'",
173 mode, unknown, fmt);
174}
175
176static float
177VALUE_to_float(VALUE obj)
178{
179 VALUE v = rb_to_float(obj);
180 double d = RFLOAT_VALUE(v);
181
182 if (isnan(d)) {
183 return NAN;
184 }
185 else if (d < -FLT_MAX) {
186 return -INFINITY;
187 }
188 else if (d <= FLT_MAX) {
189 return d;
190 }
191 else {
192 return INFINITY;
193 }
194}
195
196static void
197str_expand_fill(VALUE res, int c, rb_len_t len)
198{
199 rb_len_t olen = RSTRING_LEN(res);
200 memset(RSTRING_PTR(res) + olen, c, len);
201 rb_str_set_len(res, olen + len);
202}
203
204static char *
205skip_to_eol(const char *p, const char *pend)
206{
207 p = memchr(p, '\n', pend - p);
208 return (char *)(p ? p + 1 : pend);
209}
210
211#define skip_blank(p, type) \
212 (ISSPACE(type) || (type == '#' && (p = skip_to_eol(p, pend), 1)))
213
214#ifndef NATINT_PACK
215# define pack_modifiers(p, pe, t, n, e) pack_modifiers(p, pe, t, e)
216#endif
217static const char *
218pack_modifiers(const char *p, const char *pend, char type, int *natint, int *explicit_endian)
219{
220 while (p < pend) {
221 switch (*p) {
222 case '_':
223 case '!':
224 if (strchr(natstr, type)) {
225 USING_NATINT(*natint = 1);
226 p++;
227 }
228 else {
229 rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, natstr);
230 }
231 break;
232
233 case '<':
234 case '>':
235 if (!strchr(endstr, type)) {
236 rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, endstr);
237 }
238 if (*explicit_endian) {
239 rb_raise(rb_eRangeError, "Can't use both '<' and '>'");
240 }
241 *explicit_endian = *p++;
242 break;
243 default:
244 return (char *)p;
245 }
246 }
247 return p;
248}
249
250#ifndef NATINT_PACK
251# define pack_alignof(t, n) pack_alignof(t)
252#endif
253static size_t
254pack_alignof(char type, int natint)
255{
256 switch (type) {
257 case 'c': case 'C':
258 return RUBY_ALIGNOF(char);
259 case 's': case 'S':
260 return NATINT_ALIGN(short, 2);
261 case 'i': case 'I':
262 return RUBY_ALIGNOF(int);
263 case 'l': case 'L':
264 return NATINT_ALIGN(long, 4);
265 case 'q': case 'Q':
266 return RUBY_ALIGNOF(int64_t);
267 case 'j':
268 return RUBY_ALIGNOF(intptr_t);
269 case 'J':
270 return RUBY_ALIGNOF(uintptr_t);
271 case 'n': case 'v':
272 return RUBY_ALIGNOF(uint16_t);
273 case 'N': case 'V':
274 return RUBY_ALIGNOF(uint32_t);
275 case 'f': case 'F': case 'e': case 'g':
276 return RUBY_ALIGNOF(float);
277 case 'd': case 'D': case 'E': case 'G':
278 return RUBY_ALIGNOF(double);
279 case 'p': case 'P':
280 return RUBY_ALIGNOF(char *);
281 default:
282 return 0;
283 }
284}
285
286static rb_len_t
287pack_align_pad(rb_len_t pos, rb_len_t base, size_t alignment)
288{
289 rb_len_t offset, mod;
290
291 if (alignment <= 1) return 0;
292 if (alignment > RB_LEN_MAX) rb_raise(rb_eRangeError, "alignment too big");
293 offset = pos - base;
294 mod = offset % (rb_len_t)alignment;
295 if (mod < 0) mod += alignment;
296 return mod ? (rb_len_t)alignment - mod : 0;
297}
298
299static char *
300pack_alignment(const char *p, const char *pend, VALUE fmt, size_t *alignment)
301{
302 char type;
303 int explicit_endian = 0;
304 USING_NATINT(int natint = 0);
305
306 if (p >= pend) {
307 rb_raise(rb_eArgError, "missing alignment");
308 }
309 type = *p++;
310 p = pack_modifiers(p, pend, type, &natint, &explicit_endian);
311 if (explicit_endian) {
312 rb_raise(rb_eArgError, "endian modifier is not allowed for alignment");
313 }
314 *alignment = pack_alignof(type, natint);
315 if (!*alignment) {
316 unknown_directive("alignment", type, fmt);
317 }
318 return (char *)p;
319}
320
321static char *
322pack_alignment_size(const char *p, const char *pend, VALUE fmt, size_t *alignment)
323{
324 if (p < pend && ISDIGIT(*p)) {
325 errno = 0;
326 *alignment = STRTOUL(p, (char**)&p, 10);
327 if (*alignment <= 0 || errno) {
328 rb_raise(rb_eRangeError, "invalid alignment");
329 }
330 return (char *)p;
331 }
332 return pack_alignment(p, pend, fmt, alignment);
333}
334
335static VALUE
336pack_pack(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
337{
338 const char *p, *pend;
339 VALUE res, from, associates = 0;
340 rb_len_t len, idx, plen;
341 const char *ptr;
342 int enc_info = 1; /* 0 - BINARY, 1 - US-ASCII, 2 - UTF-8 */
343 int integer_size, bigendian_p;
344 rb_len_t align_base;
345
346 StringValue(fmt);
348 p = RSTRING_PTR(fmt);
349 pend = p + RSTRING_LEN(fmt);
350
351 if (NIL_P(buffer)) {
352 res = rb_str_buf_new(0);
353 }
354 else {
355 if (!RB_TYPE_P(buffer, T_STRING))
356 rb_raise(rb_eTypeError, "buffer must be String, not %s", rb_obj_classname(buffer));
357 rb_str_modify(buffer);
358 res = buffer;
359 }
360
361 idx = 0;
362 align_base = RSTRING_LEN(res);
363
364#define TOO_FEW (rb_raise(rb_eArgError, toofew), 0)
365#define MORE_ITEM (idx < RARRAY_LEN(ary))
366#define THISFROM (MORE_ITEM ? RARRAY_AREF(ary, idx) : TOO_FEW)
367#define NEXTFROM (MORE_ITEM ? RARRAY_AREF(ary, idx++) : TOO_FEW)
368#define NOT_BUFFER(val) (((val) == res) ? rb_raise(rb_eArgError, intoitself) : (void)0)
369#define STR_FROM(val) NOT_BUFFER(StringValue(val))
370
371 while (p < pend) {
372 int explicit_endian = 0;
373 size_t align = 0;
374 bool star = false;
375 if (RSTRING_END(fmt) != pend) {
376 rb_raise(rb_eRuntimeError, "format string modified");
377 }
378 const char type = *p++; /* get data type */
379 USING_NATINT(int natint = 0); /* native integer */
380
381 if (skip_blank(p, type)) continue;
382
383 /* Directives that do not take modifiers. */
384 if ((type == 'x' || type == '@') && p < pend && *p == '!') {
385 p++;
386 p = pack_alignment_size(p, pend, fmt, &align);
387 len = pack_align_pad(RSTRING_LEN(res), type == '@' ? 0 : align_base, align);
389 str_expand_fill(res, '\0', len);
390 continue;
391 }
392
393 p = pack_modifiers(p, pend, type, &natint, &explicit_endian);
394
395 if (*p == '*') { /* set data length */
396 star = true;
397 len = strchr("@Xxu", type) ? 0
398 : strchr("PMm", type) ? 1
399 : RARRAY_LEN(ary) - idx;
400 p++;
401 }
402 else if (ISDIGIT(*p)) {
403 errno = 0;
404 len = STRTOUL(p, (char**)&p, 10);
405 if (len < 0 || errno) {
406 rb_raise(rb_eRangeError, "pack length too big");
407 }
408 }
409 else {
410 len = 1;
411 }
412
413 switch (type) {
414 case 'U':
415 /* if encoding is US-ASCII, upgrade to UTF-8 */
416 if (enc_info == 1) enc_info = 2;
417 break;
418 case 'm': case 'M': case 'u':
419 /* keep US-ASCII (do nothing) */
420 break;
421 default:
422 /* fall back to BINARY */
423 enc_info = 0;
424 break;
425 }
426 switch (type) {
427 case 'A': case 'a': case 'Z':
428 case 'B': case 'b':
429 case 'H': case 'h':
430 from = NEXTFROM;
431 if (NIL_P(from)) {
432 ptr = "";
433 plen = 0;
434 }
435 else {
436 STR_FROM(from);
437 ptr = RSTRING_PTR(from);
438 plen = RSTRING_LEN(from);
439 }
440
441 /* The conversion of from with #to_str may have modified fmt,
442 * so p may be a dangling pointer; use star instead of p[-1]. */
443 if (star)
444 len = plen;
445
446 switch (type) {
447 case 'a': /* arbitrary binary string (null padded) */
448 case 'A': /* arbitrary binary string (ASCII space padded) */
449 case 'Z': /* null terminated string */
450 if (plen >= len) {
451 rb_str_buf_cat(res, ptr, len);
452 if (star && type == 'Z')
453 rb_str_buf_cat(res, "", 1);
454 }
455 else {
457 rb_str_buf_cat(res, ptr, plen);
458 str_expand_fill(res, (type == 'A' ? ' ' : '\0'), len - plen);
459 }
460 break;
461
462#define castchar(from) (char)((from) & 0xff)
463
464 case 'b': /* bit string (ascending) */
465 {
466 int byte = 0;
467 rb_len_t i, j = 0;
468
469 if (len > plen) {
470 j = (len - plen + 1)/2;
471 len = plen;
472 }
473 for (i=0; i++ < len; ptr++) {
474 if (*ptr & 1)
475 byte |= 128;
476 if (i & 7)
477 byte >>= 1;
478 else {
479 char c = castchar(byte);
480 rb_str_buf_cat(res, &c, 1);
481 byte = 0;
482 }
483 }
484 if (len & 7) {
485 char c;
486 byte >>= 7 - (len & 7);
487 c = castchar(byte);
488 rb_str_buf_cat(res, &c, 1);
489 }
490 len = j;
491 goto grow;
492 }
493 break;
494
495 case 'B': /* bit string (descending) */
496 {
497 int byte = 0;
498 rb_len_t i, j = 0;
499
500 if (len > plen) {
501 j = (len - plen + 1)/2;
502 len = plen;
503 }
504 for (i=0; i++ < len; ptr++) {
505 byte |= *ptr & 1;
506 if (i & 7)
507 byte <<= 1;
508 else {
509 char c = castchar(byte);
510 rb_str_buf_cat(res, &c, 1);
511 byte = 0;
512 }
513 }
514 if (len & 7) {
515 char c;
516 byte <<= 7 - (len & 7);
517 c = castchar(byte);
518 rb_str_buf_cat(res, &c, 1);
519 }
520 len = j;
521 goto grow;
522 }
523 break;
524
525 case 'h': /* hex string (low nibble first) */
526 {
527 int byte = 0;
528 rb_len_t i, j = 0;
529
530 if (len > plen) {
531 j = (len + 1) / 2 - (plen + 1) / 2;
532 len = plen;
533 }
534 for (i=0; i++ < len; ptr++) {
535 if (ISALPHA(*ptr))
536 byte |= (((*ptr & 15) + 9) & 15) << 4;
537 else
538 byte |= (*ptr & 15) << 4;
539 if (i & 1)
540 byte >>= 4;
541 else {
542 char c = castchar(byte);
543 rb_str_buf_cat(res, &c, 1);
544 byte = 0;
545 }
546 }
547 if (len & 1) {
548 char c = castchar(byte);
549 rb_str_buf_cat(res, &c, 1);
550 }
551 len = j;
552 goto grow;
553 }
554 break;
555
556 case 'H': /* hex string (high nibble first) */
557 {
558 int byte = 0;
559 rb_len_t i, j = 0;
560
561 if (len > plen) {
562 j = (len + 1) / 2 - (plen + 1) / 2;
563 len = plen;
564 }
565 for (i=0; i++ < len; ptr++) {
566 if (ISALPHA(*ptr))
567 byte |= ((*ptr & 15) + 9) & 15;
568 else
569 byte |= *ptr & 15;
570 if (i & 1)
571 byte <<= 4;
572 else {
573 char c = castchar(byte);
574 rb_str_buf_cat(res, &c, 1);
575 byte = 0;
576 }
577 }
578 if (len & 1) {
579 char c = castchar(byte);
580 rb_str_buf_cat(res, &c, 1);
581 }
582 len = j;
583 goto grow;
584 }
585 break;
586 }
587 break;
588
589 case 'c': /* signed char */
590 case 'C': /* unsigned char */
591 integer_size = 1;
592 bigendian_p = BIGENDIAN_P(); /* not effective */
593 goto pack_integer;
594
595 case 's': /* s for int16_t, s! for signed short */
596 case 'S': /* S for uint16_t, S! for unsigned short */
597 integer_size = NATINT_LEN(short, 2);
598 bigendian_p = BIGENDIAN_P();
599 goto pack_integer;
600
601 case 'i': /* i and i! for signed int */
602 case 'I': /* I and I! for unsigned int */
603 integer_size = (int)sizeof(int);
604 bigendian_p = BIGENDIAN_P();
605 goto pack_integer;
606
607 case 'l': /* l for int32_t, l! for signed long */
608 case 'L': /* L for uint32_t, L! for unsigned long */
609 integer_size = NATINT_LEN(long, 4);
610 bigendian_p = BIGENDIAN_P();
611 goto pack_integer;
612
613 case 'q': /* q for int64_t, q! for signed long long */
614 case 'Q': /* Q for uint64_t, Q! for unsigned long long */
615 integer_size = NATINT_LEN_Q;
616 bigendian_p = BIGENDIAN_P();
617 goto pack_integer;
618
619 case 'j': /* j for intptr_t */
620 integer_size = sizeof(intptr_t);
621 bigendian_p = BIGENDIAN_P();
622 goto pack_integer;
623
624 case 'J': /* J for uintptr_t */
625 integer_size = sizeof(uintptr_t);
626 bigendian_p = BIGENDIAN_P();
627 goto pack_integer;
628
629 case 'n': /* 16 bit (2 bytes) integer (network byte-order) */
630 integer_size = 2;
631 bigendian_p = 1;
632 goto pack_integer;
633
634 case 'N': /* 32 bit (4 bytes) integer (network byte-order) */
635 integer_size = 4;
636 bigendian_p = 1;
637 goto pack_integer;
638
639 case 'v': /* 16 bit (2 bytes) integer (VAX byte-order) */
640 integer_size = 2;
641 bigendian_p = 0;
642 goto pack_integer;
643
644 case 'V': /* 32 bit (4 bytes) integer (VAX byte-order) */
645 integer_size = 4;
646 bigendian_p = 0;
647 goto pack_integer;
648
649 pack_integer:
650 if (explicit_endian) {
651 bigendian_p = explicit_endian == '>';
652 }
653 if (integer_size > MAX_INTEGER_PACK_SIZE)
654 rb_bug("unexpected integer size for pack: %d", integer_size);
655 while (len-- > 0) {
656 char intbuf[MAX_INTEGER_PACK_SIZE];
657
658 from = NEXTFROM;
659 rb_integer_pack(from, intbuf, integer_size, 1, 0,
662 rb_str_buf_cat(res, intbuf, integer_size);
663 }
664 break;
665
666 case 'f': /* single precision float in native format */
667 case 'F': /* ditto */
668 while (len-- > 0) {
669 float f;
670
671 from = NEXTFROM;
672 f = VALUE_to_float(from);
673 rb_str_buf_cat(res, (char*)&f, sizeof(float));
674 }
675 break;
676
677 case 'e': /* single precision float in VAX byte-order */
678 while (len-- > 0) {
679 FLOAT_CONVWITH(tmp);
680
681 from = NEXTFROM;
682 tmp.f = VALUE_to_float(from);
683 HTOVF(tmp);
684 rb_str_buf_cat(res, tmp.buf, sizeof(float));
685 }
686 break;
687
688 case 'E': /* double precision float in VAX byte-order */
689 while (len-- > 0) {
690 DOUBLE_CONVWITH(tmp);
691 from = NEXTFROM;
692 tmp.d = RFLOAT_VALUE(rb_to_float(from));
693 HTOVD(tmp);
694 rb_str_buf_cat(res, tmp.buf, sizeof(double));
695 }
696 break;
697
698 case 'd': /* double precision float in native format */
699 case 'D': /* ditto */
700 while (len-- > 0) {
701 double d;
702
703 from = NEXTFROM;
704 d = RFLOAT_VALUE(rb_to_float(from));
705 rb_str_buf_cat(res, (char*)&d, sizeof(double));
706 }
707 break;
708
709 case 'g': /* single precision float in network byte-order */
710 while (len-- > 0) {
711 FLOAT_CONVWITH(tmp);
712 from = NEXTFROM;
713 tmp.f = VALUE_to_float(from);
714 HTONF(tmp);
715 rb_str_buf_cat(res, tmp.buf, sizeof(float));
716 }
717 break;
718
719 case 'G': /* double precision float in network byte-order */
720 while (len-- > 0) {
721 DOUBLE_CONVWITH(tmp);
722
723 from = NEXTFROM;
724 tmp.d = RFLOAT_VALUE(rb_to_float(from));
725 HTOND(tmp);
726 rb_str_buf_cat(res, tmp.buf, sizeof(double));
727 }
728 break;
729
730 case 'x': /* null byte */
731 grow:
733 str_expand_fill(res, '\0', len);
734 break;
735
736 case 'X': /* back up byte */
737 shrink:
738 plen = RSTRING_LEN(res);
739 if (plen < len)
740 rb_raise(rb_eArgError, "X outside of string");
741 rb_str_set_len(res, plen - len);
742 break;
743
744 case '@': /* null fill to absolute position */
745 len -= RSTRING_LEN(res);
746 if (len > 0) goto grow;
747 len = -len;
748 if (len > 0) goto shrink;
749 break;
750
751 case '%':
752 rb_raise(rb_eArgError, "%% is not supported");
753 break;
754
755 case 'U': /* Unicode character */
756 while (len-- > 0) {
757 SIGNED_VALUE l;
758 char buf[8];
759 int le;
760
761 from = NEXTFROM;
762 from = rb_to_int(from);
763 l = NUM2LONG(from);
764 if (l < 0) {
765 rb_raise(rb_eRangeError, "pack(U): value out of range");
766 }
767 le = rb_uv_to_utf8(buf, l);
768 rb_str_buf_cat(res, (char*)buf, le);
769 }
770 break;
771
772 case 'r': /* r for SLEB128 encoding (signed) */
773 case 'R': /* R for ULEB128 encoding (unsigned) */
774 {
775 int pack_flags = INTEGER_PACK_LITTLE_ENDIAN;
776
777 if (type == 'r') {
778 pack_flags |= INTEGER_PACK_2COMP;
779 }
780
781 while (len-- > 0) {
782 size_t numbytes, nlz_bits;
783 int sign, extra = 0;
784 char *cp;
785
786 from = NEXTFROM;
787 from = rb_to_int(from);
788 if (type == 'R' && rb_int_negative_p(from)) {
789 rb_raise(rb_eArgError, "can't encode negative numbers in ULEB128");
790 }
791
792 numbytes = rb_absint_numwords(from, 7, &nlz_bits);
793 if (numbytes == 0) {
794 numbytes = 1;
795 }
796 else if (nlz_bits == 0 && type == 'r') {
797 /* No leading zero bits, we need an extra byte for sign extension */
798 extra = 1;
799 }
800 rb_str_modify_expand(res, numbytes + extra);
801
802 rb_len_t start = RSTRING_LEN(res);
803
804 cp = RSTRING_PTR(res) + start;
805 sign = rb_integer_pack(from, cp, numbytes, 1, 1, pack_flags);
806
807 if (extra) {
808 /* Need an extra byte */
809 cp[numbytes++] = sign < 0 ? 0x7f : 0x00;
810 }
811 rb_str_set_len(res, start + numbytes);
812
813 while (1 < numbytes) {
814 *cp |= 0x80;
815 cp++;
816 numbytes--;
817 }
818 }
819 }
820 break;
821 case 'u': /* uuencoded string */
822 case 'm': /* base64 encoded string */
823 from = NEXTFROM;
824 STR_FROM(from);
825 ptr = RSTRING_PTR(from);
826 plen = RSTRING_LEN(from);
827
828 if (len == 0 && type == 'm') {
829 encodes(res, ptr, plen, type, 0);
830 ptr += plen;
831 break;
832 }
833 if (len <= 2)
834 len = 45;
835 else if (len > 63 && type == 'u')
836 len = 63;
837 else
838 len = len / 3 * 3;
839 while (plen > 0) {
840 rb_len_t todo;
841
842 if (plen > len)
843 todo = len;
844 else
845 todo = plen;
846 encodes(res, ptr, todo, type, 1);
847 plen -= todo;
848 ptr += todo;
849 }
850 break;
851
852 case 'M': /* quoted-printable encoded string */
853 from = rb_obj_as_string(NEXTFROM);
854 NOT_BUFFER(from);
855 if (len <= 1)
856 len = 72;
857 qpencode(res, from, len);
858 break;
859
860 case 'P': /* pointer to packed byte string */
861 from = THISFROM;
862 if (!NIL_P(from)) {
863 STR_FROM(from);
864 if (RSTRING_LEN(from) < len) {
865 rb_raise(rb_eArgError, "too short buffer for P(%"PRIdLEN" for %"PRIdLEN")",
866 RSTRING_LEN(from), len);
867 }
868 }
869 len = 1;
870 /* FALL THROUGH */
871 case 'p': /* pointer to string */
872 while (len-- > 0) {
873 const char *t = 0;
874 from = NEXTFROM;
875 if (!NIL_P(from)) {
876 STR_FROM(from);
877 t = RSTRING_PTR(from);
878 }
879 if (!associates) {
880 associates = rb_ary_new();
881 }
882 rb_ary_push(associates, from);
883 rb_str_buf_cat(res, (char*)&t, sizeof(char*));
884 }
885 break;
886
887 case 'w': /* BER compressed integer */
888 while (len-- > 0) {
889 VALUE buf;
890 size_t numbytes;
891 int sign;
892 char *cp;
893
894 from = NEXTFROM;
895 from = rb_to_int(from);
896 numbytes = rb_absint_numwords(from, 7, NULL);
897 if (numbytes == 0)
898 numbytes = 1;
899 buf = rb_str_new(NULL, numbytes);
900
901 sign = rb_integer_pack(from, RSTRING_PTR(buf), RSTRING_LEN(buf), 1, 1, INTEGER_PACK_BIG_ENDIAN);
902
903 if (sign < 0)
904 rb_raise(rb_eArgError, "can't compress negative numbers");
905 if (sign == 2)
906 rb_bug("buffer size problem?");
907
908 cp = RSTRING_PTR(buf);
909 while (1 < numbytes) {
910 *cp |= 0x80;
911 cp++;
912 numbytes--;
913 }
914
915 rb_str_buf_cat(res, RSTRING_PTR(buf), RSTRING_LEN(buf));
916 }
917 break;
918
919 default: {
920 unknown_directive("pack", type, fmt);
921 break;
922 }
923 }
924 }
925
926 if (associates) {
927 str_associate(res, associates);
928 }
929 switch (enc_info) {
930 case 1:
931 ENCODING_CODERANGE_SET(res, rb_usascii_encindex(), ENC_CODERANGE_7BIT);
932 break;
933 case 2:
934 rb_enc_set_index(res, rb_utf8_encindex());
935 break;
936 default:
937 /* do nothing, keep ASCII-8BIT */
938 break;
939 }
940 return res;
941}
942
943VALUE
944rb_ec_pack_ary(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
945{
946 return pack_pack(ec, ary, fmt, buffer);
947}
948
949static const char uu_table[] =
950"`!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_";
951static const char b64_table[] =
952"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
953
954static void
955encodes(VALUE str, const char *s0, rb_len_t len, int type, int tail_lf)
956{
957 enum {buff_size = 4096, encoded_unit = 4, input_unit = 3};
958 char buff[buff_size + 1]; /* +1 for tail_lf */
959 rb_len_t i = 0;
960 const char *const trans = type == 'u' ? uu_table : b64_table;
961 char padding;
962 const unsigned char *s = (const unsigned char *)s0;
963
964 if (type == 'u') {
965 buff[i++] = (char)len + ' ';
966 padding = '`';
967 }
968 else {
969 padding = '=';
970 }
971 while (len >= input_unit) {
972 while (len >= input_unit && buff_size-i >= encoded_unit) {
973 buff[i++] = trans[077 & (*s >> 2)];
974 buff[i++] = trans[077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017))];
975 buff[i++] = trans[077 & (((s[1] << 2) & 074) | ((s[2] >> 6) & 03))];
976 buff[i++] = trans[077 & s[2]];
977 s += input_unit;
978 len -= input_unit;
979 }
980 if (buff_size-i < encoded_unit) {
981 rb_str_buf_cat(str, buff, i);
982 i = 0;
983 }
984 }
985
986 if (len == 2) {
987 buff[i++] = trans[077 & (*s >> 2)];
988 buff[i++] = trans[077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017))];
989 buff[i++] = trans[077 & (((s[1] << 2) & 074) | (('\0' >> 6) & 03))];
990 buff[i++] = padding;
991 }
992 else if (len == 1) {
993 buff[i++] = trans[077 & (*s >> 2)];
994 buff[i++] = trans[077 & (((*s << 4) & 060) | (('\0' >> 4) & 017))];
995 buff[i++] = padding;
996 buff[i++] = padding;
997 }
998 if (tail_lf) buff[i++] = '\n';
999 rb_str_buf_cat(str, buff, i);
1000 if ((size_t)i > sizeof(buff)) rb_bug("encodes() buffer overrun");
1001}
1002
1003static const char hex_table[] = "0123456789ABCDEF";
1004
1005static void
1006qpencode(VALUE str, VALUE from, rb_len_t len)
1007{
1008 char buff[1024];
1009 rb_len_t i = 0;
1010 long n = 0, prev = EOF;
1011 unsigned char *s = (unsigned char*)RSTRING_PTR(from);
1012 unsigned char *send = s + RSTRING_LEN(from);
1013
1014 while (s < send) {
1015 if ((*s > 126) ||
1016 (*s < 32 && *s != '\n' && *s != '\t') ||
1017 (*s == '=')) {
1018 buff[i++] = '=';
1019 buff[i++] = hex_table[*s >> 4];
1020 buff[i++] = hex_table[*s & 0x0f];
1021 n += 3;
1022 prev = EOF;
1023 }
1024 else if (*s == '\n') {
1025 if (prev == ' ' || prev == '\t') {
1026 buff[i++] = '=';
1027 buff[i++] = *s;
1028 }
1029 buff[i++] = *s;
1030 n = 0;
1031 prev = *s;
1032 }
1033 else {
1034 buff[i++] = *s;
1035 n++;
1036 prev = *s;
1037 }
1038 if (n > len) {
1039 buff[i++] = '=';
1040 buff[i++] = '\n';
1041 n = 0;
1042 prev = '\n';
1043 }
1044 if (i > 1024 - 5) {
1045 rb_str_buf_cat(str, buff, i);
1046 i = 0;
1047 }
1048 s++;
1049 }
1050 if (n > 0) {
1051 buff[i++] = '=';
1052 buff[i++] = '\n';
1053 }
1054 if (i > 0) {
1055 rb_str_buf_cat(str, buff, i);
1056 }
1057}
1058
1059static inline int
1060hex2num(char c)
1061{
1062 int n;
1063 n = ruby_digit36_to_number_table[(unsigned char)c];
1064 if (16 <= n)
1065 n = -1;
1066 return n;
1067}
1068
1069#define PACK_LENGTH_ADJUST_SIZE(sz) do { \
1070 tmp_len = 0; \
1071 if (mode == UNPACK_ARRAY) { \
1072 rb_ary_modify_expand(ary, len); \
1073 } \
1074 if (len > (rb_len_t)((send-s)/(sz))) { \
1075 if (!star) { \
1076 tmp_len = len-(send-s)/(sz); \
1077 } \
1078 len = (send-s)/(sz); \
1079 } \
1080} while (0)
1081
1082#define PACK_ITEM_ADJUST() do { \
1083 if (tmp_len > 0 && mode == UNPACK_ARRAY) \
1084 rb_ary_resize(ary, RARRAY_LEN(ary)+tmp_len); \
1085} while (0)
1086
1087/* Workaround for Oracle Developer Studio (Oracle Solaris Studio)
1088 * 12.4/12.5/12.6 C compiler optimization bug
1089 * with "-xO4" optimization option.
1090 */
1091#if defined(__SUNPRO_C) && 0x5130 <= __SUNPRO_C && __SUNPRO_C <= 0x5150
1092# define AVOID_CC_BUG volatile
1093#else
1094# define AVOID_CC_BUG
1095#endif
1096
1097enum unpack_mode {
1098 UNPACK_ARRAY,
1099 UNPACK_BLOCK,
1100 UNPACK_1
1101};
1102
1103static VALUE
1104pack_unpack_internal(VALUE str, VALUE fmt, VALUE ofs, enum unpack_mode mode)
1105{
1106#define hexdigits ruby_hexdigits
1107 const char *s, *send;
1108 const char *p, *pend;
1109 VALUE ary, associates = Qfalse;
1110 rb_len_t len;
1111 AVOID_CC_BUG rb_len_t tmp_len;
1112 int signed_p, integer_size, bigendian_p;
1113 rb_len_t align_base;
1114 const char *sptr;
1115 rb_len_t slen;
1116 const char *fptr;
1117 rb_len_t flen;
1118#define UNPACK_PUSH(item) do {\
1119 VALUE item_val = (item);\
1120 if ((mode) == UNPACK_BLOCK) {\
1121 rb_yield(item_val);\
1122 /* The block may have modified str and invalidated s */ \
1123 if (RSTRING_PTR(str) != sptr || RSTRING_LEN(str) != slen) {\
1124 rb_raise(rb_eRuntimeError, "string modified");\
1125 }\
1126 /* The block may have also modified fmt and invalidated p */ \
1127 if (RSTRING_PTR(fmt) != fptr || RSTRING_LEN(fmt) != flen) {\
1128 rb_raise(rb_eRuntimeError, "format string modified");\
1129 }\
1130 }\
1131 else if ((mode) == UNPACK_ARRAY) {\
1132 rb_ary_push(ary, item_val);\
1133 }\
1134 else /* if ((mode) == UNPACK_1) { */ {\
1135 return item_val; \
1136 }\
1137 } while (0)
1138
1139 StringValue(str);
1140 StringValue(fmt);
1141 rb_len_t offset = NUM2LEN(ofs);
1143
1144 len = RSTRING_LEN(str);
1145 if (offset < 0 ? (offset += len) < 0 : offset > len) {
1146 rb_raise(rb_eArgError, "offset outside of string");
1147 }
1148
1149 s = RSTRING_PTR(str);
1150 send = s + len;
1151 sptr = s;
1152 slen = len;
1153 s += offset;
1154 align_base = offset;
1155
1156 p = RSTRING_PTR(fmt);
1157 pend = p + RSTRING_LEN(fmt);
1158 fptr = p;
1159 flen = RSTRING_LEN(fmt);
1160
1161#define UNPACK_FETCH(var, type) (memcpy((var), s, sizeof(type)), s += sizeof(type))
1162
1163 ary = mode == UNPACK_ARRAY ? rb_ary_new() : Qnil;
1164 while (p < pend) {
1165 int explicit_endian = 0;
1166 const char type = *p++;
1167 size_t align = 0;
1168 int star = 0;
1169 USING_NATINT(int natint = 0); /* native integer */
1170
1171 if (skip_blank(p, type)) continue;
1172
1173 /* Directives that do not take modifiers. */
1174 if ((type == 'x' || type == '@') && p < pend && *p == '!') {
1175 p++;
1176 p = pack_alignment_size(p, pend, fmt, &align);
1177 len = pack_align_pad(s - RSTRING_PTR(str), type == '@' ? 0 : align_base, align);
1178 if (len > send - s) {
1179 rb_raise(rb_eArgError, type == '@' ? "@ outside of string" : "x outside of string");
1180 }
1181 s += len;
1182 continue;
1183 }
1184
1185 p = pack_modifiers(p, pend, type, &natint, &explicit_endian);
1186
1187 if (p >= pend)
1188 len = 1;
1189 else if (*p == '*') {
1190 star = 1;
1191 len = send - s;
1192 p++;
1193 }
1194 else if (ISDIGIT(*p)) {
1195 errno = 0;
1196 len = STRTOUL(p, (char**)&p, 10);
1197 if (len < 0 || errno) {
1198 rb_raise(rb_eRangeError, "pack length too big");
1199 }
1200 }
1201 else {
1202 len = (type != '@');
1203 }
1204
1205 switch (type) {
1206 case '%':
1207 rb_raise(rb_eArgError, "%% is not supported");
1208 break;
1209
1210 case 'A':
1211 if (len > send - s) len = send - s;
1212 {
1213 rb_len_t end = len;
1214 const char *t = s + len - 1;
1215
1216 while (t >= s) {
1217 if (*t != ' ' && *t != '\0') break;
1218 t--; len--;
1219 }
1220 UNPACK_PUSH(rb_str_new(s, len));
1221 s += end;
1222 }
1223 break;
1224
1225 case 'Z':
1226 {
1227 const char *t = s;
1228
1229 if (len > send-s) len = send-s;
1230 while (t < s+len && *t) t++;
1231 UNPACK_PUSH(rb_str_new(s, t-s));
1232 if (t < send) t++;
1233 s = star ? t : s+len;
1234 }
1235 break;
1236
1237 case 'a':
1238 if (len > send - s) len = send - s;
1239 UNPACK_PUSH(rb_str_new(s, len));
1240 s += len;
1241 break;
1242
1243 case 'b':
1244 {
1245 VALUE bitstr;
1246 char *t;
1247 int bits;
1248 rb_len_t i;
1249
1250 if (p[-1] == '*' || len > (send - s) * 8)
1251 len = (send - s) * 8;
1252 bits = 0;
1253 bitstr = rb_usascii_str_new(0, len);
1254 t = RSTRING_PTR(bitstr);
1255 for (i=0; i<len; i++) {
1256 if (i & 7) bits >>= 1;
1257 else bits = (unsigned char)*s++;
1258 *t++ = (bits & 1) ? '1' : '0';
1259 }
1260 UNPACK_PUSH(bitstr);
1261 }
1262 break;
1263
1264 case 'B':
1265 {
1266 VALUE bitstr;
1267 char *t;
1268 int bits;
1269 rb_len_t i;
1270
1271 if (p[-1] == '*' || len > (send - s) * 8)
1272 len = (send - s) * 8;
1273 bits = 0;
1274 bitstr = rb_usascii_str_new(0, len);
1275 t = RSTRING_PTR(bitstr);
1276 for (i=0; i<len; i++) {
1277 if (i & 7) bits <<= 1;
1278 else bits = (unsigned char)*s++;
1279 *t++ = (bits & 128) ? '1' : '0';
1280 }
1281 UNPACK_PUSH(bitstr);
1282 }
1283 break;
1284
1285 case 'h':
1286 {
1287 VALUE bitstr;
1288 char *t;
1289 int bits;
1290 rb_len_t i;
1291
1292 if (p[-1] == '*' || len > (send - s) * 2)
1293 len = (send - s) * 2;
1294 bits = 0;
1295 bitstr = rb_usascii_str_new(0, len);
1296 t = RSTRING_PTR(bitstr);
1297 for (i=0; i<len; i++) {
1298 if (i & 1)
1299 bits >>= 4;
1300 else
1301 bits = (unsigned char)*s++;
1302 *t++ = hexdigits[bits & 15];
1303 }
1304 UNPACK_PUSH(bitstr);
1305 }
1306 break;
1307
1308 case 'H':
1309 {
1310 VALUE bitstr;
1311 char *t;
1312 int bits;
1313 rb_len_t i;
1314
1315 if (p[-1] == '*' || len > (send - s) * 2)
1316 len = (send - s) * 2;
1317 bits = 0;
1318 bitstr = rb_usascii_str_new(0, len);
1319 t = RSTRING_PTR(bitstr);
1320 for (i=0; i<len; i++) {
1321 if (i & 1)
1322 bits <<= 4;
1323 else
1324 bits = (unsigned char)*s++;
1325 *t++ = hexdigits[(bits >> 4) & 15];
1326 }
1327 UNPACK_PUSH(bitstr);
1328 }
1329 break;
1330
1331 case 'c':
1332 signed_p = 1;
1333 integer_size = 1;
1334 bigendian_p = BIGENDIAN_P(); /* not effective */
1335 goto unpack_integer;
1336
1337 case 'C':
1338 signed_p = 0;
1339 integer_size = 1;
1340 bigendian_p = BIGENDIAN_P(); /* not effective */
1341 goto unpack_integer;
1342
1343 case 's':
1344 signed_p = 1;
1345 integer_size = NATINT_LEN(short, 2);
1346 bigendian_p = BIGENDIAN_P();
1347 goto unpack_integer;
1348
1349 case 'S':
1350 signed_p = 0;
1351 integer_size = NATINT_LEN(short, 2);
1352 bigendian_p = BIGENDIAN_P();
1353 goto unpack_integer;
1354
1355 case 'i':
1356 signed_p = 1;
1357 integer_size = (int)sizeof(int);
1358 bigendian_p = BIGENDIAN_P();
1359 goto unpack_integer;
1360
1361 case 'I':
1362 signed_p = 0;
1363 integer_size = (int)sizeof(int);
1364 bigendian_p = BIGENDIAN_P();
1365 goto unpack_integer;
1366
1367 case 'l':
1368 signed_p = 1;
1369 integer_size = NATINT_LEN(long, 4);
1370 bigendian_p = BIGENDIAN_P();
1371 goto unpack_integer;
1372
1373 case 'L':
1374 signed_p = 0;
1375 integer_size = NATINT_LEN(long, 4);
1376 bigendian_p = BIGENDIAN_P();
1377 goto unpack_integer;
1378
1379 case 'q':
1380 signed_p = 1;
1381 integer_size = NATINT_LEN_Q;
1382 bigendian_p = BIGENDIAN_P();
1383 goto unpack_integer;
1384
1385 case 'Q':
1386 signed_p = 0;
1387 integer_size = NATINT_LEN_Q;
1388 bigendian_p = BIGENDIAN_P();
1389 goto unpack_integer;
1390
1391 case 'j':
1392 signed_p = 1;
1393 integer_size = sizeof(intptr_t);
1394 bigendian_p = BIGENDIAN_P();
1395 goto unpack_integer;
1396
1397 case 'J':
1398 signed_p = 0;
1399 integer_size = sizeof(uintptr_t);
1400 bigendian_p = BIGENDIAN_P();
1401 goto unpack_integer;
1402
1403 case 'n':
1404 signed_p = 0;
1405 integer_size = 2;
1406 bigendian_p = 1;
1407 goto unpack_integer;
1408
1409 case 'N':
1410 signed_p = 0;
1411 integer_size = 4;
1412 bigendian_p = 1;
1413 goto unpack_integer;
1414
1415 case 'v':
1416 signed_p = 0;
1417 integer_size = 2;
1418 bigendian_p = 0;
1419 goto unpack_integer;
1420
1421 case 'V':
1422 signed_p = 0;
1423 integer_size = 4;
1424 bigendian_p = 0;
1425 goto unpack_integer;
1426
1427 unpack_integer:
1428 if (explicit_endian) {
1429 bigendian_p = explicit_endian == '>';
1430 }
1431 PACK_LENGTH_ADJUST_SIZE(integer_size);
1432 while (len-- > 0) {
1433 int flags = bigendian_p ? INTEGER_PACK_BIG_ENDIAN : INTEGER_PACK_LITTLE_ENDIAN;
1434 VALUE val;
1435 if (signed_p)
1436 flags |= INTEGER_PACK_2COMP;
1437 val = rb_integer_unpack(s, integer_size, 1, 0, flags);
1438 UNPACK_PUSH(val);
1439 s += integer_size;
1440 }
1441 PACK_ITEM_ADJUST();
1442 break;
1443
1444 case 'f':
1445 case 'F':
1446 PACK_LENGTH_ADJUST_SIZE(sizeof(float));
1447 while (len-- > 0) {
1448 float tmp;
1449 UNPACK_FETCH(&tmp, float);
1450 UNPACK_PUSH(DBL2NUM((double)tmp));
1451 }
1452 PACK_ITEM_ADJUST();
1453 break;
1454
1455 case 'e':
1456 PACK_LENGTH_ADJUST_SIZE(sizeof(float));
1457 while (len-- > 0) {
1458 FLOAT_CONVWITH(tmp);
1459 UNPACK_FETCH(tmp.buf, float);
1460 VTOHF(tmp);
1461 UNPACK_PUSH(DBL2NUM(tmp.f));
1462 }
1463 PACK_ITEM_ADJUST();
1464 break;
1465
1466 case 'E':
1467 PACK_LENGTH_ADJUST_SIZE(sizeof(double));
1468 while (len-- > 0) {
1469 DOUBLE_CONVWITH(tmp);
1470 UNPACK_FETCH(tmp.buf, double);
1471 VTOHD(tmp);
1472 UNPACK_PUSH(DBL2NUM(tmp.d));
1473 }
1474 PACK_ITEM_ADJUST();
1475 break;
1476
1477 case 'D':
1478 case 'd':
1479 PACK_LENGTH_ADJUST_SIZE(sizeof(double));
1480 while (len-- > 0) {
1481 double tmp;
1482 UNPACK_FETCH(&tmp, double);
1483 UNPACK_PUSH(DBL2NUM(tmp));
1484 }
1485 PACK_ITEM_ADJUST();
1486 break;
1487
1488 case 'g':
1489 PACK_LENGTH_ADJUST_SIZE(sizeof(float));
1490 while (len-- > 0) {
1491 FLOAT_CONVWITH(tmp);
1492 UNPACK_FETCH(tmp.buf, float);
1493 NTOHF(tmp);
1494 UNPACK_PUSH(DBL2NUM(tmp.f));
1495 }
1496 PACK_ITEM_ADJUST();
1497 break;
1498
1499 case 'G':
1500 PACK_LENGTH_ADJUST_SIZE(sizeof(double));
1501 while (len-- > 0) {
1502 DOUBLE_CONVWITH(tmp);
1503 UNPACK_FETCH(tmp.buf, double);
1504 NTOHD(tmp);
1505 UNPACK_PUSH(DBL2NUM(tmp.d));
1506 }
1507 PACK_ITEM_ADJUST();
1508 break;
1509
1510 case 'U':
1511 if (len > send - s) len = send - s;
1512 while (len > 0 && s < send) {
1513 rb_len_t alen = send - s;
1514 unsigned long l;
1515
1516 l = utf8_to_uv(s, &alen);
1517 s += alen; len--;
1518 UNPACK_PUSH(ULONG2NUM(l));
1519 }
1520 break;
1521
1522 case 'u':
1523 {
1524 VALUE buf = rb_str_new(0, (send - s)*3/4);
1525 char *ptr = RSTRING_PTR(buf);
1526 rb_len_t total = 0;
1527
1528 while (s < send && (unsigned char)*s > ' ' && (unsigned char)*s < 'a') {
1529 long a,b,c,d;
1530 char hunk[3];
1531
1532 len = ((unsigned char)*s++ - ' ') & 077;
1533
1534 total += len;
1535 if (total > RSTRING_LEN(buf)) {
1536 len -= total - RSTRING_LEN(buf);
1537 total = RSTRING_LEN(buf);
1538 }
1539
1540 while (len > 0) {
1541 rb_len_t mlen = len > 3 ? 3 : len;
1542
1543 if (s < send && (unsigned char)*s >= ' ' && (unsigned char)*s < 'a')
1544 a = ((unsigned char)*s++ - ' ') & 077;
1545 else
1546 a = 0;
1547 if (s < send && (unsigned char)*s >= ' ' && (unsigned char)*s < 'a')
1548 b = ((unsigned char)*s++ - ' ') & 077;
1549 else
1550 b = 0;
1551 if (s < send && (unsigned char)*s >= ' ' && (unsigned char)*s < 'a')
1552 c = ((unsigned char)*s++ - ' ') & 077;
1553 else
1554 c = 0;
1555 if (s < send && (unsigned char)*s >= ' ' && (unsigned char)*s < 'a')
1556 d = ((unsigned char)*s++ - ' ') & 077;
1557 else
1558 d = 0;
1559 hunk[0] = (char)(a << 2 | b >> 4);
1560 hunk[1] = (char)(b << 4 | c >> 2);
1561 hunk[2] = (char)(c << 6 | d);
1562 memcpy(ptr, hunk, mlen);
1563 ptr += mlen;
1564 len -= mlen;
1565 }
1566 if (s < send && (unsigned char)*s != '\r' && *s != '\n')
1567 s++; /* possible checksum byte */
1568 if (s < send && *s == '\r') s++;
1569 if (s < send && *s == '\n') s++;
1570 }
1571
1572 rb_str_set_len(buf, total);
1573 UNPACK_PUSH(buf);
1574 }
1575 break;
1576
1577 case 'm':
1578 {
1579 VALUE buf = rb_str_new(0, (send - s + 3)*3/4); /* +3 is for skipping paddings */
1580 char *ptr = RSTRING_PTR(buf);
1581 int a = -1,b = -1,c = 0,d = 0;
1582 static signed char b64_xtable[256];
1583
1584 if (b64_xtable['/'] <= 0) {
1585 int i;
1586
1587 for (i = 0; i < 256; i++) {
1588 b64_xtable[i] = -1;
1589 }
1590 for (i = 0; i < 64; i++) {
1591 b64_xtable[(unsigned char)b64_table[i]] = (char)i;
1592 }
1593 }
1594 if (len == 0) {
1595 while (s < send) {
1596 a = b = c = d = -1;
1597 a = b64_xtable[(unsigned char)*s++];
1598 if (s >= send || a == -1) rb_raise(rb_eArgError, "invalid base64");
1599 b = b64_xtable[(unsigned char)*s++];
1600 if (s >= send || b == -1) rb_raise(rb_eArgError, "invalid base64");
1601 if (*s == '=') {
1602 if (s + 2 == send && *(s + 1) == '=') break;
1603 rb_raise(rb_eArgError, "invalid base64");
1604 }
1605 c = b64_xtable[(unsigned char)*s++];
1606 if (s >= send || c == -1) rb_raise(rb_eArgError, "invalid base64");
1607 if (s + 1 == send && *s == '=') break;
1608 d = b64_xtable[(unsigned char)*s++];
1609 if (d == -1) rb_raise(rb_eArgError, "invalid base64");
1610 *ptr++ = castchar(a << 2 | b >> 4);
1611 *ptr++ = castchar(b << 4 | c >> 2);
1612 *ptr++ = castchar(c << 6 | d);
1613 }
1614 if (c == -1) {
1615 *ptr++ = castchar(a << 2 | b >> 4);
1616 if (b & 0xf) rb_raise(rb_eArgError, "invalid base64");
1617 }
1618 else if (d == -1) {
1619 *ptr++ = castchar(a << 2 | b >> 4);
1620 *ptr++ = castchar(b << 4 | c >> 2);
1621 if (c & 0x3) rb_raise(rb_eArgError, "invalid base64");
1622 }
1623 }
1624 else {
1625 while (s < send) {
1626 a = b = c = d = -1;
1627 while ((a = b64_xtable[(unsigned char)*s]) == -1 && s < send) {s++;}
1628 if (s >= send) break;
1629 s++;
1630 while ((b = b64_xtable[(unsigned char)*s]) == -1 && s < send) {s++;}
1631 if (s >= send) break;
1632 s++;
1633 while ((c = b64_xtable[(unsigned char)*s]) == -1 && s < send) {if (*s == '=') break; s++;}
1634 if (*s == '=' || s >= send) break;
1635 s++;
1636 while ((d = b64_xtable[(unsigned char)*s]) == -1 && s < send) {if (*s == '=') break; s++;}
1637 if (*s == '=' || s >= send) break;
1638 s++;
1639 *ptr++ = castchar(a << 2 | b >> 4);
1640 *ptr++ = castchar(b << 4 | c >> 2);
1641 *ptr++ = castchar(c << 6 | d);
1642 a = -1;
1643 }
1644 if (a != -1 && b != -1) {
1645 if (c == -1)
1646 *ptr++ = castchar(a << 2 | b >> 4);
1647 else {
1648 *ptr++ = castchar(a << 2 | b >> 4);
1649 *ptr++ = castchar(b << 4 | c >> 2);
1650 }
1651 }
1652 }
1653 rb_str_set_len(buf, ptr - RSTRING_PTR(buf));
1654 UNPACK_PUSH(buf);
1655 }
1656 break;
1657
1658 case 'M':
1659 {
1660 VALUE buf = rb_str_new(0, send - s);
1661 char *ptr = RSTRING_PTR(buf);
1662 const char *ss = s;
1663 int csum = 0;
1664 int c1, c2;
1665
1666 while (s < send) {
1667 if (*s == '=') {
1668 if (++s == send) break;
1669 if (s+1 < send && *s == '\r' && *(s+1) == '\n')
1670 s++;
1671 if (*s != '\n') {
1672 if ((c1 = hex2num(*s)) == -1) break;
1673 if (++s == send) break;
1674 if ((c2 = hex2num(*s)) == -1) break;
1675 csum |= *ptr++ = castchar(c1 << 4 | c2);
1676 }
1677 }
1678 else {
1679 csum |= *ptr++ = *s;
1680 }
1681 s++;
1682 ss = s;
1683 }
1684 rb_str_set_len(buf, ptr - RSTRING_PTR(buf));
1685 rb_str_buf_cat(buf, ss, send-ss);
1687 ENCODING_CODERANGE_SET(buf, rb_ascii8bit_encindex(), csum);
1688 UNPACK_PUSH(buf);
1689 }
1690 break;
1691
1692 case '@':
1693 if (len > RSTRING_LEN(str))
1694 rb_raise(rb_eArgError, "@ outside of string");
1695 s = RSTRING_PTR(str) + len;
1696 break;
1697
1698 case 'X':
1699 if (len > s - RSTRING_PTR(str))
1700 rb_raise(rb_eArgError, "X outside of string");
1701 s -= len;
1702 break;
1703
1704 case 'x':
1705 if (len > send - s)
1706 rb_raise(rb_eArgError, "x outside of string");
1707 s += len;
1708 break;
1709
1710 case '^':
1711 UNPACK_PUSH(SSIZET2NUM(s - RSTRING_PTR(str)));
1712 break;
1713
1714 case 'P':
1715 if (sizeof(char *) <= (size_t)(send - s)) {
1716 VALUE tmp = Qnil;
1717 const char *t;
1718
1719 UNPACK_FETCH(&t, char *);
1720 if (t) {
1721 if (!associates) associates = str_associated(str);
1722 tmp = associated_pointer(associates, t);
1723 if (len < RSTRING_LEN(tmp)) {
1724 tmp = rb_str_new(t, len);
1725 str_associate(tmp, associates);
1726 }
1727 }
1728 UNPACK_PUSH(tmp);
1729 }
1730 break;
1731
1732 case 'p':
1733 if (len > (rb_len_t)((send - s) / sizeof(char *)))
1734 len = (send - s) / sizeof(char *);
1735 while (len-- > 0) {
1736 if ((size_t)(send - s) < sizeof(char *))
1737 break;
1738 else {
1739 VALUE tmp = Qnil;
1740 const char *t;
1741
1742 UNPACK_FETCH(&t, char *);
1743 if (t) {
1744 if (!associates) associates = str_associated(str);
1745 tmp = associated_pointer(associates, t);
1746 }
1747 UNPACK_PUSH(tmp);
1748 }
1749 }
1750 break;
1751
1752 case 'r':
1753 case 'R':
1754 {
1755 int pack_flags = INTEGER_PACK_LITTLE_ENDIAN;
1756
1757 if (type == 'r') {
1758 pack_flags |= INTEGER_PACK_2COMP;
1759 }
1760 const char *s0 = s;
1761 while (len > 0 && s < send) {
1762 if (*s & 0x80) {
1763 s++;
1764 }
1765 else {
1766 s++;
1767 UNPACK_PUSH(rb_integer_unpack(s0, s-s0, 1, 1, pack_flags));
1768 len--;
1769 s0 = s;
1770 }
1771 }
1772 /* Handle incomplete value and remaining expected values with nil (only if not using *) */
1773 if (!star) {
1774 if (s0 != s && len > 0) {
1775 UNPACK_PUSH(Qnil);
1776 len--;
1777 }
1778 while (len-- > 0) {
1779 UNPACK_PUSH(Qnil);
1780 }
1781 }
1782 }
1783 break;
1784
1785 case 'w':
1786 {
1787 const char *s0 = s;
1788 while (len > 0 && s < send) {
1789 if (*s & 0x80) {
1790 s++;
1791 }
1792 else {
1793 s++;
1794 UNPACK_PUSH(rb_integer_unpack(s0, s-s0, 1, 1, INTEGER_PACK_BIG_ENDIAN));
1795 len--;
1796 s0 = s;
1797 }
1798 }
1799 }
1800 break;
1801
1802 default:
1803 unknown_directive("unpack", type, fmt);
1804 break;
1805 }
1806 }
1807
1808 return ary;
1809}
1810
1811static VALUE
1812pack_unpack(rb_execution_context_t *ec, VALUE str, VALUE fmt, VALUE offset)
1813{
1814 enum unpack_mode mode = rb_block_given_p() ? UNPACK_BLOCK : UNPACK_ARRAY;
1815 return pack_unpack_internal(str, fmt, offset, mode);
1816}
1817
1818static VALUE
1819pack_unpack1(rb_execution_context_t *ec, VALUE str, VALUE fmt, VALUE offset)
1820{
1821 return pack_unpack_internal(str, fmt, offset, UNPACK_1);
1822}
1823
1824int
1825rb_uv_to_utf8(char buf[6], unsigned long uv)
1826{
1827 if (uv <= 0x7f) {
1828 buf[0] = (char)uv;
1829 return 1;
1830 }
1831 if (uv <= 0x7ff) {
1832 buf[0] = castchar(((uv>>6)&0xff)|0xc0);
1833 buf[1] = castchar((uv&0x3f)|0x80);
1834 return 2;
1835 }
1836 if (uv <= 0xffff) {
1837 buf[0] = castchar(((uv>>12)&0xff)|0xe0);
1838 buf[1] = castchar(((uv>>6)&0x3f)|0x80);
1839 buf[2] = castchar((uv&0x3f)|0x80);
1840 return 3;
1841 }
1842 if (uv <= 0x1fffff) {
1843 buf[0] = castchar(((uv>>18)&0xff)|0xf0);
1844 buf[1] = castchar(((uv>>12)&0x3f)|0x80);
1845 buf[2] = castchar(((uv>>6)&0x3f)|0x80);
1846 buf[3] = castchar((uv&0x3f)|0x80);
1847 return 4;
1848 }
1849 if (uv <= 0x3ffffff) {
1850 buf[0] = castchar(((uv>>24)&0xff)|0xf8);
1851 buf[1] = castchar(((uv>>18)&0x3f)|0x80);
1852 buf[2] = castchar(((uv>>12)&0x3f)|0x80);
1853 buf[3] = castchar(((uv>>6)&0x3f)|0x80);
1854 buf[4] = castchar((uv&0x3f)|0x80);
1855 return 5;
1856 }
1857 if (uv <= 0x7fffffff) {
1858 buf[0] = castchar(((uv>>30)&0xff)|0xfc);
1859 buf[1] = castchar(((uv>>24)&0x3f)|0x80);
1860 buf[2] = castchar(((uv>>18)&0x3f)|0x80);
1861 buf[3] = castchar(((uv>>12)&0x3f)|0x80);
1862 buf[4] = castchar(((uv>>6)&0x3f)|0x80);
1863 buf[5] = castchar((uv&0x3f)|0x80);
1864 return 6;
1865 }
1866 rb_raise(rb_eRangeError, "pack(U): value out of range");
1867
1869}
1870
1871static const unsigned long utf8_limits[] = {
1872 0x0, /* 1 */
1873 0x80, /* 2 */
1874 0x800, /* 3 */
1875 0x10000, /* 4 */
1876 0x200000, /* 5 */
1877 0x4000000, /* 6 */
1878 0x80000000, /* 7 */
1879};
1880
1881static unsigned long
1882utf8_to_uv(const char *p, rb_len_t *lenp)
1883{
1884 int c = *p++ & 0xff;
1885 unsigned long uv = c;
1886 rb_len_t n;
1887
1888 if (!(uv & 0x80)) {
1889 *lenp = 1;
1890 return uv;
1891 }
1892 if (!(uv & 0x40)) {
1893 *lenp = 1;
1894 rb_raise(rb_eArgError, "malformed UTF-8 character");
1895 }
1896
1897 if (!(uv & 0x20)) { n = 2; uv &= 0x1f; }
1898 else if (!(uv & 0x10)) { n = 3; uv &= 0x0f; }
1899 else if (!(uv & 0x08)) { n = 4; uv &= 0x07; }
1900 else if (!(uv & 0x04)) { n = 5; uv &= 0x03; }
1901 else if (!(uv & 0x02)) { n = 6; uv &= 0x01; }
1902 else {
1903 *lenp = 1;
1904 rb_raise(rb_eArgError, "malformed UTF-8 character");
1905 }
1906 if (n > *lenp) {
1907 rb_raise(rb_eArgError, "malformed UTF-8 character (expected %"PRIdLEN" bytes, given %"PRIdLEN" bytes)",
1908 n, *lenp);
1909 }
1910 *lenp = n--;
1911 if (n != 0) {
1912 while (n--) {
1913 c = *p++ & 0xff;
1914 if ((c & 0xc0) != 0x80) {
1915 *lenp -= n + 1;
1916 rb_raise(rb_eArgError, "malformed UTF-8 character");
1917 }
1918 else {
1919 c &= 0x3f;
1920 uv = uv << 6 | c;
1921 }
1922 }
1923 }
1924 n = *lenp - 1;
1925 if (uv < utf8_limits[n]) {
1926 rb_raise(rb_eArgError, "redundant UTF-8 sequence");
1927 }
1928 return uv;
1929}
1930
1931#include "pack.rbinc"
1932
1933void
1934Init_pack(void)
1935{
1936 id_associated = rb_make_internal_id();
1937}
#define RUBY_ALIGNOF
Wraps (or simulates) alignof.
Definition stdalign.h:28
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:1035
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
Definition coderange.h:181
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define ULONG2NUM
Old name of RB_ULONG2NUM.
Definition long.h:60
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
Definition size_t.h:64
#define STRTOUL
Old name of ruby_strtoul.
Definition ctype.h:104
#define ISDIGIT
Old name of rb_isdigit.
Definition ctype.h:93
#define ISALPHA
Old name of rb_isalpha.
Definition ctype.h:92
#define ISASCII
Old name of rb_isascii.
Definition ctype.h:85
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define NIL_P
Old name of RB_NIL_P.
#define DBL2NUM
Old name of rb_float_new.
Definition double.h:29
#define ISPRINT
Old name of rb_isprint.
Definition ctype.h:86
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define NUM2LEN
Old name of RB_NUM2LEN.
Definition len_t.h:34
#define ENCODING_CODERANGE_SET(obj, encindex, cr)
Old name of RB_ENCODING_CODERANGE_SET.
Definition coderange.h:189
VALUE rb_eRangeError
RangeError exception.
Definition error.c:1461
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1457
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1455
VALUE rb_to_float(VALUE val)
Identical to rb_check_to_float(), except it raises on error.
Definition object.c:3793
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3347
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
#define INTEGER_PACK_LITTLE_ENDIAN
Little endian combination.
Definition bignum.h:571
#define INTEGER_PACK_BIG_ENDIAN
Big endian combination.
Definition bignum.h:576
int rb_uv_to_utf8(char buf[6], unsigned long uv)
Encodes a Unicode codepoint into its UTF-8 representation.
Definition pack.c:1825
#define INTEGER_PACK_2COMP
Uses 2's complement representation.
Definition bignum.h:553
void rb_str_modify_expand(VALUE str, rb_len_t capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
Definition string.c:2841
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1523
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1706
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1557
void rb_str_set_len(VALUE str, rb_len_t len)
Overwrites the length of the string.
Definition string.c:3525
void rb_must_asciicompat(VALUE obj)
Asserts that the given string's encoding is (Ruby's definition of) ASCII compatible.
Definition string.c:2887
VALUE rb_str_buf_new(rb_len_t capa)
Allocates a "string buffer".
Definition string.c:1783
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
Definition string.c:1916
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition variable.c:2150
int len
Length of the buffer.
Definition io.h:8
const signed char ruby_digit36_to_number_table[]
Character to number mapping like ‘'a’->10,'b'->11etc.
Definition util.c:56
VALUE type(ANYARGS)
ANYARGS-ed function type.
#define RBIMPL_ATTR_NORETURN()
Wraps (or simulates) [[noreturn]]
Definition noreturn.h:38
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:50
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:51
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
Definition rstring.h:409
const char * rb_obj_classname(VALUE obj)
Queries the name of the class of the passed object.
Definition variable.c:531
#define errno
Ractor-aware version of errno.
Definition ruby.h:388
long rb_len_t
A signed integer type for lengths and indices of objects such as String and Array.
Definition value.h:142
#define RB_LEN_MAX
Maximum possible value that a rb_len_t can take.
Definition value.h:156
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition value.h:63
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376