diff options
| -rw-r--r-- | packtest.rb | 3 | ||||
| -rw-r--r-- | src/pack.c | 48 |
2 files changed, 50 insertions, 1 deletions
diff --git a/packtest.rb b/packtest.rb index feaed31f9..e8be7c76c 100644 --- a/packtest.rb +++ b/packtest.rb @@ -149,3 +149,6 @@ pptest ["1","2"], "1\0002", "Z*Z" unpacktest ["1","3"], "1\00023", "Z3Z" packtest [1, 2], "\x01\x02", "CyC" + +packtest [65], "A", 'U' +packtest [59411], "\xEE\xA0\x93", 'U' diff --git a/src/pack.c b/src/pack.c index 1ceda8c11..d8bd68d4c 100644 --- a/src/pack.c +++ b/src/pack.c @@ -28,7 +28,7 @@ enum { PACK_DIR_QUAD, /* Q */ //PACK_DIR_INT, /* i */ //PACK_DIR_VAX, - //PACK_DIR_UTF8, /* U */ + PACK_DIR_UTF8, /* U */ //PACK_DIR_BER, PACK_DIR_DOUBLE, /* E */ PACK_DIR_FLOAT, /* f */ @@ -409,6 +409,45 @@ unpack_float(mrb_state *mrb, const unsigned char * src, int srclen, mrb_value ar } static int +pack_utf8(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, long count, unsigned int flags) +{ + char utf8[4]; + int len; + + unsigned long c = mrb_fixnum(o); + + /* Unicode character */ + /* from mruby-compiler gem */ + if (c < 0x80) { + utf8[0] = (char)c; + len = 1; + } + else if (c < 0x800) { + utf8[0] = (char)(0xC0 | (c >> 6)); + utf8[1] = (char)(0x80 | (c & 0x3F)); + len = 2; + } + else if (c < 0x10000) { + utf8[0] = (char)(0xE0 | (c >> 12) ); + utf8[1] = (char)(0x80 | ((c >> 6) & 0x3F)); + utf8[2] = (char)(0x80 | ( c & 0x3F)); + len = 3; + } + else { + utf8[0] = (char)(0xF0 | (c >> 18) ); + utf8[1] = (char)(0x80 | ((c >> 12) & 0x3F)); + utf8[2] = (char)(0x80 | ((c >> 6) & 0x3F)); + utf8[3] = (char)(0x80 | ( c & 0x3F)); + len = 4; + } + + str = str_len_ensure(mrb, str, sidx + len); + memcpy(RSTRING_PTR(str) + sidx, utf8, len); + + return len; +} + +static int pack_a(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, unsigned int flags) { int copylen, slen, padlen; @@ -856,6 +895,10 @@ alias: size = 2; flags |= PACK_FLAG_SIGNED; break; + case 'U': + dir = PACK_DIR_UTF8; + type = PACK_TYPE_INTEGER; + break; case 'V': /* = "L<" */ dir = PACK_DIR_LONG; type = PACK_TYPE_INTEGER; @@ -989,6 +1032,9 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary) case PACK_DIR_FLOAT: ridx += pack_float(mrb, o, result, ridx, flags); break; + case PACK_DIR_UTF8: + ridx += pack_utf8(mrb, o, result, ridx, count, flags); + break; default: break; } |
