Ruby 4.1.0dev (2026-09-21 revision 8befacf9e6c898a0f79dcb53bdd2e4cea24e0d1c)
pack.c (8befacf9e6c898a0f79dcb53bdd2e4cea24e0d1c)
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 NEXTSTEP and 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*,long,int,int);
123static void qpencode(VALUE,VALUE,long);
124
125static unsigned long utf8_to_uv(const char*,long*);
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, long len)
198{
199 long 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 long
287pack_align_pad(long pos, long base, size_t alignment)
288{
289 long offset, mod;
290
291 if (alignment <= 1) return 0;
292 if (alignment > LONG_MAX) rb_raise(rb_eRangeError, "alignment too big");
293 offset = pos - base;
294 mod = offset % (long)alignment;
295 if (mod < 0) mod += alignment;
296 return mod ? (long)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 long 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 long 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 if (RSTRING_END(fmt) != pend) {
375 rb_raise(rb_eRuntimeError, "format string modified");
376 }
377 const char type = *p++; /* get data type */
378 USING_NATINT(int natint = 0); /* native integer */
379
380 if (skip_blank(p, type)) continue;
381
382 /* Directives that do not take modifiers. */
383 if ((type == 'x' || type == '@') && p < pend && *p == '!') {
384 p++;
385 p = pack_alignment_size(p, pend, fmt, &align);
386 len = pack_align_pad(RSTRING_LEN(res), type == '@' ? 0 : align_base, align);
388 str_expand_fill(res, '\0', len);
389 continue;
390 }
391
392 p = pack_modifiers(p, pend, type, &natint, &explicit_endian);
393
394 if (*p == '*') { /* set data length */
395 len = strchr("@Xxu", type) ? 0
396 : strchr("PMm", type) ? 1
397 : RARRAY_LEN(ary) - idx;
398 p++;
399 }
400 else if (ISDIGIT(*p)) {
401 errno = 0;
402 len = STRTOUL(p, (char**)&p, 10);
403 if (len < 0 || errno) {
404 rb_raise(rb_eRangeError, "pack length too big");
405 }
406 }
407 else {
408 len = 1;
409 }
410
411 switch (type) {
412 case 'U':
413 /* if encoding is US-ASCII, upgrade to UTF-8 */
414 if (enc_info == 1) enc_info = 2;
415 break;
416 case 'm': case 'M': case 'u':
417 /* keep US-ASCII (do nothing) */
418 break;
419 default:
420 /* fall back to BINARY */
421 enc_info = 0;
422 break;
423 }
424 switch (type) {
425 case 'A': case 'a': case 'Z':
426 case 'B': case 'b':
427 case 'H': case 'h':
428 from = NEXTFROM;
429 if (NIL_P(from)) {
430 ptr = "";
431 plen = 0;
432 }
433 else {
434 STR_FROM(from);
435 ptr = RSTRING_PTR(from);
436 plen = RSTRING_LEN(from);
437 }
438
439 if (p[-1] == '*')
440 len = plen;
441
442 switch (type) {
443 case 'a': /* arbitrary binary string (null padded) */
444 case 'A': /* arbitrary binary string (ASCII space padded) */
445 case 'Z': /* null terminated string */
446 if (plen >= len) {
447 rb_str_buf_cat(res, ptr, len);
448 if (p[-1] == '*' && type == 'Z')
449 rb_str_buf_cat(res, "", 1);
450 }
451 else {
453 rb_str_buf_cat(res, ptr, plen);
454 str_expand_fill(res, (type == 'A' ? ' ' : '\0'), len - plen);
455 }
456 break;
457
458#define castchar(from) (char)((from) & 0xff)
459
460 case 'b': /* bit string (ascending) */
461 {
462 int byte = 0;
463 long i, j = 0;
464
465 if (len > plen) {
466 j = (len - plen + 1)/2;
467 len = plen;
468 }
469 for (i=0; i++ < len; ptr++) {
470 if (*ptr & 1)
471 byte |= 128;
472 if (i & 7)
473 byte >>= 1;
474 else {
475 char c = castchar(byte);
476 rb_str_buf_cat(res, &c, 1);
477 byte = 0;
478 }
479 }
480 if (len & 7) {
481 char c;
482 byte >>= 7 - (len & 7);
483 c = castchar(byte);
484 rb_str_buf_cat(res, &c, 1);
485 }
486 len = j;
487 goto grow;
488 }
489 break;
490
491 case 'B': /* bit string (descending) */
492 {
493 int byte = 0;
494 long i, j = 0;
495
496 if (len > plen) {
497 j = (len - plen + 1)/2;
498 len = plen;
499 }
500 for (i=0; i++ < len; ptr++) {
501 byte |= *ptr & 1;
502 if (i & 7)
503 byte <<= 1;
504 else {
505 char c = castchar(byte);
506 rb_str_buf_cat(res, &c, 1);
507 byte = 0;
508 }
509 }
510 if (len & 7) {
511 char c;
512 byte <<= 7 - (len & 7);
513 c = castchar(byte);
514 rb_str_buf_cat(res, &c, 1);
515 }
516 len = j;
517 goto grow;
518 }
519 break;
520
521 case 'h': /* hex string (low nibble first) */
522 {
523 int byte = 0;
524 long i, j = 0;
525
526 if (len > plen) {
527 j = (len + 1) / 2 - (plen + 1) / 2;
528 len = plen;
529 }
530 for (i=0; i++ < len; ptr++) {
531 if (ISALPHA(*ptr))
532 byte |= (((*ptr & 15) + 9) & 15) << 4;
533 else
534 byte |= (*ptr & 15) << 4;
535 if (i & 1)
536 byte >>= 4;
537 else {
538 char c = castchar(byte);
539 rb_str_buf_cat(res, &c, 1);
540 byte = 0;
541 }
542 }
543 if (len & 1) {
544 char c = castchar(byte);
545 rb_str_buf_cat(res, &c, 1);
546 }
547 len = j;
548 goto grow;
549 }
550 break;
551
552 case 'H': /* hex string (high nibble first) */
553 {
554 int byte = 0;
555 long i, j = 0;
556
557 if (len > plen) {
558 j = (len + 1) / 2 - (plen + 1) / 2;
559 len = plen;
560 }
561 for (i=0; i++ < len; ptr++) {
562 if (ISALPHA(*ptr))
563 byte |= ((*ptr & 15) + 9) & 15;
564 else
565 byte |= *ptr & 15;
566 if (i & 1)
567 byte <<= 4;
568 else {
569 char c = castchar(byte);
570 rb_str_buf_cat(res, &c, 1);
571 byte = 0;
572 }
573 }
574 if (len & 1) {
575 char c = castchar(byte);
576 rb_str_buf_cat(res, &c, 1);
577 }
578 len = j;
579 goto grow;
580 }
581 break;
582 }
583 break;
584
585 case 'c': /* signed char */
586 case 'C': /* unsigned char */
587 integer_size = 1;
588 bigendian_p = BIGENDIAN_P(); /* not effective */
589 goto pack_integer;
590
591 case 's': /* s for int16_t, s! for signed short */
592 case 'S': /* S for uint16_t, S! for unsigned short */
593 integer_size = NATINT_LEN(short, 2);
594 bigendian_p = BIGENDIAN_P();
595 goto pack_integer;
596
597 case 'i': /* i and i! for signed int */
598 case 'I': /* I and I! for unsigned int */
599 integer_size = (int)sizeof(int);
600 bigendian_p = BIGENDIAN_P();
601 goto pack_integer;
602
603 case 'l': /* l for int32_t, l! for signed long */
604 case 'L': /* L for uint32_t, L! for unsigned long */
605 integer_size = NATINT_LEN(long, 4);
606 bigendian_p = BIGENDIAN_P();
607 goto pack_integer;
608
609 case 'q': /* q for int64_t, q! for signed long long */
610 case 'Q': /* Q for uint64_t, Q! for unsigned long long */
611 integer_size = NATINT_LEN_Q;
612 bigendian_p = BIGENDIAN_P();
613 goto pack_integer;
614
615 case 'j': /* j for intptr_t */
616 integer_size = sizeof(intptr_t);
617 bigendian_p = BIGENDIAN_P();
618 goto pack_integer;
619
620 case 'J': /* J for uintptr_t */
621 integer_size = sizeof(uintptr_t);
622 bigendian_p = BIGENDIAN_P();
623 goto pack_integer;
624
625 case 'n': /* 16 bit (2 bytes) integer (network byte-order) */
626 integer_size = 2;
627 bigendian_p = 1;
628 goto pack_integer;
629
630 case 'N': /* 32 bit (4 bytes) integer (network byte-order) */
631 integer_size = 4;
632 bigendian_p = 1;
633 goto pack_integer;
634
635 case 'v': /* 16 bit (2 bytes) integer (VAX byte-order) */
636 integer_size = 2;
637 bigendian_p = 0;
638 goto pack_integer;
639
640 case 'V': /* 32 bit (4 bytes) integer (VAX byte-order) */
641 integer_size = 4;
642 bigendian_p = 0;
643 goto pack_integer;
644
645 pack_integer:
646 if (explicit_endian) {
647 bigendian_p = explicit_endian == '>';
648 }
649 if (integer_size > MAX_INTEGER_PACK_SIZE)
650 rb_bug("unexpected integer size for pack: %d", integer_size);
651 while (len-- > 0) {
652 char intbuf[MAX_INTEGER_PACK_SIZE];
653
654 from = NEXTFROM;
655 rb_integer_pack(from, intbuf, integer_size, 1, 0,
658 rb_str_buf_cat(res, intbuf, integer_size);
659 }
660 break;
661
662 case 'f': /* single precision float in native format */
663 case 'F': /* ditto */
664 while (len-- > 0) {
665 float f;
666
667 from = NEXTFROM;
668 f = VALUE_to_float(from);
669 rb_str_buf_cat(res, (char*)&f, sizeof(float));
670 }
671 break;
672
673 case 'e': /* single precision float in VAX byte-order */
674 while (len-- > 0) {
675 FLOAT_CONVWITH(tmp);
676
677 from = NEXTFROM;
678 tmp.f = VALUE_to_float(from);
679 HTOVF(tmp);
680 rb_str_buf_cat(res, tmp.buf, sizeof(float));
681 }
682 break;
683
684 case 'E': /* double precision float in VAX byte-order */
685 while (len-- > 0) {
686 DOUBLE_CONVWITH(tmp);
687 from = NEXTFROM;
688 tmp.d = RFLOAT_VALUE(rb_to_float(from));
689 HTOVD(tmp);
690 rb_str_buf_cat(res, tmp.buf, sizeof(double));
691 }
692 break;
693
694 case 'd': /* double precision float in native format */
695 case 'D': /* ditto */
696 while (len-- > 0) {
697 double d;
698
699 from = NEXTFROM;
700 d = RFLOAT_VALUE(rb_to_float(from));
701 rb_str_buf_cat(res, (char*)&d, sizeof(double));
702 }
703 break;
704
705 case 'g': /* single precision float in network byte-order */
706 while (len-- > 0) {
707 FLOAT_CONVWITH(tmp);
708 from = NEXTFROM;
709 tmp.f = VALUE_to_float(from);
710 HTONF(tmp);
711 rb_str_buf_cat(res, tmp.buf, sizeof(float));
712 }
713 break;
714
715 case 'G': /* double precision float in network byte-order */
716 while (len-- > 0) {
717 DOUBLE_CONVWITH(tmp);
718
719 from = NEXTFROM;
720 tmp.d = RFLOAT_VALUE(rb_to_float(from));
721 HTOND(tmp);
722 rb_str_buf_cat(res, tmp.buf, sizeof(double));
723 }
724 break;
725
726 case 'x': /* null byte */
727 grow:
729 str_expand_fill(res, '\0', len);
730 break;
731
732 case 'X': /* back up byte */
733 shrink:
734 plen = RSTRING_LEN(res);
735 if (plen < len)
736 rb_raise(rb_eArgError, "X outside of string");
737 rb_str_set_len(res, plen - len);
738 break;
739
740 case '@': /* null fill to absolute position */
741 len -= RSTRING_LEN(res);
742 if (len > 0) goto grow;
743 len = -len;
744 if (len > 0) goto shrink;
745 break;
746
747 case '%':
748 rb_raise(rb_eArgError, "%% is not supported");
749 break;
750
751 case 'U': /* Unicode character */
752 while (len-- > 0) {
753 SIGNED_VALUE l;
754 char buf[8];
755 int le;
756
757 from = NEXTFROM;
758 from = rb_to_int(from);
759 l = NUM2LONG(from);
760 if (l < 0) {
761 rb_raise(rb_eRangeError, "pack(U): value out of range");
762 }
763 le = rb_uv_to_utf8(buf, l);
764 rb_str_buf_cat(res, (char*)buf, le);
765 }
766 break;
767
768 case 'r': /* r for SLEB128 encoding (signed) */
769 case 'R': /* R for ULEB128 encoding (unsigned) */
770 {
771 int pack_flags = INTEGER_PACK_LITTLE_ENDIAN;
772
773 if (type == 'r') {
774 pack_flags |= INTEGER_PACK_2COMP;
775 }
776
777 while (len-- > 0) {
778 size_t numbytes, nlz_bits;
779 int sign, extra = 0;
780 char *cp;
781
782 from = NEXTFROM;
783 from = rb_to_int(from);
784 if (type == 'R' && rb_int_negative_p(from)) {
785 rb_raise(rb_eArgError, "can't encode negative numbers in ULEB128");
786 }
787
788 numbytes = rb_absint_numwords(from, 7, &nlz_bits);
789 if (numbytes == 0) {
790 numbytes = 1;
791 }
792 else if (nlz_bits == 0 && type == 'r') {
793 /* No leading zero bits, we need an extra byte for sign extension */
794 extra = 1;
795 }
796 rb_str_modify_expand(res, numbytes + extra);
797
798 long start = RSTRING_LEN(res);
799
800 cp = RSTRING_PTR(res) + start;
801 sign = rb_integer_pack(from, cp, numbytes, 1, 1, pack_flags);
802
803 if (extra) {
804 /* Need an extra byte */
805 cp[numbytes++] = sign < 0 ? 0x7f : 0x00;
806 }
807 rb_str_set_len(res, start + numbytes);
808
809 while (1 < numbytes) {
810 *cp |= 0x80;
811 cp++;
812 numbytes--;
813 }
814 }
815 }
816 break;
817 case 'u': /* uuencoded string */
818 case 'm': /* base64 encoded string */
819 from = NEXTFROM;
820 STR_FROM(from);
821 ptr = RSTRING_PTR(from);
822 plen = RSTRING_LEN(from);
823
824 if (len == 0 && type == 'm') {
825 encodes(res, ptr, plen, type, 0);
826 ptr += plen;
827 break;
828 }
829 if (len <= 2)
830 len = 45;
831 else if (len > 63 && type == 'u')
832 len = 63;
833 else
834 len = len / 3 * 3;
835 while (plen > 0) {
836 long todo;
837
838 if (plen > len)
839 todo = len;
840 else
841 todo = plen;
842 encodes(res, ptr, todo, type, 1);
843 plen -= todo;
844 ptr += todo;
845 }
846 break;
847
848 case 'M': /* quoted-printable encoded string */
849 from = rb_obj_as_string(NEXTFROM);
850 NOT_BUFFER(from);
851 if (len <= 1)
852 len = 72;
853 qpencode(res, from, len);
854 break;
855
856 case 'P': /* pointer to packed byte string */
857 from = THISFROM;
858 if (!NIL_P(from)) {
859 STR_FROM(from);
860 if (RSTRING_LEN(from) < len) {
861 rb_raise(rb_eArgError, "too short buffer for P(%ld for %ld)",
862 RSTRING_LEN(from), len);
863 }
864 }
865 len = 1;
866 /* FALL THROUGH */
867 case 'p': /* pointer to string */
868 while (len-- > 0) {
869 const char *t = 0;
870 from = NEXTFROM;
871 if (!NIL_P(from)) {
872 STR_FROM(from);
873 t = RSTRING_PTR(from);
874 }
875 if (!associates) {
876 associates = rb_ary_new();
877 }
878 rb_ary_push(associates, from);
879 rb_str_buf_cat(res, (char*)&t, sizeof(char*));
880 }
881 break;
882
883 case 'w': /* BER compressed integer */
884 while (len-- > 0) {
885 VALUE buf;
886 size_t numbytes;
887 int sign;
888 char *cp;
889
890 from = NEXTFROM;
891 from = rb_to_int(from);
892 numbytes = rb_absint_numwords(from, 7, NULL);
893 if (numbytes == 0)
894 numbytes = 1;
895 buf = rb_str_new(NULL, numbytes);
896
897 sign = rb_integer_pack(from, RSTRING_PTR(buf), RSTRING_LEN(buf), 1, 1, INTEGER_PACK_BIG_ENDIAN);
898
899 if (sign < 0)
900 rb_raise(rb_eArgError, "can't compress negative numbers");
901 if (sign == 2)
902 rb_bug("buffer size problem?");
903
904 cp = RSTRING_PTR(buf);
905 while (1 < numbytes) {
906 *cp |= 0x80;
907 cp++;
908 numbytes--;
909 }
910
911 rb_str_buf_cat(res, RSTRING_PTR(buf), RSTRING_LEN(buf));
912 }
913 break;
914
915 default: {
916 unknown_directive("pack", type, fmt);
917 break;
918 }
919 }
920 }
921
922 if (associates) {
923 str_associate(res, associates);
924 }
925 switch (enc_info) {
926 case 1:
927 ENCODING_CODERANGE_SET(res, rb_usascii_encindex(), ENC_CODERANGE_7BIT);
928 break;
929 case 2:
930 rb_enc_set_index(res, rb_utf8_encindex());
931 break;
932 default:
933 /* do nothing, keep ASCII-8BIT */
934 break;
935 }
936 return res;
937}
938
939VALUE
940rb_ec_pack_ary(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
941{
942 return pack_pack(ec, ary, fmt, buffer);
943}
944
945static const char uu_table[] =
946"`!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_";
947static const char b64_table[] =
948"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
949
950static void
951encodes(VALUE str, const char *s0, long len, int type, int tail_lf)
952{
953 enum {buff_size = 4096, encoded_unit = 4, input_unit = 3};
954 char buff[buff_size + 1]; /* +1 for tail_lf */
955 long i = 0;
956 const char *const trans = type == 'u' ? uu_table : b64_table;
957 char padding;
958 const unsigned char *s = (const unsigned char *)s0;
959
960 if (type == 'u') {
961 buff[i++] = (char)len + ' ';
962 padding = '`';
963 }
964 else {
965 padding = '=';
966 }
967 while (len >= input_unit) {
968 while (len >= input_unit && buff_size-i >= encoded_unit) {
969 buff[i++] = trans[077 & (*s >> 2)];
970 buff[i++] = trans[077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017))];
971 buff[i++] = trans[077 & (((s[1] << 2) & 074) | ((s[2] >> 6) & 03))];
972 buff[i++] = trans[077 & s[2]];
973 s += input_unit;
974 len -= input_unit;
975 }
976 if (buff_size-i < encoded_unit) {
977 rb_str_buf_cat(str, buff, i);
978 i = 0;
979 }
980 }
981
982 if (len == 2) {
983 buff[i++] = trans[077 & (*s >> 2)];
984 buff[i++] = trans[077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017))];
985 buff[i++] = trans[077 & (((s[1] << 2) & 074) | (('\0' >> 6) & 03))];
986 buff[i++] = padding;
987 }
988 else if (len == 1) {
989 buff[i++] = trans[077 & (*s >> 2)];
990 buff[i++] = trans[077 & (((*s << 4) & 060) | (('\0' >> 4) & 017))];
991 buff[i++] = padding;
992 buff[i++] = padding;
993 }
994 if (tail_lf) buff[i++] = '\n';
995 rb_str_buf_cat(str, buff, i);
996 if ((size_t)i > sizeof(buff)) rb_bug("encodes() buffer overrun");
997}
998
999static const char hex_table[] = "0123456789ABCDEF";
1000
1001static void
1002qpencode(VALUE str, VALUE from, long len)
1003{
1004 char buff[1024];
1005 long i = 0, n = 0, prev = EOF;
1006 unsigned char *s = (unsigned char*)RSTRING_PTR(from);
1007 unsigned char *send = s + RSTRING_LEN(from);
1008
1009 while (s < send) {
1010 if ((*s > 126) ||
1011 (*s < 32 && *s != '\n' && *s != '\t') ||
1012 (*s == '=')) {
1013 buff[i++] = '=';
1014 buff[i++] = hex_table[*s >> 4];
1015 buff[i++] = hex_table[*s & 0x0f];
1016 n += 3;
1017 prev = EOF;
1018 }
1019 else if (*s == '\n') {
1020 if (prev == ' ' || prev == '\t') {
1021 buff[i++] = '=';
1022 buff[i++] = *s;
1023 }
1024 buff[i++] = *s;
1025 n = 0;
1026 prev = *s;
1027 }
1028 else {
1029 buff[i++] = *s;
1030 n++;
1031 prev = *s;
1032 }
1033 if (n > len) {
1034 buff[i++] = '=';
1035 buff[i++] = '\n';
1036 n = 0;
1037 prev = '\n';
1038 }
1039 if (i > 1024 - 5) {
1040 rb_str_buf_cat(str, buff, i);
1041 i = 0;
1042 }
1043 s++;
1044 }
1045 if (n > 0) {
1046 buff[i++] = '=';
1047 buff[i++] = '\n';
1048 }
1049 if (i > 0) {
1050 rb_str_buf_cat(str, buff, i);
1051 }
1052}
1053
1054static inline int
1055hex2num(char c)
1056{
1057 int n;
1058 n = ruby_digit36_to_number_table[(unsigned char)c];
1059 if (16 <= n)
1060 n = -1;
1061 return n;
1062}
1063
1064#define PACK_LENGTH_ADJUST_SIZE(sz) do { \
1065 tmp_len = 0; \
1066 if (mode == UNPACK_ARRAY) { \
1067 rb_ary_modify_expand(ary, len); \
1068 } \
1069 if (len > (long)((send-s)/(sz))) { \
1070 if (!star) { \
1071 tmp_len = len-(send-s)/(sz); \
1072 } \
1073 len = (send-s)/(sz); \
1074 } \
1075} while (0)
1076
1077#define PACK_ITEM_ADJUST() do { \
1078 if (tmp_len > 0 && mode == UNPACK_ARRAY) \
1079 rb_ary_resize(ary, RARRAY_LEN(ary)+tmp_len); \
1080} while (0)
1081
1082/* Workaround for Oracle Developer Studio (Oracle Solaris Studio)
1083 * 12.4/12.5/12.6 C compiler optimization bug
1084 * with "-xO4" optimization option.
1085 */
1086#if defined(__SUNPRO_C) && 0x5130 <= __SUNPRO_C && __SUNPRO_C <= 0x5150
1087# define AVOID_CC_BUG volatile
1088#else
1089# define AVOID_CC_BUG
1090#endif
1091
1092enum unpack_mode {
1093 UNPACK_ARRAY,
1094 UNPACK_BLOCK,
1095 UNPACK_1
1096};
1097
1098static VALUE
1099pack_unpack_internal(VALUE str, VALUE fmt, VALUE ofs, enum unpack_mode mode)
1100{
1101#define hexdigits ruby_hexdigits
1102 const char *s, *send;
1103 const char *p, *pend;
1104 VALUE ary, associates = Qfalse;
1105 long len;
1106 AVOID_CC_BUG long tmp_len;
1107 int signed_p, integer_size, bigendian_p;
1108 long align_base;
1109 const char *sptr;
1110 long slen;
1111#define UNPACK_PUSH(item) do {\
1112 VALUE item_val = (item);\
1113 if ((mode) == UNPACK_BLOCK) {\
1114 rb_yield(item_val);\
1115 /* The block may have modified str and invalidated s */ \
1116 if (RSTRING_PTR(str) != sptr || RSTRING_LEN(str) != slen) {\
1117 rb_raise(rb_eRuntimeError, "string modified");\
1118 }\
1119 }\
1120 else if ((mode) == UNPACK_ARRAY) {\
1121 rb_ary_push(ary, item_val);\
1122 }\
1123 else /* if ((mode) == UNPACK_1) { */ {\
1124 return item_val; \
1125 }\
1126 } while (0)
1127
1128 StringValue(str);
1129 StringValue(fmt);
1130 long offset = NUM2LONG(ofs);
1132
1133 len = RSTRING_LEN(str);
1134 if (offset < 0 ? (offset += len) < 0 : offset > len) {
1135 rb_raise(rb_eArgError, "offset outside of string");
1136 }
1137
1138 s = RSTRING_PTR(str);
1139 send = s + len;
1140 sptr = s;
1141 slen = len;
1142 s += offset;
1143 align_base = offset;
1144
1145 p = RSTRING_PTR(fmt);
1146 pend = p + RSTRING_LEN(fmt);
1147
1148#define UNPACK_FETCH(var, type) (memcpy((var), s, sizeof(type)), s += sizeof(type))
1149
1150 ary = mode == UNPACK_ARRAY ? rb_ary_new() : Qnil;
1151 while (p < pend) {
1152 int explicit_endian = 0;
1153 const char type = *p++;
1154 size_t align = 0;
1155 int star = 0;
1156 USING_NATINT(int natint = 0); /* native integer */
1157
1158 if (skip_blank(p, type)) continue;
1159
1160 /* Directives that do not take modifiers. */
1161 if ((type == 'x' || type == '@') && p < pend && *p == '!') {
1162 p++;
1163 p = pack_alignment_size(p, pend, fmt, &align);
1164 len = pack_align_pad(s - RSTRING_PTR(str), type == '@' ? 0 : align_base, align);
1165 if (len > send - s) {
1166 rb_raise(rb_eArgError, type == '@' ? "@ outside of string" : "x outside of string");
1167 }
1168 s += len;
1169 continue;
1170 }
1171
1172 p = pack_modifiers(p, pend, type, &natint, &explicit_endian);
1173
1174 if (p >= pend)
1175 len = 1;
1176 else if (*p == '*') {
1177 star = 1;
1178 len = send - s;
1179 p++;
1180 }
1181 else if (ISDIGIT(*p)) {
1182 errno = 0;
1183 len = STRTOUL(p, (char**)&p, 10);
1184 if (len < 0 || errno) {
1185 rb_raise(rb_eRangeError, "pack length too big");
1186 }
1187 }
1188 else {
1189 len = (type != '@');
1190 }
1191
1192 switch (type) {
1193 case '%':
1194 rb_raise(rb_eArgError, "%% is not supported");
1195 break;
1196
1197 case 'A':
1198 if (len > send - s) len = send - s;
1199 {
1200 long end = len;
1201 const char *t = s + len - 1;
1202
1203 while (t >= s) {
1204 if (*t != ' ' && *t != '\0') break;
1205 t--; len--;
1206 }
1207 UNPACK_PUSH(rb_str_new(s, len));
1208 s += end;
1209 }
1210 break;
1211
1212 case 'Z':
1213 {
1214 const char *t = s;
1215
1216 if (len > send-s) len = send-s;
1217 while (t < s+len && *t) t++;
1218 UNPACK_PUSH(rb_str_new(s, t-s));
1219 if (t < send) t++;
1220 s = star ? t : s+len;
1221 }
1222 break;
1223
1224 case 'a':
1225 if (len > send - s) len = send - s;
1226 UNPACK_PUSH(rb_str_new(s, len));
1227 s += len;
1228 break;
1229
1230 case 'b':
1231 {
1232 VALUE bitstr;
1233 char *t;
1234 int bits;
1235 long i;
1236
1237 if (p[-1] == '*' || len > (send - s) * 8)
1238 len = (send - s) * 8;
1239 bits = 0;
1240 bitstr = rb_usascii_str_new(0, len);
1241 t = RSTRING_PTR(bitstr);
1242 for (i=0; i<len; i++) {
1243 if (i & 7) bits >>= 1;
1244 else bits = (unsigned char)*s++;
1245 *t++ = (bits & 1) ? '1' : '0';
1246 }
1247 UNPACK_PUSH(bitstr);
1248 }
1249 break;
1250
1251 case 'B':
1252 {
1253 VALUE bitstr;
1254 char *t;
1255 int bits;
1256 long i;
1257
1258 if (p[-1] == '*' || len > (send - s) * 8)
1259 len = (send - s) * 8;
1260 bits = 0;
1261 bitstr = rb_usascii_str_new(0, len);
1262 t = RSTRING_PTR(bitstr);
1263 for (i=0; i<len; i++) {
1264 if (i & 7) bits <<= 1;
1265 else bits = (unsigned char)*s++;
1266 *t++ = (bits & 128) ? '1' : '0';
1267 }
1268 UNPACK_PUSH(bitstr);
1269 }
1270 break;
1271
1272 case 'h':
1273 {
1274 VALUE bitstr;
1275 char *t;
1276 int bits;
1277 long i;
1278
1279 if (p[-1] == '*' || len > (send - s) * 2)
1280 len = (send - s) * 2;
1281 bits = 0;
1282 bitstr = rb_usascii_str_new(0, len);
1283 t = RSTRING_PTR(bitstr);
1284 for (i=0; i<len; i++) {
1285 if (i & 1)
1286 bits >>= 4;
1287 else
1288 bits = (unsigned char)*s++;
1289 *t++ = hexdigits[bits & 15];
1290 }
1291 UNPACK_PUSH(bitstr);
1292 }
1293 break;
1294
1295 case 'H':
1296 {
1297 VALUE bitstr;
1298 char *t;
1299 int bits;
1300 long i;
1301
1302 if (p[-1] == '*' || len > (send - s) * 2)
1303 len = (send - s) * 2;
1304 bits = 0;
1305 bitstr = rb_usascii_str_new(0, len);
1306 t = RSTRING_PTR(bitstr);
1307 for (i=0; i<len; i++) {
1308 if (i & 1)
1309 bits <<= 4;
1310 else
1311 bits = (unsigned char)*s++;
1312 *t++ = hexdigits[(bits >> 4) & 15];
1313 }
1314 UNPACK_PUSH(bitstr);
1315 }
1316 break;
1317
1318 case 'c':
1319 signed_p = 1;
1320 integer_size = 1;
1321 bigendian_p = BIGENDIAN_P(); /* not effective */
1322 goto unpack_integer;
1323
1324 case 'C':
1325 signed_p = 0;
1326 integer_size = 1;
1327 bigendian_p = BIGENDIAN_P(); /* not effective */
1328 goto unpack_integer;
1329
1330 case 's':
1331 signed_p = 1;
1332 integer_size = NATINT_LEN(short, 2);
1333 bigendian_p = BIGENDIAN_P();
1334 goto unpack_integer;
1335
1336 case 'S':
1337 signed_p = 0;
1338 integer_size = NATINT_LEN(short, 2);
1339 bigendian_p = BIGENDIAN_P();
1340 goto unpack_integer;
1341
1342 case 'i':
1343 signed_p = 1;
1344 integer_size = (int)sizeof(int);
1345 bigendian_p = BIGENDIAN_P();
1346 goto unpack_integer;
1347
1348 case 'I':
1349 signed_p = 0;
1350 integer_size = (int)sizeof(int);
1351 bigendian_p = BIGENDIAN_P();
1352 goto unpack_integer;
1353
1354 case 'l':
1355 signed_p = 1;
1356 integer_size = NATINT_LEN(long, 4);
1357 bigendian_p = BIGENDIAN_P();
1358 goto unpack_integer;
1359
1360 case 'L':
1361 signed_p = 0;
1362 integer_size = NATINT_LEN(long, 4);
1363 bigendian_p = BIGENDIAN_P();
1364 goto unpack_integer;
1365
1366 case 'q':
1367 signed_p = 1;
1368 integer_size = NATINT_LEN_Q;
1369 bigendian_p = BIGENDIAN_P();
1370 goto unpack_integer;
1371
1372 case 'Q':
1373 signed_p = 0;
1374 integer_size = NATINT_LEN_Q;
1375 bigendian_p = BIGENDIAN_P();
1376 goto unpack_integer;
1377
1378 case 'j':
1379 signed_p = 1;
1380 integer_size = sizeof(intptr_t);
1381 bigendian_p = BIGENDIAN_P();
1382 goto unpack_integer;
1383
1384 case 'J':
1385 signed_p = 0;
1386 integer_size = sizeof(uintptr_t);
1387 bigendian_p = BIGENDIAN_P();
1388 goto unpack_integer;
1389
1390 case 'n':
1391 signed_p = 0;
1392 integer_size = 2;
1393 bigendian_p = 1;
1394 goto unpack_integer;
1395
1396 case 'N':
1397 signed_p = 0;
1398 integer_size = 4;
1399 bigendian_p = 1;
1400 goto unpack_integer;
1401
1402 case 'v':
1403 signed_p = 0;
1404 integer_size = 2;
1405 bigendian_p = 0;
1406 goto unpack_integer;
1407
1408 case 'V':
1409 signed_p = 0;
1410 integer_size = 4;
1411 bigendian_p = 0;
1412 goto unpack_integer;
1413
1414 unpack_integer:
1415 if (explicit_endian) {
1416 bigendian_p = explicit_endian == '>';
1417 }
1418 PACK_LENGTH_ADJUST_SIZE(integer_size);
1419 while (len-- > 0) {
1420 int flags = bigendian_p ? INTEGER_PACK_BIG_ENDIAN : INTEGER_PACK_LITTLE_ENDIAN;
1421 VALUE val;
1422 if (signed_p)
1423 flags |= INTEGER_PACK_2COMP;
1424 val = rb_integer_unpack(s, integer_size, 1, 0, flags);
1425 UNPACK_PUSH(val);
1426 s += integer_size;
1427 }
1428 PACK_ITEM_ADJUST();
1429 break;
1430
1431 case 'f':
1432 case 'F':
1433 PACK_LENGTH_ADJUST_SIZE(sizeof(float));
1434 while (len-- > 0) {
1435 float tmp;
1436 UNPACK_FETCH(&tmp, float);
1437 UNPACK_PUSH(DBL2NUM((double)tmp));
1438 }
1439 PACK_ITEM_ADJUST();
1440 break;
1441
1442 case 'e':
1443 PACK_LENGTH_ADJUST_SIZE(sizeof(float));
1444 while (len-- > 0) {
1445 FLOAT_CONVWITH(tmp);
1446 UNPACK_FETCH(tmp.buf, float);
1447 VTOHF(tmp);
1448 UNPACK_PUSH(DBL2NUM(tmp.f));
1449 }
1450 PACK_ITEM_ADJUST();
1451 break;
1452
1453 case 'E':
1454 PACK_LENGTH_ADJUST_SIZE(sizeof(double));
1455 while (len-- > 0) {
1456 DOUBLE_CONVWITH(tmp);
1457 UNPACK_FETCH(tmp.buf, double);
1458 VTOHD(tmp);
1459 UNPACK_PUSH(DBL2NUM(tmp.d));
1460 }
1461 PACK_ITEM_ADJUST();
1462 break;
1463
1464 case 'D':
1465 case 'd':
1466 PACK_LENGTH_ADJUST_SIZE(sizeof(double));
1467 while (len-- > 0) {
1468 double tmp;
1469 UNPACK_FETCH(&tmp, double);
1470 UNPACK_PUSH(DBL2NUM(tmp));
1471 }
1472 PACK_ITEM_ADJUST();
1473 break;
1474
1475 case 'g':
1476 PACK_LENGTH_ADJUST_SIZE(sizeof(float));
1477 while (len-- > 0) {
1478 FLOAT_CONVWITH(tmp);
1479 UNPACK_FETCH(tmp.buf, float);
1480 NTOHF(tmp);
1481 UNPACK_PUSH(DBL2NUM(tmp.f));
1482 }
1483 PACK_ITEM_ADJUST();
1484 break;
1485
1486 case 'G':
1487 PACK_LENGTH_ADJUST_SIZE(sizeof(double));
1488 while (len-- > 0) {
1489 DOUBLE_CONVWITH(tmp);
1490 UNPACK_FETCH(tmp.buf, double);
1491 NTOHD(tmp);
1492 UNPACK_PUSH(DBL2NUM(tmp.d));
1493 }
1494 PACK_ITEM_ADJUST();
1495 break;
1496
1497 case 'U':
1498 if (len > send - s) len = send - s;
1499 while (len > 0 && s < send) {
1500 long alen = send - s;
1501 unsigned long l;
1502
1503 l = utf8_to_uv(s, &alen);
1504 s += alen; len--;
1505 UNPACK_PUSH(ULONG2NUM(l));
1506 }
1507 break;
1508
1509 case 'u':
1510 {
1511 VALUE buf = rb_str_new(0, (send - s)*3/4);
1512 char *ptr = RSTRING_PTR(buf);
1513 long total = 0;
1514
1515 while (s < send && (unsigned char)*s > ' ' && (unsigned char)*s < 'a') {
1516 long a,b,c,d;
1517 char hunk[3];
1518
1519 len = ((unsigned char)*s++ - ' ') & 077;
1520
1521 total += len;
1522 if (total > RSTRING_LEN(buf)) {
1523 len -= total - RSTRING_LEN(buf);
1524 total = RSTRING_LEN(buf);
1525 }
1526
1527 while (len > 0) {
1528 long mlen = len > 3 ? 3 : len;
1529
1530 if (s < send && (unsigned char)*s >= ' ' && (unsigned char)*s < 'a')
1531 a = ((unsigned char)*s++ - ' ') & 077;
1532 else
1533 a = 0;
1534 if (s < send && (unsigned char)*s >= ' ' && (unsigned char)*s < 'a')
1535 b = ((unsigned char)*s++ - ' ') & 077;
1536 else
1537 b = 0;
1538 if (s < send && (unsigned char)*s >= ' ' && (unsigned char)*s < 'a')
1539 c = ((unsigned char)*s++ - ' ') & 077;
1540 else
1541 c = 0;
1542 if (s < send && (unsigned char)*s >= ' ' && (unsigned char)*s < 'a')
1543 d = ((unsigned char)*s++ - ' ') & 077;
1544 else
1545 d = 0;
1546 hunk[0] = (char)(a << 2 | b >> 4);
1547 hunk[1] = (char)(b << 4 | c >> 2);
1548 hunk[2] = (char)(c << 6 | d);
1549 memcpy(ptr, hunk, mlen);
1550 ptr += mlen;
1551 len -= mlen;
1552 }
1553 if (s < send && (unsigned char)*s != '\r' && *s != '\n')
1554 s++; /* possible checksum byte */
1555 if (s < send && *s == '\r') s++;
1556 if (s < send && *s == '\n') s++;
1557 }
1558
1559 rb_str_set_len(buf, total);
1560 UNPACK_PUSH(buf);
1561 }
1562 break;
1563
1564 case 'm':
1565 {
1566 VALUE buf = rb_str_new(0, (send - s + 3)*3/4); /* +3 is for skipping paddings */
1567 char *ptr = RSTRING_PTR(buf);
1568 int a = -1,b = -1,c = 0,d = 0;
1569 static signed char b64_xtable[256];
1570
1571 if (b64_xtable['/'] <= 0) {
1572 int i;
1573
1574 for (i = 0; i < 256; i++) {
1575 b64_xtable[i] = -1;
1576 }
1577 for (i = 0; i < 64; i++) {
1578 b64_xtable[(unsigned char)b64_table[i]] = (char)i;
1579 }
1580 }
1581 if (len == 0) {
1582 while (s < send) {
1583 a = b = c = d = -1;
1584 a = b64_xtable[(unsigned char)*s++];
1585 if (s >= send || a == -1) rb_raise(rb_eArgError, "invalid base64");
1586 b = b64_xtable[(unsigned char)*s++];
1587 if (s >= send || b == -1) rb_raise(rb_eArgError, "invalid base64");
1588 if (*s == '=') {
1589 if (s + 2 == send && *(s + 1) == '=') break;
1590 rb_raise(rb_eArgError, "invalid base64");
1591 }
1592 c = b64_xtable[(unsigned char)*s++];
1593 if (s >= send || c == -1) rb_raise(rb_eArgError, "invalid base64");
1594 if (s + 1 == send && *s == '=') break;
1595 d = b64_xtable[(unsigned char)*s++];
1596 if (d == -1) rb_raise(rb_eArgError, "invalid base64");
1597 *ptr++ = castchar(a << 2 | b >> 4);
1598 *ptr++ = castchar(b << 4 | c >> 2);
1599 *ptr++ = castchar(c << 6 | d);
1600 }
1601 if (c == -1) {
1602 *ptr++ = castchar(a << 2 | b >> 4);
1603 if (b & 0xf) rb_raise(rb_eArgError, "invalid base64");
1604 }
1605 else if (d == -1) {
1606 *ptr++ = castchar(a << 2 | b >> 4);
1607 *ptr++ = castchar(b << 4 | c >> 2);
1608 if (c & 0x3) rb_raise(rb_eArgError, "invalid base64");
1609 }
1610 }
1611 else {
1612 while (s < send) {
1613 a = b = c = d = -1;
1614 while ((a = b64_xtable[(unsigned char)*s]) == -1 && s < send) {s++;}
1615 if (s >= send) break;
1616 s++;
1617 while ((b = b64_xtable[(unsigned char)*s]) == -1 && s < send) {s++;}
1618 if (s >= send) break;
1619 s++;
1620 while ((c = b64_xtable[(unsigned char)*s]) == -1 && s < send) {if (*s == '=') break; s++;}
1621 if (*s == '=' || s >= send) break;
1622 s++;
1623 while ((d = b64_xtable[(unsigned char)*s]) == -1 && s < send) {if (*s == '=') break; s++;}
1624 if (*s == '=' || s >= send) break;
1625 s++;
1626 *ptr++ = castchar(a << 2 | b >> 4);
1627 *ptr++ = castchar(b << 4 | c >> 2);
1628 *ptr++ = castchar(c << 6 | d);
1629 a = -1;
1630 }
1631 if (a != -1 && b != -1) {
1632 if (c == -1)
1633 *ptr++ = castchar(a << 2 | b >> 4);
1634 else {
1635 *ptr++ = castchar(a << 2 | b >> 4);
1636 *ptr++ = castchar(b << 4 | c >> 2);
1637 }
1638 }
1639 }
1640 rb_str_set_len(buf, ptr - RSTRING_PTR(buf));
1641 UNPACK_PUSH(buf);
1642 }
1643 break;
1644
1645 case 'M':
1646 {
1647 VALUE buf = rb_str_new(0, send - s);
1648 char *ptr = RSTRING_PTR(buf);
1649 const char *ss = s;
1650 int csum = 0;
1651 int c1, c2;
1652
1653 while (s < send) {
1654 if (*s == '=') {
1655 if (++s == send) break;
1656 if (s+1 < send && *s == '\r' && *(s+1) == '\n')
1657 s++;
1658 if (*s != '\n') {
1659 if ((c1 = hex2num(*s)) == -1) break;
1660 if (++s == send) break;
1661 if ((c2 = hex2num(*s)) == -1) break;
1662 csum |= *ptr++ = castchar(c1 << 4 | c2);
1663 }
1664 }
1665 else {
1666 csum |= *ptr++ = *s;
1667 }
1668 s++;
1669 ss = s;
1670 }
1671 rb_str_set_len(buf, ptr - RSTRING_PTR(buf));
1672 rb_str_buf_cat(buf, ss, send-ss);
1674 ENCODING_CODERANGE_SET(buf, rb_ascii8bit_encindex(), csum);
1675 UNPACK_PUSH(buf);
1676 }
1677 break;
1678
1679 case '@':
1680 if (len > RSTRING_LEN(str))
1681 rb_raise(rb_eArgError, "@ outside of string");
1682 s = RSTRING_PTR(str) + len;
1683 break;
1684
1685 case 'X':
1686 if (len > s - RSTRING_PTR(str))
1687 rb_raise(rb_eArgError, "X outside of string");
1688 s -= len;
1689 break;
1690
1691 case 'x':
1692 if (len > send - s)
1693 rb_raise(rb_eArgError, "x outside of string");
1694 s += len;
1695 break;
1696
1697 case '^':
1698 UNPACK_PUSH(SSIZET2NUM(s - RSTRING_PTR(str)));
1699 break;
1700
1701 case 'P':
1702 if (sizeof(char *) <= (size_t)(send - s)) {
1703 VALUE tmp = Qnil;
1704 const char *t;
1705
1706 UNPACK_FETCH(&t, char *);
1707 if (t) {
1708 if (!associates) associates = str_associated(str);
1709 tmp = associated_pointer(associates, t);
1710 if (len < RSTRING_LEN(tmp)) {
1711 tmp = rb_str_new(t, len);
1712 str_associate(tmp, associates);
1713 }
1714 }
1715 UNPACK_PUSH(tmp);
1716 }
1717 break;
1718
1719 case 'p':
1720 if (len > (long)((send - s) / sizeof(char *)))
1721 len = (send - s) / sizeof(char *);
1722 while (len-- > 0) {
1723 if ((size_t)(send - s) < sizeof(char *))
1724 break;
1725 else {
1726 VALUE tmp = Qnil;
1727 const char *t;
1728
1729 UNPACK_FETCH(&t, char *);
1730 if (t) {
1731 if (!associates) associates = str_associated(str);
1732 tmp = associated_pointer(associates, t);
1733 }
1734 UNPACK_PUSH(tmp);
1735 }
1736 }
1737 break;
1738
1739 case 'r':
1740 case 'R':
1741 {
1742 int pack_flags = INTEGER_PACK_LITTLE_ENDIAN;
1743
1744 if (type == 'r') {
1745 pack_flags |= INTEGER_PACK_2COMP;
1746 }
1747 const char *s0 = s;
1748 while (len > 0 && s < send) {
1749 if (*s & 0x80) {
1750 s++;
1751 }
1752 else {
1753 s++;
1754 UNPACK_PUSH(rb_integer_unpack(s0, s-s0, 1, 1, pack_flags));
1755 len--;
1756 s0 = s;
1757 }
1758 }
1759 /* Handle incomplete value and remaining expected values with nil (only if not using *) */
1760 if (!star) {
1761 if (s0 != s && len > 0) {
1762 UNPACK_PUSH(Qnil);
1763 len--;
1764 }
1765 while (len-- > 0) {
1766 UNPACK_PUSH(Qnil);
1767 }
1768 }
1769 }
1770 break;
1771
1772 case 'w':
1773 {
1774 const char *s0 = s;
1775 while (len > 0 && s < send) {
1776 if (*s & 0x80) {
1777 s++;
1778 }
1779 else {
1780 s++;
1781 UNPACK_PUSH(rb_integer_unpack(s0, s-s0, 1, 1, INTEGER_PACK_BIG_ENDIAN));
1782 len--;
1783 s0 = s;
1784 }
1785 }
1786 }
1787 break;
1788
1789 default:
1790 unknown_directive("unpack", type, fmt);
1791 break;
1792 }
1793 }
1794
1795 return ary;
1796}
1797
1798static VALUE
1799pack_unpack(rb_execution_context_t *ec, VALUE str, VALUE fmt, VALUE offset)
1800{
1801 enum unpack_mode mode = rb_block_given_p() ? UNPACK_BLOCK : UNPACK_ARRAY;
1802 return pack_unpack_internal(str, fmt, offset, mode);
1803}
1804
1805static VALUE
1806pack_unpack1(rb_execution_context_t *ec, VALUE str, VALUE fmt, VALUE offset)
1807{
1808 return pack_unpack_internal(str, fmt, offset, UNPACK_1);
1809}
1810
1811int
1812rb_uv_to_utf8(char buf[6], unsigned long uv)
1813{
1814 if (uv <= 0x7f) {
1815 buf[0] = (char)uv;
1816 return 1;
1817 }
1818 if (uv <= 0x7ff) {
1819 buf[0] = castchar(((uv>>6)&0xff)|0xc0);
1820 buf[1] = castchar((uv&0x3f)|0x80);
1821 return 2;
1822 }
1823 if (uv <= 0xffff) {
1824 buf[0] = castchar(((uv>>12)&0xff)|0xe0);
1825 buf[1] = castchar(((uv>>6)&0x3f)|0x80);
1826 buf[2] = castchar((uv&0x3f)|0x80);
1827 return 3;
1828 }
1829 if (uv <= 0x1fffff) {
1830 buf[0] = castchar(((uv>>18)&0xff)|0xf0);
1831 buf[1] = castchar(((uv>>12)&0x3f)|0x80);
1832 buf[2] = castchar(((uv>>6)&0x3f)|0x80);
1833 buf[3] = castchar((uv&0x3f)|0x80);
1834 return 4;
1835 }
1836 if (uv <= 0x3ffffff) {
1837 buf[0] = castchar(((uv>>24)&0xff)|0xf8);
1838 buf[1] = castchar(((uv>>18)&0x3f)|0x80);
1839 buf[2] = castchar(((uv>>12)&0x3f)|0x80);
1840 buf[3] = castchar(((uv>>6)&0x3f)|0x80);
1841 buf[4] = castchar((uv&0x3f)|0x80);
1842 return 5;
1843 }
1844 if (uv <= 0x7fffffff) {
1845 buf[0] = castchar(((uv>>30)&0xff)|0xfc);
1846 buf[1] = castchar(((uv>>24)&0x3f)|0x80);
1847 buf[2] = castchar(((uv>>18)&0x3f)|0x80);
1848 buf[3] = castchar(((uv>>12)&0x3f)|0x80);
1849 buf[4] = castchar(((uv>>6)&0x3f)|0x80);
1850 buf[5] = castchar((uv&0x3f)|0x80);
1851 return 6;
1852 }
1853 rb_raise(rb_eRangeError, "pack(U): value out of range");
1854
1856}
1857
1858static const unsigned long utf8_limits[] = {
1859 0x0, /* 1 */
1860 0x80, /* 2 */
1861 0x800, /* 3 */
1862 0x10000, /* 4 */
1863 0x200000, /* 5 */
1864 0x4000000, /* 6 */
1865 0x80000000, /* 7 */
1866};
1867
1868static unsigned long
1869utf8_to_uv(const char *p, long *lenp)
1870{
1871 int c = *p++ & 0xff;
1872 unsigned long uv = c;
1873 long n;
1874
1875 if (!(uv & 0x80)) {
1876 *lenp = 1;
1877 return uv;
1878 }
1879 if (!(uv & 0x40)) {
1880 *lenp = 1;
1881 rb_raise(rb_eArgError, "malformed UTF-8 character");
1882 }
1883
1884 if (!(uv & 0x20)) { n = 2; uv &= 0x1f; }
1885 else if (!(uv & 0x10)) { n = 3; uv &= 0x0f; }
1886 else if (!(uv & 0x08)) { n = 4; uv &= 0x07; }
1887 else if (!(uv & 0x04)) { n = 5; uv &= 0x03; }
1888 else if (!(uv & 0x02)) { n = 6; uv &= 0x01; }
1889 else {
1890 *lenp = 1;
1891 rb_raise(rb_eArgError, "malformed UTF-8 character");
1892 }
1893 if (n > *lenp) {
1894 rb_raise(rb_eArgError, "malformed UTF-8 character (expected %ld bytes, given %ld bytes)",
1895 n, *lenp);
1896 }
1897 *lenp = n--;
1898 if (n != 0) {
1899 while (n--) {
1900 c = *p++ & 0xff;
1901 if ((c & 0xc0) != 0x80) {
1902 *lenp -= n + 1;
1903 rb_raise(rb_eArgError, "malformed UTF-8 character");
1904 }
1905 else {
1906 c &= 0x3f;
1907 uv = uv << 6 | c;
1908 }
1909 }
1910 }
1911 n = *lenp - 1;
1912 if (uv < utf8_limits[n]) {
1913 rb_raise(rb_eArgError, "redundant UTF-8 sequence");
1914 }
1915 return uv;
1916}
1917
1918#include "pack.rbinc"
1919
1920void
1921Init_pack(void)
1922{
1923 id_associated = rb_make_internal_id();
1924}
#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 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:1467
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1463
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1461
VALUE rb_to_float(VALUE val)
Identical to rb_check_to_float(), except it raises on error.
Definition object.c:3773
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3327
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:1812
#define INTEGER_PACK_2COMP
Uses 2's complement representation.
Definition bignum.h:553
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1499
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1682
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1533
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3485
void rb_must_asciicompat(VALUE obj)
Asserts that the given string's encoding is (Ruby's definition of) ASCII compatible.
Definition string.c:2847
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
Definition string.c:2801
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1755
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:1887
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:2131
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:60
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:533
#define errno
Ractor-aware version of errno.
Definition ruby.h:388
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