1#include "prism/extension.h"
4static VALUE rb_cPrismPack;
5static VALUE rb_cPrismPackDirective;
6static VALUE rb_cPrismPackFormat;
8static VALUE v3_2_0_symbol;
9static VALUE pack_symbol;
10static VALUE unpack_symbol;
12#if SIZEOF_UINT64_T == SIZEOF_LONG_LONG
13# define UINT64T2NUM(x) ULL2NUM(x)
14# define NUM2UINT64T(x) (uint64_t)NUM2ULL(x)
15#elif SIZEOF_UINT64_T == SIZEOF_LONG
16# define UINT64T2NUM(x) ULONG2NUM(x)
17# define NUM2UINT64T(x) (uint64_t)NUM2ULONG(x)
26 return ID2SYM(rb_intern(
"SPACE"));
28 return ID2SYM(rb_intern(
"COMMENT"));
30 return ID2SYM(rb_intern(
"INTEGER"));
32 return ID2SYM(rb_intern(
"UTF8"));
34 return ID2SYM(rb_intern(
"BER"));
36 return ID2SYM(rb_intern(
"FLOAT"));
37 case PM_PACK_STRING_SPACE_PADDED:
38 return ID2SYM(rb_intern(
"STRING_SPACE_PADDED"));
39 case PM_PACK_STRING_NULL_PADDED:
40 return ID2SYM(rb_intern(
"STRING_NULL_PADDED"));
41 case PM_PACK_STRING_NULL_TERMINATED:
42 return ID2SYM(rb_intern(
"STRING_NULL_TERMINATED"));
43 case PM_PACK_STRING_MSB:
44 return ID2SYM(rb_intern(
"STRING_MSB"));
45 case PM_PACK_STRING_LSB:
46 return ID2SYM(rb_intern(
"STRING_LSB"));
47 case PM_PACK_STRING_HEX_HIGH:
48 return ID2SYM(rb_intern(
"STRING_HEX_HIGH"));
49 case PM_PACK_STRING_HEX_LOW:
50 return ID2SYM(rb_intern(
"STRING_HEX_LOW"));
51 case PM_PACK_STRING_UU:
52 return ID2SYM(rb_intern(
"STRING_UU"));
53 case PM_PACK_STRING_MIME:
54 return ID2SYM(rb_intern(
"STRING_MIME"));
55 case PM_PACK_STRING_BASE64:
56 return ID2SYM(rb_intern(
"STRING_BASE64"));
57 case PM_PACK_STRING_FIXED:
58 return ID2SYM(rb_intern(
"STRING_FIXED"));
59 case PM_PACK_STRING_POINTER:
60 return ID2SYM(rb_intern(
"STRING_POINTER"));
62 return ID2SYM(rb_intern(
"MOVE"));
64 return ID2SYM(rb_intern(
"BACK"));
66 return ID2SYM(rb_intern(
"NULL"));
74 switch (signed_type) {
75 case PM_PACK_UNSIGNED:
76 return ID2SYM(rb_intern(
"UNSIGNED"));
78 return ID2SYM(rb_intern(
"SIGNED"));
79 case PM_PACK_SIGNED_NA:
80 return ID2SYM(rb_intern(
"SIGNED_NA"));
89 case PM_PACK_AGNOSTIC_ENDIAN:
90 return ID2SYM(rb_intern(
"AGNOSTIC_ENDIAN"));
91 case PM_PACK_LITTLE_ENDIAN:
92 return ID2SYM(rb_intern(
"LITTLE_ENDIAN"));
93 case PM_PACK_BIG_ENDIAN:
94 return ID2SYM(rb_intern(
"BIG_ENDIAN"));
95 case PM_PACK_NATIVE_ENDIAN:
96 return ID2SYM(rb_intern(
"NATIVE_ENDIAN"));
97 case PM_PACK_ENDIAN_NA:
98 return ID2SYM(rb_intern(
"ENDIAN_NA"));
107 case PM_PACK_SIZE_SHORT:
108 return ID2SYM(rb_intern(
"SIZE_SHORT"));
109 case PM_PACK_SIZE_INT:
110 return ID2SYM(rb_intern(
"SIZE_INT"));
111 case PM_PACK_SIZE_LONG:
112 return ID2SYM(rb_intern(
"SIZE_LONG"));
113 case PM_PACK_SIZE_LONG_LONG:
114 return ID2SYM(rb_intern(
"SIZE_LONG_LONG"));
116 return ID2SYM(rb_intern(
"SIZE_8"));
117 case PM_PACK_SIZE_16:
118 return ID2SYM(rb_intern(
"SIZE_16"));
119 case PM_PACK_SIZE_32:
120 return ID2SYM(rb_intern(
"SIZE_32"));
121 case PM_PACK_SIZE_64:
122 return ID2SYM(rb_intern(
"SIZE_64"));
124 return ID2SYM(rb_intern(
"SIZE_P"));
125 case PM_PACK_SIZE_NA:
126 return ID2SYM(rb_intern(
"SIZE_NA"));
134 switch (length_type) {
135 case PM_PACK_LENGTH_FIXED:
136 return ID2SYM(rb_intern(
"LENGTH_FIXED"));
137 case PM_PACK_LENGTH_MAX:
138 return ID2SYM(rb_intern(
"LENGTH_MAX"));
139 case PM_PACK_LENGTH_RELATIVE:
140 return ID2SYM(rb_intern(
"LENGTH_RELATIVE"));
141 case PM_PACK_LENGTH_NA:
142 return ID2SYM(rb_intern(
"LENGTH_NA"));
152 case PM_PACK_ENCODING_ASCII_8BIT:
153 index = rb_ascii8bit_encindex();
155 case PM_PACK_ENCODING_US_ASCII:
156 index = rb_usascii_encindex();
158 case PM_PACK_ENCODING_UTF_8:
159 index = rb_utf8_encindex();
164 return rb_enc_from_encoding(rb_enc_from_index(index));
175 if (version_symbol != v3_2_0_symbol) {
176 rb_raise(rb_eArgError,
"invalid version");
180 if (variant_symbol == pack_symbol) {
181 variant = PM_PACK_VARIANT_PACK;
182 }
else if (variant_symbol == unpack_symbol) {
183 variant = PM_PACK_VARIANT_UNPACK;
185 rb_raise(rb_eArgError,
"invalid variant");
190 const char *format = RSTRING_PTR(format_string);
191 const char *format_end = format + RSTRING_LEN(format_string);
194 VALUE directives_array = rb_ary_new();
196 while (format < format_end) {
204 const char *directive_start = format;
206 pm_pack_result parse_result = pm_pack_parse(variant, &format, format_end, &
type, &signed_type, &endian,
207 &size, &length_type, &length, &encoding);
209 const char *directive_end = format;
211 switch (parse_result) {
214 case PM_PACK_ERROR_UNSUPPORTED_DIRECTIVE:
215 rb_raise(rb_eArgError,
"unsupported directive");
216 case PM_PACK_ERROR_UNKNOWN_DIRECTIVE:
217 rb_raise(rb_eArgError,
"unsupported directive");
218 case PM_PACK_ERROR_LENGTH_TOO_BIG:
220 case PM_PACK_ERROR_BANG_NOT_ALLOWED:
222 case PM_PACK_ERROR_DOUBLE_ENDIAN:
225 rb_bug(
"parse result");
228 if (
type == PM_PACK_END) {
232 VALUE directive_args[9] = {
236 pack_type_to_symbol(
type),
237 pack_signed_to_symbol(signed_type),
238 pack_endian_to_symbol(endian),
239 pack_size_to_symbol(size),
240 pack_length_type_to_symbol(length_type),
247 VALUE format_args[2];
248 format_args[0] = directives_array;
249 format_args[1] = pack_encoding_to_ruby(encoding);
257Init_prism_pack(
void) {
264 v3_2_0_symbol =
ID2SYM(rb_intern(
"v3_2_0"));
265 pack_symbol =
ID2SYM(rb_intern(
"pack"));
266 unpack_symbol =
ID2SYM(rb_intern(
"unpack"));
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
VALUE rb_define_module(const char *name)
Defines a top-level module.
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
#define ID2SYM
Old name of RB_ID2SYM.
#define Qnil
Old name of RUBY_Qnil.
VALUE rb_eRangeError
RangeError exception.
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
VALUE type(ANYARGS)
ANYARGS-ed function type.
pm_pack_encoding
The type of encoding for a pack template string.
pm_pack_result
The result of parsing a pack template.
pm_pack_variant
The type of pack template we are parsing.
pm_pack_endian
The endianness of a pack directive.
pm_pack_signed
The signness of a pack directive.
pm_pack_size
The size of an integer pack directive.
pm_pack_length_type
The type of length of a pack directive.
pm_pack_type
A directive within the pack template.
#define StringValue(v)
Ensures that the parameter object is a String.
uintptr_t VALUE
Type that represents a Ruby object.