summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-pack
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2021-06-12 14:59:48 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2021-06-12 16:18:44 +0900
commit3ddc57ed6e331541e805114d8123d3ab2d929681 (patch)
tree75657f4dd3148c73fe8a54a33d972f88c0f21041 /mrbgems/mruby-pack
parentfb013595edb73de9e0a3f5f1468e5c937670b8c6 (diff)
downloadmruby-3ddc57ed6e331541e805114d8123d3ab2d929681.tar.gz
mruby-3ddc57ed6e331541e805114d8123d3ab2d929681.zip
pack.c: add `X` directive (back up byte).
Diffstat (limited to 'mrbgems/mruby-pack')
-rw-r--r--mrbgems/mruby-pack/src/pack.c33
1 files changed, 32 insertions, 1 deletions
diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c
index 30b5e7fa0..70852438a 100644
--- a/mrbgems/mruby-pack/src/pack.c
+++ b/mrbgems/mruby-pack/src/pack.c
@@ -39,6 +39,7 @@ enum pack_dir {
PACK_DIR_BASE64, /* m */
PACK_DIR_QENC, /* M */
PACK_DIR_NUL, /* x */
+ PACK_DIR_BACK, /* X */
PACK_DIR_INVALID
};
@@ -1024,6 +1025,24 @@ unpack_x(mrb_state *mrb, int slen, int count)
return count;
}
+static int
+pack_X(mrb_state *mrb, mrb_value dst, mrb_int didx, int count)
+{
+ if (count > didx) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "X outside of string");
+ }
+ return count;
+}
+
+static int
+unpack_X(mrb_state *mrb, int sidx, int count)
+{
+ if (sidx < count) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "X outside of string");
+ }
+ return count;
+}
+
static void
prepare_tmpl(mrb_state *mrb, struct tmpl *tmpl)
{
@@ -1214,13 +1233,16 @@ alias:
dir = PACK_DIR_NUL;
type = PACK_TYPE_NONE;
break;
+ case 'X':
+ dir = PACK_DIR_BACK;
+ type = PACK_TYPE_NONE;
+ break;
case 'Z':
dir = PACK_DIR_STR;
type = PACK_TYPE_STRING;
flags |= PACK_FLAG_WIDTH | PACK_FLAG_COUNT2 | PACK_FLAG_Z;
break;
case 'p': case 'P':
- case 'X':
case '%': case '@':
mrb_raisef(mrb, E_ARGUMENT_ERROR, "%c is not supported", (char)t);
break;
@@ -1300,6 +1322,11 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary)
ridx += pack_x(mrb, result, ridx, count);
continue;
}
+ else if (dir == PACK_DIR_BACK) {
+ if (count > 0 && ridx > INT_MAX - count) goto overflow;
+ ridx -= pack_X(mrb, result, ridx, count);
+ continue;
+ }
if ((flags & PACK_FLAG_WIDTH) && aidx >= RARRAY_LEN(ary)) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "too few arguments");
@@ -1412,6 +1439,10 @@ pack_unpack(mrb_state *mrb, mrb_value str, int single)
srcidx += unpack_x(mrb, srclen-srcidx, count);
continue;
}
+ else if (dir == PACK_DIR_BACK) {
+ srcidx -= unpack_X(mrb, srcidx, count);
+ continue;
+ }
if (flags & PACK_FLAG_COUNT2) {
sptr = (const unsigned char *)RSTRING_PTR(str) + srcidx;