summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/pack.c48
1 files changed, 47 insertions, 1 deletions
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;
}