summaryrefslogtreecommitdiff
path: root/pack.c
diff options
context:
space:
mode:
authorJean Boussier <jean.boussier@gmail.com>2021-10-18 16:23:54 +0200
committerJean Boussier <jean.boussier@gmail.com>2021-10-26 22:27:30 +0200
commite5319dc9856298f38aa9cdc6ed55e39ad0e8e070 (patch)
tree7c1d685ae65979ce2ae3bee4ccce54507d3f49f8 /pack.c
parent717ab0bb2ee63dfe76076e0c9f91fbac3a0de4fd (diff)
downloadruby-e5319dc9856298f38aa9cdc6ed55e39ad0e8e070.tar.gz
pack.c: add an offset argument to unpack and unpack1
[Feature #18254] This is useful to avoid repeteadly copying strings when parsing binary formats
Diffstat (limited to 'pack.c')
-rw-r--r--pack.c19
1 files changed, 13 insertions, 6 deletions
diff --git a/pack.c b/pack.c
index e6a729ab08..1fbbd724d7 100644
--- a/pack.c
+++ b/pack.c
@@ -944,7 +944,7 @@ hex2num(char c)
#define UNPACK_1 2
static VALUE
-pack_unpack_internal(VALUE str, VALUE fmt, int mode)
+pack_unpack_internal(VALUE str, VALUE fmt, int mode, long offset)
{
#define hexdigits ruby_hexdigits
char *s, *send;
@@ -973,8 +973,15 @@ pack_unpack_internal(VALUE str, VALUE fmt, int mode)
StringValue(str);
StringValue(fmt);
+
+ if (offset < 0) rb_raise(rb_eArgError, "offset can't be negative");
+ len = RSTRING_LEN(str);
+ if (offset > len) rb_raise(rb_eArgError, "offset outside of string");
+
s = RSTRING_PTR(str);
- send = s + RSTRING_LEN(str);
+ send = s + len;
+ s += offset;
+
p = RSTRING_PTR(fmt);
pend = p + RSTRING_LEN(fmt);
@@ -1614,16 +1621,16 @@ pack_unpack_internal(VALUE str, VALUE fmt, int mode)
}
static VALUE
-pack_unpack(rb_execution_context_t *ec, VALUE str, VALUE fmt)
+pack_unpack(rb_execution_context_t *ec, VALUE str, VALUE fmt, VALUE offset)
{
int mode = rb_block_given_p() ? UNPACK_BLOCK : UNPACK_ARRAY;
- return pack_unpack_internal(str, fmt, mode);
+ return pack_unpack_internal(str, fmt, mode, RB_NUM2LONG(offset));
}
static VALUE
-pack_unpack1(rb_execution_context_t *ec, VALUE str, VALUE fmt)
+pack_unpack1(rb_execution_context_t *ec, VALUE str, VALUE fmt, VALUE offset)
{
- return pack_unpack_internal(str, fmt, UNPACK_1);
+ return pack_unpack_internal(str, fmt, UNPACK_1, RB_NUM2LONG(offset));
}
int