diff --git a/README.md b/README.md
index 609050f5..97858699 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,34 @@
-[MessagePack](http://msgpack.org/)
-==================================
+[MessagePack](http://msgpack.org/) with key extension
+=====================================================
Space-efficient binary serialization format.
+This includes an extension to remove xtra space for duplicate keys:
+
+
+ | format name | first byte (in binary) | first byte (in hex) |
+ | fixext 1 | 11010100 | 0xd4 |
+ | fixext 2 | 11010101 | 0xd5 |
+
+
+where:
+
+ Y: 1-512 unit id of a map space
+ key: the string to save in that map space
+ +--------+--------+========+
+ | 0xd4 |YYYYYYYY| key |
+ +--------+--------+========+
+
+ Z: lookup the previously assigned key
+ +--------+--------+
+ | 0xd5 |ZZZZZZZZ|
+ +--------+--------+
+
+this allows reused keys (i.e. for object serialization) to use up much less space.
+
+I.e. if you have a list of objects like {id:1,name:"test"} you will save 4 bytes per iteration (one from id, and 3 from name)
+
+
Quick start
===========
diff --git a/msgpack.js b/msgpack.js
index 7d09c846..ed9b3196 100644
--- a/msgpack.js
+++ b/msgpack.js
@@ -39,7 +39,7 @@ self.importScripts && (onmessage = function(event) {
// msgpack.pack
function msgpackpack(data) { // @param Mix:
// @return ArrayBuffer:
- return new Uint8Array( encode( [], data, { i: -1, d: msgpack.MAX_DEPTH } ) ).buffer;
+ return new Uint8Array( encode( [], data, { i: -1, d: msgpack.MAX_DEPTH, k: {}, l: 1 } ) ).buffer;
}
// msgpack.unpack
@@ -50,7 +50,26 @@ function msgpackunpack(data) { // @param ArrayBuffer:
} else if ( !(data instanceof Uint8Array) ) {
throw new SyntaxError("ArrayBuffer or Uint8Array expected");
}
- return decode( data, { i: -1, d: msgpack.MAX_DEPTH } ); // mix or undefined
+ return decode( data, { i: -1, d: msgpack.MAX_DEPTH, k: {} } ); // mix or undefined
+}
+
+// key encoding: 0xd4+id+string
+// 0xd5+id
+function encodeKey(rv, // @param ByteArray: result
+ mix, // @param Mix: source data (string in that case)
+ ctx) { // @param Object: context
+ var id = ctx.k[mix];
+ if(id) {
+ rv.push(0xd5, id);
+ } else if(ctx.l < 512) {
+ id = ctx.l++; // next id
+ ctx.k[mix] = id; // lookup
+ rv.push(0xd4, id); // field + 0 + id
+ encode(rv, mix, ctx); // name
+ } else {
+ // just encode
+ encode(rv, mix, ctx); // name
+ }
}
// inner - encoder
@@ -344,6 +363,12 @@ function decode(buf, // @param source buffer
hash[decode(buf, ctx)] = decode(buf, ctx);
}
return hash;
+ case 0xd4: num += buf[++ctx.i];
+ str = decode(buf, ctx);
+ ctx.k[num] = str;
+ return str;
+ case 0xd5: num += buf[++ctx.i];
+ return ctx.k[num];
// 0xdd: array32, 0xdc: array16, 0x90: array
case 0xdd: num += buf[++ctx.i] * 0x1000000 + (buf[++ctx.i] << 16);
case 0xdc: num += (buf[++ctx.i] << 8) + buf[++ctx.i];