From cf14183bcd5485b4a71541599ddce0b35eb71352 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Thu, 28 Apr 2016 14:34:59 -0700 Subject: Down integrate from Google internal. --- js/binary/utils.js | 50 +++++++++++++++++++++++++++++++++++++++++++++++++ js/binary/utils_test.js | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) (limited to 'js') diff --git a/js/binary/utils.js b/js/binary/utils.js index 875ff955..51405553 100644 --- a/js/binary/utils.js +++ b/js/binary/utils.js @@ -567,6 +567,56 @@ jspb.utils.hash64ArrayToDecimalStrings = function(hashes, signed) { }; +/** + * Converts a signed or unsigned decimal string into its hash string + * representation. + * @param {string} dec + * @return {string} + */ +jspb.utils.decimalStringToHash64 = function(dec) { + goog.asserts.assert(dec.length > 0); + + // Check for minus sign. + var minus = false; + if (dec[0] === '-') { + minus = true; + dec = dec.slice(1); + } + + // Store result as a byte array. + var resultBytes = [0, 0, 0, 0, 0, 0, 0, 0]; + + // Set result to m*result + c. + function muladd(m, c) { + for (var i = 0; i < 8 && (m !== 1 || c > 0); i++) { + var r = m * resultBytes[i] + c; + resultBytes[i] = r & 0xFF; + c = r >>> 8; + } + } + + // Negate the result bits. + function neg() { + for (var i = 0; i < 8; i++) { + resultBytes[i] = (~resultBytes[i]) & 0xFF; + } + } + + // For each decimal digit, set result to 10*result + digit. + for (var i = 0; i < dec.length; i++) { + muladd(10, jspb.utils.DIGITS.indexOf(dec[i])); + } + + // If there's a minus sign, convert into two's complement. + if (minus) { + neg(); + muladd(1, 1); + } + + return String.fromCharCode.apply(null, resultBytes); +}; + + /** * Converts an 8-character hash string into its hexadecimal representation. * @param {string} hash diff --git a/js/binary/utils_test.js b/js/binary/utils_test.js index 518d7597..d27e5ea2 100644 --- a/js/binary/utils_test.js +++ b/js/binary/utils_test.js @@ -197,6 +197,41 @@ describe('binaryUtilsTest', function() { assertEquals('123456789123456789', result[2]); }); + /* + * Going from decimal strings to hash strings should be lossless. + */ + it('testDecimalToHashConversion', function() { + var result; + var convert = jspb.utils.decimalStringToHash64; + + result = convert('0'); + assertEquals(String.fromCharCode.apply(null, + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), result); + + result = convert('-1'); + assertEquals(String.fromCharCode.apply(null, + [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]), result); + + result = convert('18446744073709551615'); + assertEquals(String.fromCharCode.apply(null, + [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]), result); + + result = convert('9223372036854775808'); + assertEquals(String.fromCharCode.apply(null, + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80]), result); + + result = convert('-9223372036854775808'); + assertEquals(String.fromCharCode.apply(null, + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80]), result); + + result = convert('123456789123456789'); + assertEquals(String.fromCharCode.apply(null, + [0x15, 0x5F, 0xD0, 0xAC, 0x4B, 0x9B, 0xB6, 0x01]), result); + + result = convert('-123456789123456789'); + assertEquals(String.fromCharCode.apply(null, + [0xEB, 0xA0, 0x2F, 0x53, 0xB4, 0x64, 0x49, 0xFE]), result); + }); /** * Going from hash strings to hex strings should be lossless. -- cgit v1.2.3