-
Notifications
You must be signed in to change notification settings - Fork 989
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The implementation follows the ZeroMQ RFC spec: http://rfc.zeromq.org/spec:32/Z85/ Test Plan: Added test cases for Z85-encoding from the following sources: * The RFC itself * The PyZMQ Implementation. * The Base85 encoding example of Thomas Hobbes' "Leviathan". All test cases pass.
- Loading branch information
1 parent
a1d5c46
commit 4cd1985
Showing
7 changed files
with
204 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,8 @@ core_closure.js | |
node_modules/ | ||
doc/ | ||
doc_private/ | ||
|
||
# Swap Files # | ||
# ########## # | ||
~* | ||
*.swp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
/** | ||
* @fileOverview Z85 codec implementation. | ||
* @summary Z85 encoding is the "string-safe" ZeroMQ variant of Base85 | ||
* encoding. The character set avoids the single and double | ||
* quotes and the backslash, making the encoded string | ||
* safe to embed in command-line interpreters. | ||
* Base85 uses 5 characters to encode 4 bytes of data, | ||
* making the encoded size 1/4 larger than the original; | ||
* this also makes it more efficient than uuencode or Base64, | ||
* which uses 4 characters to encode 3 bytes of data, making | ||
* the encoded size 1/3 larger than the original. | ||
* | ||
* @author Manjul Apratim | ||
*/ | ||
|
||
/** | ||
* Z85 encoding/decoding | ||
* http://rfc.zeromq.org/spec:32/Z85/ | ||
* @namespace | ||
*/ | ||
sjcl.codec.z85 = { | ||
/** The Z85 alphabet. | ||
* @private | ||
*/ | ||
_chars: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#", | ||
|
||
/** The decoder map (maps base 85 to base 256). | ||
* @private | ||
*/ | ||
_byteMap: [ | ||
0x00, 0x44, 0x00, 0x54, 0x53, 0x52, 0x48, 0x00, | ||
0x4B, 0x4C, 0x46, 0x41, 0x00, 0x3F, 0x3E, 0x45, | ||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, | ||
0x08, 0x09, 0x40, 0x00, 0x49, 0x42, 0x4A, 0x47, | ||
0x51, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, | ||
0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, | ||
0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, | ||
0x3B, 0x3C, 0x3D, 0x4D, 0x00, 0x4E, 0x43, 0x00, | ||
0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, | ||
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, | ||
0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, | ||
0x21, 0x22, 0x23, 0x4F, 0x00, 0x50, 0x00, 0x00 | ||
], | ||
|
||
/** | ||
* @summary Method to convert a bitArray to a Z85-encoded string. | ||
* The bits represented by the array MUST be multiples of 4 bytes. | ||
* @param {bitArray} arr - The input bitArray. | ||
* @return {string} The Z85-encoded string. | ||
*/ | ||
fromBits: function (arr) { | ||
// Sanity checks | ||
if (!arr) { | ||
return null; | ||
} | ||
// Check we have multiples of 4 bytes (32 bits) | ||
if (0 !== sjcl.bitArray.bitLength(arr) % 32) { | ||
throw new sjcl.exception.invalid("Invalid bitArray length!"); | ||
} | ||
|
||
var out = "", c = sjcl.codec.z85._chars; | ||
|
||
// Convert sequences of 4 bytes (each word) to 5 characters. | ||
for (var i = 0; i < arr.length; ++i) { | ||
// Each element in the bitArray is a 32-bit (4-byte) word. | ||
var word = arr[i]; | ||
var value = 0; | ||
for (var j = 0; j < 4; ++j) { | ||
// Extract each successive byte from the word from the left. | ||
var byteChunk = (word >>> 8*(4 - j - 1)) & 0xFF; | ||
// Accumulate in base-256 | ||
value = value*256 + byteChunk; | ||
} | ||
var divisor = 85*85*85*85; | ||
while (divisor) { | ||
out += c.charAt(Math.floor(value/divisor) % 85); | ||
divisor = Math.floor(divisor/85); | ||
} | ||
} | ||
|
||
// Sanity check - each 4-bytes (1 word) should yield 5 characters. | ||
var encodedSize = arr.length*5; | ||
if (out.length !== encodedSize) { | ||
throw new sjcl.exception.invalid("Bad Z85 conversion!"); | ||
} | ||
return out; | ||
}, | ||
|
||
/** | ||
* @summary Method to convert a Z85-encoded string to a bitArray. | ||
* The length of the string MUST be a multiple of 5 | ||
* (else it is not a valid Z85 string). | ||
* @param {string} str - A valid Z85-encoded string. | ||
* @return {bitArray} The decoded data represented as a bitArray. | ||
*/ | ||
toBits: function(str) { | ||
// Sanity check | ||
if (!str) { | ||
return []; | ||
} | ||
// Accept only strings bounded to 5 bytes | ||
if (0 !== str.length % 5) { | ||
throw new sjcl.exception.invalid("Invalid Z85 string!"); | ||
} | ||
|
||
var out = [], value = 0, byteMap = sjcl.codec.z85._byteMap; | ||
var word = 0, wordSize = 0; | ||
for (var i = 0; i < str.length;) { | ||
// Accumulate value in base 85. | ||
value = value * 85 + byteMap[str[i++].charCodeAt(0) - 32]; | ||
if (0 === i % 5) { | ||
// Output value in base-256 | ||
var divisor = 256*256*256; | ||
while (divisor) { | ||
// The following is equivalent to a left shift by 8 bits | ||
// followed by OR-ing; however, left shift may cause sign problems | ||
// due to 2's complement interpretation, | ||
// and we're operating on unsigned values. | ||
word = (word * Math.pow(2, 8)) + (Math.floor(value/divisor) % 256); | ||
++wordSize; | ||
// If 4 bytes have been acumulated, push the word into the bitArray. | ||
if (4 === wordSize) { | ||
out.push(word); | ||
word = 0, wordSize = 0; | ||
} | ||
divisor = Math.floor(divisor/256); | ||
} | ||
value = 0; | ||
} | ||
} | ||
|
||
return out; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
new sjcl.test.TestCase("Z85-encoding from rfc.zeromq.org/spec:32/Z85/", function (cb) { | ||
if (!sjcl.codec.z85) { | ||
this.unimplemented(); | ||
cb && cb(); | ||
return; | ||
} | ||
|
||
var i, kat=sjcl.test.vector.z85, p=0, f=0; | ||
for (i=0; i<kat.length; i++) { | ||
// Test encoding | ||
this.require(sjcl.codec.z85.fromBits(sjcl.codec.hex.toBits(kat[i][0])) == | ||
kat[i][1], i); | ||
// Test decoding | ||
this.require(sjcl.codec.hex.fromBits(sjcl.codec.z85.toBits(kat[i][1])) == | ||
kat[i][0], i); | ||
} | ||
|
||
cb && cb(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/** | ||
* Test vector for Z85 | ||
*/ | ||
sjcl.test.vector.z85 = | ||
[ | ||
/** | ||
* Test case from http://rfc.zeromq.org/spec:32/Z85/: | ||
* | 0x86 | 0x4F | 0xD2 | 0x6F | 0xB5 | 0x59 | 0xF7 | 0x5B | encodes as | ||
* | H | e | l | l | o | W | o | r | l | d | | ||
*/ | ||
["864fd26fb559f75b", "HelloWorld"], | ||
/** | ||
* Sanity tests: | ||
*/ | ||
["00000000", "00000"], | ||
["ffffffff", "%nSc0"], | ||
/** | ||
* Test cases from PyZMQ (https://github.com/zeromq/pyzmq): | ||
*/ | ||
["bb88471d65e2659b30c55a5321cebb5aab2b70a398645c26dca2b2fcb43fc518", | ||
"Yne@$w-vo<fVvi]a<NY6T1ed:M$fCG*[IaLV{hID"], | ||
["7bb864b489afa3671fbe69101f94b38972f24816dfb01b51656b3fec8dfd0888", | ||
"D:)Q[IlAW!ahhC2ac:9*A}h:p?([4%wOTJ%JR%cs"], | ||
["54fcba24e93249969316fb617c872bb0c1d1ff14800427c594cbfacf1bc2d652", | ||
"rq:rM>}U?@Lns47E1%kR.o@n%FcmmsL/@{H8]yf7"], | ||
["8e0bdd697628b91d8f245587ee95c5b04d48963f79259877b49cd9063aead3b7", | ||
"JTKVSB%%)wK0E.X)V>+}o?pNmC{O&4W4b!Ni{Lh6"], | ||
/** | ||
* Thomas Hobbes' "Leviathan", Part I, Chapter VI: | ||
* (The "classic" Base85 example, also the second Wikipedia logo): | ||
* | ||
* "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure" | ||
* | ||
* The period at the end of the sentence has been omitted, | ||
* since keeping it requires padding the Hex string to align to 4-bytes. | ||
*/ | ||
["4d616e2069732064697374696e677569736865642c206e6f74206f6e6c792062792068697320726561736f6e2c2062757420627920746869732073696e67756c61722070617373696f6e2066726f6d206f7468657220616e696d616c732c2077686963682069732061206c757374206f6620746865206d696e642c20746861742062792061207065727365766572616e6365206f662064656c6967687420696e2074686520636f6e74696e75656420616e6420696e6465666174696761626c652067656e65726174696f6e206f66206b6e6f776c656467652c2065786365656473207468652073686f727420766568656d656e6365206f6620616e79206361726e616c20706c656173757265", | ||
"o<}]Zx(+zcx(!xgzFa9aB7/b}efF?GBrCHty<vdjC{3^mB0bHmvrlv8efFzABrC4raARphB0bKrzFa9dvr9GfvrlH7z/cXfA=k!qz//V7AV!!dx(do{B1wCTxLy%&azC)tvixxeB95Kyw/#hewGU&7zE+pvBzb98ayYQsvixJ2A=U/nwPzi%v}u^3w/$R}y?WJ}BrCpnaARpday/tcBzkSnwN(](zE:(7zE^r<vrui@vpB4:azkn6wPzj3x(v(iz!pbczF%-nwN]B+efFIGv}xjZB0bNrwGV5cz/P}xC4Ct#zdNP{wGU]6ayPekay!&2zEEu7Abo8]B9hIm"] | ||
]; |