From 1045f4f8e85fa592358df2ee0300e77e47f4b56d Mon Sep 17 00:00:00 2001 From: SheetJS Date: Sat, 8 Oct 2016 14:48:03 -0400 Subject: [PATCH] version bump 1.0.0: rolling checksums - browser tests work in IE6+ - miscellaneous adjustments to tooling --- .flowconfig | 5 + Makefile | 3 + README.md | 50 +++++---- bin/crc32.njs | 85 ++++++++++++---- bits/01_version.js | 2 +- bits/40_crc.js | 20 ++-- crc32.flow.js | 22 ++-- crc32.js | 22 ++-- ctest/crc32.js | 22 ++-- ctest/fakeassert.js | 2 +- ctest/fixtures.js | 27 +++-- ctest/index.html | 1 + ctest/shim.js | 237 +++++++++++++++++++++++++++++++++++++++++++ ctest/test.js | 29 +++++- demo/browser.flow.js | 6 +- demo/browser.js | 4 +- index.html | 1 + misc/flow.js | 7 +- misc/flowdeps.js | 12 +++ misc/integration.js | 8 +- package.json | 3 +- perf.txt | 82 --------------- perf/bstr.js | 8 +- perf/utf8.js | 61 ++++++----- shim.js | 237 +++++++++++++++++++++++++++++++++++++++++++ test.js | 29 +++++- 26 files changed, 765 insertions(+), 220 deletions(-) create mode 100644 ctest/shim.js create mode 100644 misc/flowdeps.js delete mode 100644 perf.txt create mode 100644 shim.js diff --git a/.flowconfig b/.flowconfig index 67bebf7..1a3ec98 100644 --- a/.flowconfig +++ b/.flowconfig @@ -10,13 +10,18 @@ .*/perf/.* .*/demo/browser.js +.*/shim.js [include] crc32.flow.js +.*/bin/.*.njs .*/demo/browser.flow.js [libs] bits/10_types.js misc/flow.js +misc/flowdeps.js [options] +module.file_ext=.js +module.file_ext=.njs diff --git a/Makefile b/Makefile index a37ea6f..302fd6b 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ LIB=crc32 REQS= ADDONS= AUXTARGETS=demo/browser.js +CMDS=bin/crc32.njs HTMLLINT=index.html ULIB=$(shell echo $(LIB) | tr a-z A-Z) @@ -37,6 +38,7 @@ test mocha: test.js $(TARGET) baseline ## Run test suite ctest: ## Build browser test (into ctest/ subdirectory) cat misc/*.js > ctest/fixtures.js cp -f test.js ctest/test.js + cp -f shim.js ctest/shim.js cp -f $(TARGET) ctest/ .PHONY: ctestserv @@ -56,6 +58,7 @@ clean-baseline: ## Remove test baselines .PHONY: lint lint: $(TARGET) $(AUXTARGETS) ## Run jshint and jscs checks @jshint --show-non-errors $(TARGET) $(AUXTARGETS) + @jshint --show-non-errors $(CMDS) @jshint --show-non-errors package.json @jshint --show-non-errors --extract=always $(HTMLLINT) @jscs $(TARGET) $(AUXTARGETS) diff --git a/README.md b/README.md index fb81efc..e879afd 100644 --- a/README.md +++ b/README.md @@ -1,52 +1,62 @@ # crc32 Standard CRC-32 algorithm implementation in JS (for the browser and nodejs). -Emphasis on correctness and performance. +Emphasis on correctness, performance, and IE6+ support. ## Installation With [npm](https://www.npmjs.org/package/crc-32): - $ npm install crc-32 +```bash +$ npm install crc-32 +``` In the browser: - +```html + +``` -The browser exposes a variable ADLER32 +The browser exposes a variable `CRC32`. When installed globally, npm installs a script `crc32` that computes the checksum for a specified file or standard input. The script will manipulate `module.exports` if available (e.g. in a CommonJS `require` context). This is not always desirable. To prevent the behavior, -define `DO_NOT_EXPORT_CRC` +define `DO_NOT_EXPORT_CRC`. ## Usage -In all cases, the relevant function takes a single argument representing data. +In all cases, the relevant function takes an argument representing data and an +optional second argument representing the starting "seed" (for rolling CRC). The return value is a signed 32-bit integer. -- `CRC32.buf(byte array or buffer)` assumes the argument is a set of 8-bit - unsigned integers (e.g. nodejs `Buffer` or simple array of ints). +- `CRC32.buf(byte array or buffer[, seed])` assumes the argument is a sequence + of 8-bit unsigned integers (e.g. nodejs `Buffer` or simple array of ints). -- `CRC32.bstr(binary string)` interprets the argument as a binary string where - the `i`-th byte is the low byte of the UCS-2 char: `str.charCodeAt(i) & 0xFF` +- `CRC32.bstr(binary string[, seed])` assumes the argument is a "binary" string + where byte `i` is the low byte of the UCS-2 char: `str.charCodeAt(i) & 0xFF` -- `CRC32.str(string)` interprets the argument as a standard JS string +- `CRC32.str(string[, seed])` assumes the argument is a standard string and + calculates the CRC32 of the UTF-8 encoding. For example: ```js -> // var CRC32 = require('crc-32'); // uncomment this line if in node -> CRC32.str("SheetJS") // -1647298270 -> CRC32.bstr("SheetJS") // -1647298270 -> CRC32.buf([ 83, 104, 101, 101, 116, 74, 83 ]) // -1647298270 +// var CRC32 = require('crc-32'); // uncomment this line if in node +CRC32.str("SheetJS") // -1647298270 +CRC32.bstr("SheetJS") // -1647298270 +CRC32.buf([ 83, 104, 101, 101, 116, 74, 83 ]) // -1647298270 -> [CRC32.str("\u2603"), CRC32.str("\u0003")] // [ -1743909036, 1259060791 ] -> [CRC32.bstr("\u2603"), CRC32.bstr("\u0003")] // [ 1259060791, 1259060791 ] -> [CRC32.buf([0x2603]), CRC32.buf([0x0003])] // [ 1259060791, 1259060791 ] +crc32 = CRC32.buf([83, 104]) // -1826163454 "Sh" +crc32 = CRC32.str("eet", crc32) // 1191034598 "Sheet" +CRC32.bstr("JS", crc32) // -1647298270 "SheetJS" + +[CRC32.str("\u2603"), CRC32.str("\u0003")] // [ -1743909036, 1259060791 ] +[CRC32.bstr("\u2603"), CRC32.bstr("\u0003")] // [ 1259060791, 1259060791 ] +[CRC32.buf([0x2603]), CRC32.buf([0x0003])] // [ 1259060791, 1259060791 ] ``` ## Testing @@ -73,7 +83,7 @@ To generate the bits file, use the `crc32` function from python zlib: The included `crc32.njs` script can process files or stdin: -``` +```bash $ echo "this is a test" > t.txt $ bin/crc32.njs t.txt 1912935186 @@ -81,7 +91,7 @@ $ bin/crc32.njs t.txt For comparison, the included `crc32.py` script uses python zlib: -``` +```bash $ bin/crc32.py t.txt 1912935186 ``` diff --git a/bin/crc32.njs b/bin/crc32.njs index c107e30..41a9ea0 100755 --- a/bin/crc32.njs +++ b/bin/crc32.njs @@ -2,36 +2,77 @@ /* crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */ /* vim: set ts=2 ft=javascript: */ -var X; +var X/*:CRC32Module*/; try { X = require('../'); } catch(e) { X = require('crc-32'); } + +function help()/*:number*/ { +[ +"usage: crc32 [options] [filename]", +"", +"Options:", +" -h, --help output usage information", +" -V, --version output the version number", +" -S, --seed= use integer seed as starting value (rolling CRC)", +" -H, --hex-seed= use hex seed as starting value (rolling CRC)", +" -d, --signed print result with format `%d` (default)", +" -u, --unsigned print result with format `%u`", +" -x, --hex print result with format `%0.8x`", +" -X, --HEX print result with format `%0.8X`", +" -F, --format= use specified printf format", +"", +"Set filename = '-' or pipe data into crc32 to read from stdin", +"Default output mode is signed (-d)", +"" +].forEach(function(l) { console.log(l); }); + return 0; +} + +function version()/*:number*/ { console.log(X.version); return 0; } + var fs = require('fs'); require('exit-on-epipe'); -var args = process.argv.slice(2); +function die(msg/*:string*/, ec/*:?number*/)/*:void*/ { console.error(msg); process.exit(ec || 0); } -var filename; -if(args[0]) filename = args[0]; +var args/*:Array*/ = process.argv.slice(2); +var filename/*:string*/ = ""; +var fmt/*:string*/ = ""; +var seed = 0, r = 10; + +for(var i = 0; i < args.length; ++i) { + var arg = args[i]; + if(arg.charCodeAt(0) != 45) { if(filename === "") filename = arg; continue; } + var m = arg.indexOf("=") == -1 ? arg : arg.substr(0, arg.indexOf("=")); + switch(m) { + case "-": filename = "-"; break; + + case "--help": case "-h": process.exit(help()); break; + case "--version": case "-V": process.exit(version()); break; + + case "--signed": case "-d": fmt = "%d"; break; + case "--unsigned": case "-u": fmt = "%u"; break; + case "--hex": case "-x": fmt = "%0.8x"; break; + case "--HEX": case "-X": fmt = "%0.8X"; break; + case "--format": case "-F": + fmt = ((m!=arg) ? arg.substr(m.length+1) : args[++i])||""; break; + + case "--hex-seed": case "-H": r = 16; + /* falls through */ + case "--seed": case "-S": + seed=parseInt((m!=arg) ? arg.substr(m.length+1) : args[++i], r)||0; break; + + default: die("crc32: unrecognized option `" + arg + "'", 22); + } +} if(!process.stdin.isTTY) filename = filename || "-"; +if(filename.length===0) die("crc32: must specify a filename ('-' for stdin)",1); -if(!filename) { - console.error("crc32: must specify a filename ('-' for stdin)"); - process.exit(1); -} - -if(filename === "-h" || filename === "--help") { - console.log("usage: " + process.argv[0] + " [filename]"); - process.exit(0); -} - -if(filename !== "-" && !fs.existsSync(filename)) { - console.error("crc32: " + filename + ": No such file or directory"); - process.exit(2); +function process_data(data/*:Buffer*/) { + var out/*:CRC32Type*/ = X.buf(data, seed); + return console.log(fmt === "" ? out : require("printj").sprintf(fmt, out)); } if(filename === "-") process.stdin.pipe(require('concat-stream')(process_data)); -else process_data(fs.readFileSync(filename)); - -function process_data(data) { - console.log(X.buf(data)); -} +else if(fs.existsSync(filename)) process_data(fs.readFileSync(filename)); +else die("crc32: " + filename + ": No such file or directory", 2); diff --git a/bits/01_version.js b/bits/01_version.js index faa6d9c..d9dd0f3 100644 --- a/bits/01_version.js +++ b/bits/01_version.js @@ -1 +1 @@ -CRC32.version = '0.4.1'; +CRC32.version = '1.0.0'; diff --git a/bits/40_crc.js b/bits/40_crc.js index 1153876..bd2cbb6 100644 --- a/bits/40_crc.js +++ b/bits/40_crc.js @@ -1,9 +1,9 @@ /*# charCodeAt is the best approach for binary strings */ /*global Buffer */ var use_buffer = typeof Buffer !== 'undefined'; -function crc32_bstr(bstr/*:string*/)/*:CRC32Type*/ { - if(bstr.length > 32768) if(use_buffer) return crc32_buf_8(new Buffer(bstr)); - var C = -1, L = bstr.length - 1; +function crc32_bstr(bstr/*:string*/, seed/*:?CRC32Type*/)/*:CRC32Type*/ { + if(bstr.length > 32768) if(use_buffer) return crc32_buf_8(new Buffer(bstr), seed); + var C = seed/*:: ? 0 : 0 */ ^ -1, L = bstr.length - 1; for(var i = 0; i < L;) { C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF]; C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF]; @@ -12,9 +12,9 @@ function crc32_bstr(bstr/*:string*/)/*:CRC32Type*/ { return C ^ -1; } -function crc32_buf(buf/*:ABuf*/)/*:CRC32Type*/ { - if(buf.length > 10000) return crc32_buf_8(buf); - var C = -1, L = buf.length - 3; +function crc32_buf(buf/*:ABuf*/, seed/*:?CRC32Type*/)/*:CRC32Type*/ { + if(buf.length > 10000) return crc32_buf_8(buf, seed); + var C = seed/*:: ? 0 : 0 */ ^ -1, L = buf.length - 3; for(var i = 0; i < L;) { C = (C>>>8) ^ T[(C^buf[i++])&0xFF]; C = (C>>>8) ^ T[(C^buf[i++])&0xFF]; @@ -25,8 +25,8 @@ function crc32_buf(buf/*:ABuf*/)/*:CRC32Type*/ { return C ^ -1; } -function crc32_buf_8(buf/*:ABuf*/)/*:CRC32Type*/ { - var C = -1, L = buf.length - 7; +function crc32_buf_8(buf/*:ABuf*/, seed/*:?CRC32Type*/)/*:CRC32Type*/ { + var C = seed/*:: ? 0 : 0 */ ^ -1, L = buf.length - 7; for(var i = 0; i < L;) { C = (C>>>8) ^ T[(C^buf[i++])&0xFF]; C = (C>>>8) ^ T[(C^buf[i++])&0xFF]; @@ -42,8 +42,8 @@ function crc32_buf_8(buf/*:ABuf*/)/*:CRC32Type*/ { } /*# much much faster to intertwine utf8 and C */ -function crc32_str(str/*:string*/)/*:CRC32Type*/ { - var C = -1; +function crc32_str(str/*:string*/, seed/*:?CRC32Type*/)/*:CRC32Type*/ { + var C = seed/*:: ? 0 : 0 */ ^ -1; for(var i = 0, L=str.length, c, d; i < L;) { c = str.charCodeAt(i++); if(c < 0x80) { diff --git a/crc32.flow.js b/crc32.flow.js index 74d6de5..422724c 100644 --- a/crc32.flow.js +++ b/crc32.flow.js @@ -23,7 +23,7 @@ var CRC32; } /*jshint ignore:end */ }(function(CRC32) { -CRC32.version = '0.4.1'; +CRC32.version = '1.0.0'; /*:: type CRC32Type = number; type ABuf = Array | Buffer; @@ -54,9 +54,9 @@ var T = signed_crc_table(); /*# charCodeAt is the best approach for binary strings */ /*global Buffer */ var use_buffer = typeof Buffer !== 'undefined'; -function crc32_bstr(bstr/*:string*/)/*:CRC32Type*/ { - if(bstr.length > 32768) if(use_buffer) return crc32_buf_8(new Buffer(bstr)); - var C = -1, L = bstr.length - 1; +function crc32_bstr(bstr/*:string*/, seed/*:?CRC32Type*/)/*:CRC32Type*/ { + if(bstr.length > 32768) if(use_buffer) return crc32_buf_8(new Buffer(bstr), seed); + var C = seed/*:: ? 0 : 0 */ ^ -1, L = bstr.length - 1; for(var i = 0; i < L;) { C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF]; C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF]; @@ -65,9 +65,9 @@ function crc32_bstr(bstr/*:string*/)/*:CRC32Type*/ { return C ^ -1; } -function crc32_buf(buf/*:ABuf*/)/*:CRC32Type*/ { - if(buf.length > 10000) return crc32_buf_8(buf); - var C = -1, L = buf.length - 3; +function crc32_buf(buf/*:ABuf*/, seed/*:?CRC32Type*/)/*:CRC32Type*/ { + if(buf.length > 10000) return crc32_buf_8(buf, seed); + var C = seed/*:: ? 0 : 0 */ ^ -1, L = buf.length - 3; for(var i = 0; i < L;) { C = (C>>>8) ^ T[(C^buf[i++])&0xFF]; C = (C>>>8) ^ T[(C^buf[i++])&0xFF]; @@ -78,8 +78,8 @@ function crc32_buf(buf/*:ABuf*/)/*:CRC32Type*/ { return C ^ -1; } -function crc32_buf_8(buf/*:ABuf*/)/*:CRC32Type*/ { - var C = -1, L = buf.length - 7; +function crc32_buf_8(buf/*:ABuf*/, seed/*:?CRC32Type*/)/*:CRC32Type*/ { + var C = seed/*:: ? 0 : 0 */ ^ -1, L = buf.length - 7; for(var i = 0; i < L;) { C = (C>>>8) ^ T[(C^buf[i++])&0xFF]; C = (C>>>8) ^ T[(C^buf[i++])&0xFF]; @@ -95,8 +95,8 @@ function crc32_buf_8(buf/*:ABuf*/)/*:CRC32Type*/ { } /*# much much faster to intertwine utf8 and C */ -function crc32_str(str/*:string*/)/*:CRC32Type*/ { - var C = -1; +function crc32_str(str/*:string*/, seed/*:?CRC32Type*/)/*:CRC32Type*/ { + var C = seed/*:: ? 0 : 0 */ ^ -1; for(var i = 0, L=str.length, c, d; i < L;) { c = str.charCodeAt(i++); if(c < 0x80) { diff --git a/crc32.js b/crc32.js index 19af237..5bf1634 100644 --- a/crc32.js +++ b/crc32.js @@ -21,7 +21,7 @@ var CRC32; } /*jshint ignore:end */ }(function(CRC32) { -CRC32.version = '0.4.1'; +CRC32.version = '1.0.0'; /* see perf/crc32table.js */ /*global Int32Array */ function signed_crc_table() { @@ -46,9 +46,9 @@ function signed_crc_table() { var T = signed_crc_table(); /*global Buffer */ var use_buffer = typeof Buffer !== 'undefined'; -function crc32_bstr(bstr) { - if(bstr.length > 32768) if(use_buffer) return crc32_buf_8(new Buffer(bstr)); - var C = -1, L = bstr.length - 1; +function crc32_bstr(bstr, seed) { + if(bstr.length > 32768) if(use_buffer) return crc32_buf_8(new Buffer(bstr), seed); + var C = seed ^ -1, L = bstr.length - 1; for(var i = 0; i < L;) { C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF]; C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF]; @@ -57,9 +57,9 @@ function crc32_bstr(bstr) { return C ^ -1; } -function crc32_buf(buf) { - if(buf.length > 10000) return crc32_buf_8(buf); - var C = -1, L = buf.length - 3; +function crc32_buf(buf, seed) { + if(buf.length > 10000) return crc32_buf_8(buf, seed); + var C = seed ^ -1, L = buf.length - 3; for(var i = 0; i < L;) { C = (C>>>8) ^ T[(C^buf[i++])&0xFF]; C = (C>>>8) ^ T[(C^buf[i++])&0xFF]; @@ -70,8 +70,8 @@ function crc32_buf(buf) { return C ^ -1; } -function crc32_buf_8(buf) { - var C = -1, L = buf.length - 7; +function crc32_buf_8(buf, seed) { + var C = seed ^ -1, L = buf.length - 7; for(var i = 0; i < L;) { C = (C>>>8) ^ T[(C^buf[i++])&0xFF]; C = (C>>>8) ^ T[(C^buf[i++])&0xFF]; @@ -86,8 +86,8 @@ function crc32_buf_8(buf) { return C ^ -1; } -function crc32_str(str) { - var C = -1; +function crc32_str(str, seed) { + var C = seed ^ -1; for(var i = 0, L=str.length, c, d; i < L;) { c = str.charCodeAt(i++); if(c < 0x80) { diff --git a/ctest/crc32.js b/ctest/crc32.js index 19af237..5bf1634 100644 --- a/ctest/crc32.js +++ b/ctest/crc32.js @@ -21,7 +21,7 @@ var CRC32; } /*jshint ignore:end */ }(function(CRC32) { -CRC32.version = '0.4.1'; +CRC32.version = '1.0.0'; /* see perf/crc32table.js */ /*global Int32Array */ function signed_crc_table() { @@ -46,9 +46,9 @@ function signed_crc_table() { var T = signed_crc_table(); /*global Buffer */ var use_buffer = typeof Buffer !== 'undefined'; -function crc32_bstr(bstr) { - if(bstr.length > 32768) if(use_buffer) return crc32_buf_8(new Buffer(bstr)); - var C = -1, L = bstr.length - 1; +function crc32_bstr(bstr, seed) { + if(bstr.length > 32768) if(use_buffer) return crc32_buf_8(new Buffer(bstr), seed); + var C = seed ^ -1, L = bstr.length - 1; for(var i = 0; i < L;) { C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF]; C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF]; @@ -57,9 +57,9 @@ function crc32_bstr(bstr) { return C ^ -1; } -function crc32_buf(buf) { - if(buf.length > 10000) return crc32_buf_8(buf); - var C = -1, L = buf.length - 3; +function crc32_buf(buf, seed) { + if(buf.length > 10000) return crc32_buf_8(buf, seed); + var C = seed ^ -1, L = buf.length - 3; for(var i = 0; i < L;) { C = (C>>>8) ^ T[(C^buf[i++])&0xFF]; C = (C>>>8) ^ T[(C^buf[i++])&0xFF]; @@ -70,8 +70,8 @@ function crc32_buf(buf) { return C ^ -1; } -function crc32_buf_8(buf) { - var C = -1, L = buf.length - 7; +function crc32_buf_8(buf, seed) { + var C = seed ^ -1, L = buf.length - 7; for(var i = 0; i < L;) { C = (C>>>8) ^ T[(C^buf[i++])&0xFF]; C = (C>>>8) ^ T[(C^buf[i++])&0xFF]; @@ -86,8 +86,8 @@ function crc32_buf_8(buf) { return C ^ -1; } -function crc32_str(str) { - var C = -1; +function crc32_str(str, seed) { + var C = seed ^ -1; for(var i = 0, L=str.length, c, d; i < L;) { c = str.charCodeAt(i++); if(c < 0x80) { diff --git a/ctest/fakeassert.js b/ctest/fakeassert.js index dd20b48..16eb822 100644 --- a/ctest/fakeassert.js +++ b/ctest/fakeassert.js @@ -1,2 +1,2 @@ var assert = {}; -assert.equal = function(x,y) { if(x !== y) throw x + " !== " + y; }; +assert.equal = function(x,y) { if(x !== y) throw new Error(x + " !== " + y); }; diff --git a/ctest/fixtures.js b/ctest/fixtures.js index 0132362..78c2533 100644 --- a/ctest/fixtures.js +++ b/ctest/fixtures.js @@ -17,9 +17,22 @@ type Stringifier = {(d:ArrayLike):string}; declare class CRC32Module { table:CRC32TableType; - bstr(s:string):CRC32Type; - buf(b:ABuf):CRC32Type; - str(s:string):CRC32Type; + bstr(s:string, seed:?CRC32Type):CRC32Type; + buf(b:ABuf, seed:?CRC32Type):CRC32Type; + str(s:string, seed:?CRC32Type):CRC32Type; + version:string; +}; +*/ +/*:: +type _CB = {(data:Buffer):void;}; +declare module 'concat-stream' {declare function exports(f:_CB):stream$Duplex;}; +declare module 'exit-on-epipe' {}; + +declare module 'crc-32' { declare var exports:CRC32Module; }; +declare module '../' { declare var exports:CRC32Module; }; + +declare module 'printj' { + declare function sprintf(fmt:string, ...args:any):string; }; */ /* vim: set ts=2: */ @@ -33,13 +46,13 @@ var node_crc = require('./node-crc'); function z1(bstr) { return js_crc32.bstr(bstr); } function z2(bstr) { return buffer_crc32.signed(bstr); } function z3(bstr) { return crc32(bstr); } -function z4(bstr) { return node_crc.crc32(bstr);} +function z4(bstr) { return node_crc.crc32(bstr)|0;} function z5(bstr) { return js_crc32_old.bstr(bstr); } function b1(buf) { return js_crc32.buf(buf); } function b2(buf) { return buffer_crc32.signed(buf); } function b3(buf) { return crc32(buf); } -function b4(buf) { return node_crc.crc32(buf); } +function b4(buf) { return node_crc.crc32(buf)|0; } function b5(buf) { return js_crc32_old.buf(buf); } function u1(str) { return js_crc32.str(str); } @@ -97,14 +110,14 @@ if(btest) for(var j = 0; j != ntests; ++j) { if(do_bstr) { assert.equal(z1(bstr_tests[j][0]), z2(bstr_tests[j][0])); assert.equal(z1(bstr_tests[j][0]), fix(z3(bstr_tests[j][0]))); - assert.equal(z1(bstr_tests[j][0]), fix(z4(bstr_tests[j][0]))); + assert.equal(z1(bstr_tests[j][0]), (z4(bstr_tests[j][0]))); assert.equal(z1(bstr_tests[j][0]), z5(bstr_tests[j][0])); } if(do_buf) { assert.equal(b1(bstr_tests[j][1]), b2(bstr_tests[j][1])); assert.equal(b1(bstr_tests[j][1]), fix(b3(bstr_tests[j][1]))); - assert.equal(b1(bstr_tests[j][1]), fix(b4(bstr_tests[j][1]))); + assert.equal(b1(bstr_tests[j][1]), (b4(bstr_tests[j][1]))); assert.equal(b1(bstr_tests[j][1]), b5(bstr_tests[j][1])); } } diff --git a/ctest/index.html b/ctest/index.html index 417db5f..b275f3f 100644 --- a/ctest/index.html +++ b/ctest/index.html @@ -8,6 +8,7 @@
+ diff --git a/ctest/shim.js b/ctest/shim.js new file mode 100644 index 0000000..e3d7840 --- /dev/null +++ b/ctest/shim.js @@ -0,0 +1,237 @@ +// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys +if (!Object.keys) { + Object.keys = (function () { + var hasOwnProperty = Object.prototype.hasOwnProperty, + hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), + dontEnums = [ + 'toString', + 'toLocaleString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'constructor' + ], + dontEnumsLength = dontEnums.length; + + return function (obj) { + if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object'); + + var result = []; + + for (var prop in obj) { + if (hasOwnProperty.call(obj, prop)) result.push(prop); + } + + if (hasDontEnumBug) { + for (var i=0; i < dontEnumsLength; i++) { + if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]); + } + } + return result; + }; + })(); +} + +// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter +if (!Array.prototype.filter) +{ + Array.prototype.filter = function(fun /*, thisp */) + { + "use strict"; + + if (this == null) + throw new TypeError(); + + var t = Object(this); + var len = t.length >>> 0; + if (typeof fun != "function") + throw new TypeError(); + + var res = []; + var thisp = arguments[1]; + for (var i = 0; i < len; i++) + { + if (i in t) + { + var val = t[i]; // in case fun mutates this + if (fun.call(thisp, val, i, t)) + res.push(val); + } + } + + return res; + }; +} + +// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim +if (!String.prototype.trim) { + String.prototype.trim = function () { + return this.replace(/^\s+|\s+$/g, ''); + }; +} + +// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach +if (!Array.prototype.forEach) +{ + Array.prototype.forEach = function(fun /*, thisArg */) + { + "use strict"; + + if (this === void 0 || this === null) + throw new TypeError(); + + var t = Object(this); + var len = t.length >>> 0; + if (typeof fun !== "function") + throw new TypeError(); + + var thisArg = arguments.length >= 2 ? arguments[1] : void 0; + for (var i = 0; i < len; i++) + { + if (i in t) + fun.call(thisArg, t[i], i, t); + } + }; +} + +// Production steps of ECMA-262, Edition 5, 15.4.4.19 +// Reference: http://es5.github.com/#x15.4.4.19 +if (!Array.prototype.map) { + Array.prototype.map = function(callback, thisArg) { + + var T, A, k; + + if (this == null) { + throw new TypeError(" this is null or not defined"); + } + + // 1. Let O be the result of calling ToObject passing the |this| value as the argument. + var O = Object(this); + + // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length". + // 3. Let len be ToUint32(lenValue). + var len = O.length >>> 0; + + // 4. If IsCallable(callback) is false, throw a TypeError exception. + // See: http://es5.github.com/#x9.11 + if (typeof callback !== "function") { + throw new TypeError(callback + " is not a function"); + } + + // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. + if (thisArg) { + T = thisArg; + } + + // 6. Let A be a new array created as if by the expression new Array(len) where Array is + // the standard built-in constructor with that name and len is the value of len. + A = new Array(len); + + // 7. Let k be 0 + k = 0; + + // 8. Repeat, while k < len + while(k < len) { + + var kValue, mappedValue; + + // a. Let Pk be ToString(k). + // This is implicit for LHS operands of the in operator + // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk. + // This step can be combined with c + // c. If kPresent is true, then + if (k in O) { + + // i. Let kValue be the result of calling the Get internal method of O with argument Pk. + kValue = O[ k ]; + + // ii. Let mappedValue be the result of calling the Call internal method of callback + // with T as the this value and argument list containing kValue, k, and O. + mappedValue = callback.call(T, kValue, k, O); + + // iii. Call the DefineOwnProperty internal method of A with arguments + // Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true}, + // and false. + + // In browsers that support Object.defineProperty, use the following: + // Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true }); + + // For best browser support, use the following: + A[ k ] = mappedValue; + } + // d. Increase k by 1. + k++; + } + + // 9. return A + return A; + }; +} + +// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf +if (!Array.prototype.indexOf) { + Array.prototype.indexOf = function (searchElement, fromIndex) { + if ( this === undefined || this === null ) { + throw new TypeError( '"this" is null or not defined' ); + } + + var length = this.length >>> 0; // Hack to convert object.length to a UInt32 + + fromIndex = +fromIndex || 0; + + if (Math.abs(fromIndex) === Infinity) { + fromIndex = 0; + } + + if (fromIndex < 0) { + fromIndex += length; + if (fromIndex < 0) { + fromIndex = 0; + } + } + + for (;fromIndex < length; fromIndex++) { + if (this[fromIndex] === searchElement) { + return fromIndex; + } + } + + return -1; + }; +} +// Based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray + +if (! Array.isArray) { + Array.isArray = function(obj) { + return Object.prototype.toString.call(obj) === "[object Array]"; + }; +} + +// https://github.com/ttaubert/node-arraybuffer-slice +// (c) 2013 Tim Taubert +// arraybuffer-slice may be freely distributed under the MIT license. + +"use strict"; + +if (typeof ArrayBuffer !== 'undefined' && !ArrayBuffer.prototype.slice) { + ArrayBuffer.prototype.slice = function (begin, end) { + begin = (begin|0) || 0; + var num = this.byteLength; + end = end === (void 0) ? num : (end|0); + + // Handle negative values. + if (begin < 0) begin += num; + if (end < 0) end += num; + + if (num === 0 || begin >= num || begin >= end) { + return new ArrayBuffer(0); + } + + var length = Math.min(num - begin, end - begin); + var target = new ArrayBuffer(length); + var targetArray = new Uint8Array(target); + targetArray.set(new Uint8Array(this, begin, length)); + return target; + }; +} diff --git a/ctest/test.js b/ctest/test.js index 319fb60..ace7a20 100644 --- a/ctest/test.js +++ b/ctest/test.js @@ -10,6 +10,16 @@ if(typeof require !== 'undefined') { function readlines(f) { return fs.readFileSync(f, "ascii").split("\n"); } +function msieversion() +{ + if(typeof window == 'undefined') return Infinity; + if(typeof window.navigator == 'undefined') return Infinity; + var ua = window.navigator.userAgent + var msie = ua.indexOf ( "MSIE " ) + if(msie < 0) return Infinity; + return parseInt (ua.substring (msie+5, ua.indexOf (".", msie ))); +} + describe('crc32 table', function() { it('should match fixed table', function() { var overflow = 0; @@ -25,10 +35,25 @@ describe('crc32 bits', function() { bits.forEach(function(i) { var msg = i[0], l = i[0].length, L = i[1]|0; if(l > 20) msg = i[0].substr(0,5) + "...(" + l + ")..." + i[0].substr(-5); + if(l > 100 && msieversion() < 7) return; it(msg, function() { if(i[2] === 1) assert.equal(X.bstr(i[0]), L); assert.equal(X.str(i[0]), i[1]|0); if(typeof Buffer !== 'undefined') assert.equal(X.buf(new Buffer(i[0])), L); + for(var x = 0; x < i[0].length; ++x) { + if(i[0].charCodeAt(x) >= 0xD800 && i[0].charCodeAt(x) < 0xE000) continue; + if(i[2] === 1) { + var bstrcrc = X.bstr(i[0].substr(x), X.bstr(i[0].substr(0, x))); + assert.equal(bstrcrc, L); + } + var strcrc = X.str(i[0].substr(x), X.str(i[0].substr(0, x))); + assert.equal(strcrc, i[1]|0); + if(typeof Buffer !== 'undefined') { + var buf = new Buffer(i[0]); + var bufcrc = X.buf(buf.slice(x), X.buf(buf.slice(0, x))); + assert.equal(bufcrc, L); + } + } }); }); }); @@ -46,9 +71,9 @@ if(typeof require !== 'undefined') describe("unicode", function() { if(c.charCodeAt(0) >= 0xD800 && c.charCodeAt(0) < 0xE000) continue; var cc = corpus[ucidx], dd = X.str(c); assert.equal(dd, cc, ":" + ucidx + ":" + c + ":" + cc + ":" + dd); - var ee = X.buf(new Buffer(c, "utf8")); - assert.equal(ee, cc, ":" + ucidx + ":" + c + ":" + cc + ":" + ee); if(typeof Buffer !== 'undefined') { + var ee = X.buf(new Buffer(c, "utf8")); + assert.equal(ee, cc, ":" + ucidx + ":" + c + ":" + cc + ":" + ee); var ff = X.bstr(String.fromCharCode.apply(null, new Buffer(c, "utf8"))); assert.equal(ff, cc, ":" + ucidx + ":" + c + ":" + cc + ":" + ff); } diff --git a/demo/browser.flow.js b/demo/browser.flow.js index 7ad9d77..31b9504 100644 --- a/demo/browser.flow.js +++ b/demo/browser.flow.js @@ -26,10 +26,10 @@ function make_chunk_buf_to_str(BType/*:function*/)/*:Stringifier*/ { }; } /*# buffer to binary string */ -var bstrify/*:Stringifier*/ = make_chunk_buf_to_str(Uint8Array); +var bstrify/*:Stringifier*/ = make_chunk_buf_to_str(typeof Uint8Array !== 'undefined' ? Uint8Array : Array); /*# readAsBinaryString support */ -var rABS/*:boolean*/ = is_defined(FileReader, ['prototype', 'readAsBinaryString']); +var rABS/*:boolean*/ = typeof FileReader !== 'undefined' && is_defined(FileReader, ['prototype', 'readAsBinaryString']); var userABS/*:HTMLInputElement*/ = (document.getElementsByName("userabs")[0]/*:any*/); if(!rABS) { userABS.disabled = true; @@ -37,7 +37,7 @@ if(!rABS) { } /*## Process Result */ -/*:: declare class HTMLPreElement extends HTMLElement { innerText:string; } */ +/*:: declare class HTMLPreElement extends HTMLElement { innerText?:string; } */ function process_value(val/*:CRC32Type*/) { var output = []; output[0] = "Signed : " + val; diff --git a/demo/browser.js b/demo/browser.js index 1645f3f..d3d2933 100644 --- a/demo/browser.js +++ b/demo/browser.js @@ -23,9 +23,9 @@ function make_chunk_buf_to_str(BType) { return o; }; } -var bstrify = make_chunk_buf_to_str(Uint8Array); +var bstrify = make_chunk_buf_to_str(typeof Uint8Array !== 'undefined' ? Uint8Array : Array); -var rABS = is_defined(FileReader, ['prototype', 'readAsBinaryString']); +var rABS = typeof FileReader !== 'undefined' && is_defined(FileReader, ['prototype', 'readAsBinaryString']); var userABS = (document.getElementsByName("userabs")[0]); if(!rABS) { userABS.disabled = true; diff --git a/index.html b/index.html index 6dfdc53..fbd5138 100644 --- a/index.html +++ b/index.html @@ -34,6 +34,7 @@ Use readAsBinaryString: (when available) .
+