version bump 0.4.0

- simplified utf8 code
- added browser demo
- added command line tool adler32
- fixed unicode baseline script (node 6 changed default array printing)
- fixed performance tests (benchmark module changed behavior)
- updated travis versions for test
- miscellaneous adjustments to tooling
This commit is contained in:
SheetJS 2016-05-29 19:13:34 -04:00
parent 8215562b11
commit b692b3f7df
30 changed files with 651 additions and 145 deletions

View File

@ -9,9 +9,14 @@
.*/misc/.*
.*/perf/.*
.*/demo/browser.js
[include]
adler32.flow.js
.*/demo/browser.flow.js
[libs]
bits/10_types.js
misc/flow.js
[options]

1
.gitignore vendored
View File

@ -3,4 +3,3 @@ test_files/*.py
test_files/*.js
test_files/baseline*
misc/coverage.html
misc/*/

View File

@ -2,4 +2,3 @@
"bitwise": false,
"curly": false
}

View File

@ -1,7 +1,8 @@
language: node_js
node_js:
- "5.0"
- "4.2"
- "6"
- "5"
- "4"
- "0.12"
- "0.10"
- "0.8"

View File

@ -1,79 +1,88 @@
LIB=adler32
REQS=
ADDONS=
AUXTARGETS=
AUXTARGETS=demo/browser.js
HTMLLINT=index.html
ULIB=$(shell echo $(LIB) | tr a-z A-Z)
DEPS=$(sort $(wildcard bits/*.js))
TARGET=$(LIB).js
FLOWTARGET=$(LIB).flow.js
## Main Targets
.PHONY: all
all: $(TARGET) $(AUXTARGETS)
all: $(TARGET) $(AUXTARGETS) ## Build library and auxiliary scripts
$(TARGET) $(AUXTARGETS): %.js : %.flow.js
node -e 'process.stdout.write(require("fs").readFileSync("$<","utf8").replace(/^\s*\/\*:[^*]*\*\/\s*(\n)?/gm,"").replace(/\/\*:[^*]*\*\//gm,""))' > $@
node -e 'process.stdout.write(require("fs").readFileSync("$<","utf8").replace(/^[ \t]*\/\*[:#][^*]*\*\/\s*(\n)?/gm,"").replace(/\/\*[:#][^*]*\*\//gm,""))' > $@
$(LIB).flow.js: $(DEPS)
$(FLOWTARGET): $(DEPS)
cat $^ | tr -d '\15\32' > $@
bits/01_version.js: package.json
echo "ADLER32.version = '"`grep version package.json | awk '{gsub(/[^0-9a-z\.-]/,"",$$2); print $$2}'`"';" > $@
.PHONY: clean
clean: clean-baseline
rm -f $(TARGET)
clean: clean-baseline ## Remove targets and build artifacts
rm -f $(TARGET) $(FLOWTARGET)
## Testing
.PHONY: test mocha
test mocha: test.js $(TARGET) baseline
test mocha: test.js $(TARGET) baseline ## Run test suite
mocha -R spec -t 20000
.PHONY: ctest
ctest:
ctest: ## Build browser test (into ctest/ subdirectory)
cat misc/*.js > ctest/fixtures.js
cp -f test.js ctest/test.js
cp -f $(TARGET) ctest/
.PHONY: ctestserv
ctestserv: ## Start a test server on port 8000
@cd ctest && python -mSimpleHTTPServer
.PHONY: baseline
baseline: ## Build test baselines
@bash ./misc/make_baseline.sh
.PHONY: clean-baseline
clean-baseline: ## Remove test baselines
@bash ./misc/make_baseline.sh clean
## Code Checking
.PHONY: lint
lint: $(TARGET) $(AUXTARGETS)
jshint --show-non-errors $(TARGET) $(AUXTARGETS)
jshint --show-non-errors package.json
jscs $(TARGET) $(AUXTARGETS)
lint: $(TARGET) $(AUXTARGETS) ## Run jshint and jscs checks
@jshint --show-non-errors $(TARGET) $(AUXTARGETS)
@jshint --show-non-errors package.json
@jshint --show-non-errors --extract=always $(HTMLLINT)
@jscs $(TARGET) $(AUXTARGETS)
.PHONY: flow
flow: lint
flow check --all --show-all-errors
flow: lint ## Run flow checker
@flow check --all --show-all-errors
.PHONY: cov cov-spin
cov: misc/coverage.html
cov-spin:
make cov & bash misc/spin.sh $$!
COVFMT=$(patsubst %,cov_%,$(FMT))
.PHONY: $(COVFMT)
$(COVFMT): cov_%:
FMTS=$* make cov
.PHONY: cov
cov: misc/coverage.html ## Run coverage test
misc/coverage.html: $(TARGET) test.js
mocha --require blanket -R html-cov -t 20000 > $@
.PHONY: coveralls coveralls-spin
coveralls:
mocha --require blanket --reporter mocha-lcov-reporter -t 20000 | ./node_modules/coveralls/bin/coveralls.js
coveralls-spin:
make coveralls & bash misc/spin.sh $$!
.PHONY: coveralls
coveralls: ## Coverage Test + Send to coveralls.io
mocha --require blanket --reporter mocha-lcov-reporter -t 20000 | node ./node_modules/coveralls/bin/coveralls.js
.PHONY: perf
perf:
bash perf/perf.sh
perf: ## Run Performance Tests
@bash perf/perf.sh
.PHONY: perf-all
perf-all:
bash misc/perf.sh
.PHONY: baseline clean-baseline
baseline:
./misc/make_baseline.sh
.PHONY: help
help:
@grep -hE '(^[a-zA-Z_-][ a-zA-Z_-]*:.*?|^#[#*])' $(MAKEFILE_LIST) | bash misc/help.sh
clean-baseline:
rm -f test_files/*.*
#* To show a spinner, append "-spin" to any target e.g. cov-spin
%-spin:
@make $* & bash misc/spin.sh $$!

View File

@ -5,7 +5,7 @@ Emphasis on correctness and performance.
## Installation
In [nodejs](https://www.npmjs.org/package/adler-32):
With [npm](https://www.npmjs.org/package/adler-32):
npm install adler-32
@ -15,6 +15,9 @@ In the browser:
The browser exposes a variable ADLER32
When installed globally, npm installs a script `adler32` that computes the
checksum for a specified file or standard input.
## Usage
- `ADLER32.buf(byte array or buffer)` assumes the argument is a set of 8 bit
@ -27,9 +30,12 @@ The browser exposes a variable ADLER32
## Testing
`make test` will run the nodejs-based test. To run the in-browser tests, run a
local server and go to the `ctest` directory. To update the browser artifacts,
run `make ctest`.
`make test` will run the nodejs-based test.
To run the in-browser tests, run a local server and go to the `ctest` directory.
`make ctestserv` will start a python `SimpleHTTPServer` server on port 8000.
To update the browser artifacts, run `make ctest`.
To generate the bits file, use the `adler32` function from python zlib:
@ -44,10 +50,25 @@ To generate the bits file, use the `adler32` function from python zlib:
2023497376
```
The included `adler32.njs` script can process files or stdin:
```
$ echo "this is a test" > t.txt
$ bin/adler32.njs t.txt
726861088
```
For comparison, the included `adler32.py` script uses python zlib:
```
$ bin/adler32.py t.txt
726861088
```
## Performance
`make perf` will run algorithmic performance tests (which should justify certain
decisions in the code).
decisions in the code).
[js-crc](http://git.io/crc32) has more performance notes

View File

@ -1,9 +1,11 @@
/* adler32.js (C) 2014-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*exported ADLER32 */
var ADLER32;
/*:: declare var DO_NOT_EXPORT_ADLER: any; */
/*:: declare var define: any; */
(function (factory) {
/*jshint ignore:start */
if(typeof DO_NOT_EXPORT_ADLER === 'undefined') {
if('object' === typeof exports) {
factory(exports);
@ -19,18 +21,20 @@ var ADLER32;
} else {
factory(ADLER32 = {});
}
/*jshint ignore:end */
}(function(ADLER32) {
ADLER32.version = '0.3.0';
ADLER32.version = '0.4.0';
/*::
type ADLER32Type = number;
type ABuf = Array<number> | Buffer;
*/
/* consult README.md for the magic number */
/* charCodeAt is the best approach for binary strings */
/*# consult README.md for the magic number */
/*# charCodeAt is the best approach for binary strings */
/*global Buffer */
var use_buffer = typeof Buffer !== 'undefined';
function adler32_bstr(bstr/*:string*/)/*:ADLER32Type*/ {
if(bstr.length > 32768) if(use_buffer) return adler32_buf(new Buffer(bstr));
var a = 1, b = 0, L = bstr.length, M;
var a = 1, b = 0, L = bstr.length, M = 0;
for(var i = 0; i < L;) {
M = Math.min(L-i, 3850)+i;
for(;i<M;i++) {
@ -44,7 +48,7 @@ function adler32_bstr(bstr/*:string*/)/*:ADLER32Type*/ {
}
function adler32_buf(buf/*:ABuf*/)/*:ADLER32Type*/ {
var a = 1, b = 0, L = buf.length, M;
var a = 1, b = 0, L = buf.length, M = 0;
for(var i = 0; i < L;) {
M = Math.min(L-i, 3850)+i;
for(;i<M;i++) {
@ -57,31 +61,32 @@ function adler32_buf(buf/*:ABuf*/)/*:ADLER32Type*/ {
return ((b%65521) << 16) | (a%65521);
}
/* much much faster to intertwine utf8 and adler */
/*# much much faster to intertwine utf8 and adler */
function adler32_str(str/*:string*/)/*:ADLER32Type*/ {
var a = 1, b = 0, L = str.length, M, c, d;
var a = 1, b = 0, L = str.length, M = 0, c = 0, d = 0;
for(var i = 0; i < L;) {
M = Math.min(L-i, 3850);
while(M>0) {
c = str.charCodeAt(i++);
if(c < 0x80) { a += c; b += a; --M; }
if(c < 0x80) { a += c; }
else if(c < 0x800) {
a += 192|((c>>6)&31); b += a; --M;
a += 128|(c&63); b += a; --M;
a += 128|(c&63);
} else if(c >= 0xD800 && c < 0xE000) {
c = (c&1023)+64; d = str.charCodeAt(i++) & 1023;
a += 240|((c>>8)&7); b += a; --M;
a += 128|((c>>2)&63); b += a; --M;
a += 128|((d>>6)&15)|((c&3)<<4); b += a; --M;
a += 128|(d&63); b += a; --M;
a += 128|(d&63);
} else {
a += 224|((c>>12)&15); b += a; --M;
a += 128|((c>>6)&63); b += a; --M;
a += 128|(c&63); b += a; --M;
a += 128|(c&63);
}
b += a; --M;
}
a %= 65521;
b %= 65521;
a = (15*(a>>>16)+(a&65535));
b = (15*(b>>>16)+(b&65535));
}
return (b << 16) | a;
}

View File

@ -1,7 +1,9 @@
/* adler32.js (C) 2014-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*exported ADLER32 */
var ADLER32;
(function (factory) {
/*jshint ignore:start */
if(typeof DO_NOT_EXPORT_ADLER === 'undefined') {
if('object' === typeof exports) {
factory(exports);
@ -17,14 +19,14 @@ var ADLER32;
} else {
factory(ADLER32 = {});
}
/*jshint ignore:end */
}(function(ADLER32) {
ADLER32.version = '0.3.0';
/* consult README.md for the magic number */
/* charCodeAt is the best approach for binary strings */
ADLER32.version = '0.4.0';
/*global Buffer */
var use_buffer = typeof Buffer !== 'undefined';
function adler32_bstr(bstr) {
if(bstr.length > 32768) if(use_buffer) return adler32_buf(new Buffer(bstr));
var a = 1, b = 0, L = bstr.length, M;
var a = 1, b = 0, L = bstr.length, M = 0;
for(var i = 0; i < L;) {
M = Math.min(L-i, 3850)+i;
for(;i<M;i++) {
@ -38,7 +40,7 @@ function adler32_bstr(bstr) {
}
function adler32_buf(buf) {
var a = 1, b = 0, L = buf.length, M;
var a = 1, b = 0, L = buf.length, M = 0;
for(var i = 0; i < L;) {
M = Math.min(L-i, 3850)+i;
for(;i<M;i++) {
@ -51,31 +53,31 @@ function adler32_buf(buf) {
return ((b%65521) << 16) | (a%65521);
}
/* much much faster to intertwine utf8 and adler */
function adler32_str(str) {
var a = 1, b = 0, L = str.length, M, c, d;
var a = 1, b = 0, L = str.length, M = 0, c = 0, d = 0;
for(var i = 0; i < L;) {
M = Math.min(L-i, 3850);
while(M>0) {
c = str.charCodeAt(i++);
if(c < 0x80) { a += c; b += a; --M; }
if(c < 0x80) { a += c; }
else if(c < 0x800) {
a += 192|((c>>6)&31); b += a; --M;
a += 128|(c&63); b += a; --M;
a += 128|(c&63);
} else if(c >= 0xD800 && c < 0xE000) {
c = (c&1023)+64; d = str.charCodeAt(i++) & 1023;
a += 240|((c>>8)&7); b += a; --M;
a += 128|((c>>2)&63); b += a; --M;
a += 128|((d>>6)&15)|((c&3)<<4); b += a; --M;
a += 128|(d&63); b += a; --M;
a += 128|(d&63);
} else {
a += 224|((c>>12)&15); b += a; --M;
a += 128|((c>>6)&63); b += a; --M;
a += 128|(c&63); b += a; --M;
a += 128|(c&63);
}
b += a; --M;
}
a %= 65521;
b %= 65521;
a = (15*(a>>>16)+(a&65535));
b = (15*(b>>>16)+(b&65535));
}
return (b << 16) | a;
}

37
bin/adler32.njs Executable file
View File

@ -0,0 +1,37 @@
#!/usr/bin/env node
/* adler32.js (C) 2014-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2 ft=javascript: */
var X;
try { X = require('../'); } catch(e) { X = require('adler-32'); }
var fs = require('fs');
require('exit-on-epipe');
var args = process.argv.slice(2);
var filename;
if(args[0]) filename = args[0];
if(!process.stdin.isTTY) filename = filename || "-";
if(!filename) {
console.error("adler32: 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("adler32: " + filename + ": No such file or directory");
process.exit(2);
}
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));
}

15
bin/adler32.py Executable file
View File

@ -0,0 +1,15 @@
#!/usr/bin/env python
# adler32.py -- calculate adler32 checksum of data
# Copyright (C) 2016-present SheetJS
from zlib import adler32
from sys import argv, stdin
args=argv[1:]
payload=""
if len(args) == 0 or args[0] == "-":
payload = stdin.read()
else:
payload = open(args[0],"rb").read()
# NOTE: python 2 returns a signed value; python3 is unsigned
print adler32(payload)

View File

@ -1,9 +1,11 @@
/* adler32.js (C) 2014-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*exported ADLER32 */
var ADLER32;
/*:: declare var DO_NOT_EXPORT_ADLER: any; */
/*:: declare var define: any; */
(function (factory) {
/*jshint ignore:start */
if(typeof DO_NOT_EXPORT_ADLER === 'undefined') {
if('object' === typeof exports) {
factory(exports);
@ -19,4 +21,5 @@ var ADLER32;
} else {
factory(ADLER32 = {});
}
/*jshint ignore:end */
}(function(ADLER32) {

View File

@ -1 +1 @@
ADLER32.version = '0.3.0';
ADLER32.version = '0.4.0';

View File

@ -1,9 +1,10 @@
/* consult README.md for the magic number */
/* charCodeAt is the best approach for binary strings */
/*# consult README.md for the magic number */
/*# charCodeAt is the best approach for binary strings */
/*global Buffer */
var use_buffer = typeof Buffer !== 'undefined';
function adler32_bstr(bstr/*:string*/)/*:ADLER32Type*/ {
if(bstr.length > 32768) if(use_buffer) return adler32_buf(new Buffer(bstr));
var a = 1, b = 0, L = bstr.length, M;
var a = 1, b = 0, L = bstr.length, M = 0;
for(var i = 0; i < L;) {
M = Math.min(L-i, 3850)+i;
for(;i<M;i++) {
@ -17,7 +18,7 @@ function adler32_bstr(bstr/*:string*/)/*:ADLER32Type*/ {
}
function adler32_buf(buf/*:ABuf*/)/*:ADLER32Type*/ {
var a = 1, b = 0, L = buf.length, M;
var a = 1, b = 0, L = buf.length, M = 0;
for(var i = 0; i < L;) {
M = Math.min(L-i, 3850)+i;
for(;i<M;i++) {
@ -30,31 +31,32 @@ function adler32_buf(buf/*:ABuf*/)/*:ADLER32Type*/ {
return ((b%65521) << 16) | (a%65521);
}
/* much much faster to intertwine utf8 and adler */
/*# much much faster to intertwine utf8 and adler */
function adler32_str(str/*:string*/)/*:ADLER32Type*/ {
var a = 1, b = 0, L = str.length, M, c, d;
var a = 1, b = 0, L = str.length, M = 0, c = 0, d = 0;
for(var i = 0; i < L;) {
M = Math.min(L-i, 3850);
while(M>0) {
c = str.charCodeAt(i++);
if(c < 0x80) { a += c; b += a; --M; }
if(c < 0x80) { a += c; }
else if(c < 0x800) {
a += 192|((c>>6)&31); b += a; --M;
a += 128|(c&63); b += a; --M;
a += 128|(c&63);
} else if(c >= 0xD800 && c < 0xE000) {
c = (c&1023)+64; d = str.charCodeAt(i++) & 1023;
a += 240|((c>>8)&7); b += a; --M;
a += 128|((c>>2)&63); b += a; --M;
a += 128|((d>>6)&15)|((c&3)<<4); b += a; --M;
a += 128|(d&63); b += a; --M;
a += 128|(d&63);
} else {
a += 224|((c>>12)&15); b += a; --M;
a += 128|((c>>6)&63); b += a; --M;
a += 128|(c&63); b += a; --M;
a += 128|(c&63);
}
b += a; --M;
}
a %= 65521;
b %= 65521;
a = (15*(a>>>16)+(a&65535));
b = (15*(b>>>16)+(b&65535));
}
return (b << 16) | a;
}

View File

@ -1,7 +1,9 @@
/* adler32.js (C) 2014-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*exported ADLER32 */
var ADLER32;
(function (factory) {
/*jshint ignore:start */
if(typeof DO_NOT_EXPORT_ADLER === 'undefined') {
if('object' === typeof exports) {
factory(exports);
@ -17,14 +19,14 @@ var ADLER32;
} else {
factory(ADLER32 = {});
}
/*jshint ignore:end */
}(function(ADLER32) {
ADLER32.version = '0.3.0';
/* consult README.md for the magic number */
/* charCodeAt is the best approach for binary strings */
ADLER32.version = '0.4.0';
/*global Buffer */
var use_buffer = typeof Buffer !== 'undefined';
function adler32_bstr(bstr) {
if(bstr.length > 32768) if(use_buffer) return adler32_buf(new Buffer(bstr));
var a = 1, b = 0, L = bstr.length, M;
var a = 1, b = 0, L = bstr.length, M = 0;
for(var i = 0; i < L;) {
M = Math.min(L-i, 3850)+i;
for(;i<M;i++) {
@ -38,7 +40,7 @@ function adler32_bstr(bstr) {
}
function adler32_buf(buf) {
var a = 1, b = 0, L = buf.length, M;
var a = 1, b = 0, L = buf.length, M = 0;
for(var i = 0; i < L;) {
M = Math.min(L-i, 3850)+i;
for(;i<M;i++) {
@ -51,31 +53,31 @@ function adler32_buf(buf) {
return ((b%65521) << 16) | (a%65521);
}
/* much much faster to intertwine utf8 and adler */
function adler32_str(str) {
var a = 1, b = 0, L = str.length, M, c, d;
var a = 1, b = 0, L = str.length, M = 0, c = 0, d = 0;
for(var i = 0; i < L;) {
M = Math.min(L-i, 3850);
while(M>0) {
c = str.charCodeAt(i++);
if(c < 0x80) { a += c; b += a; --M; }
if(c < 0x80) { a += c; }
else if(c < 0x800) {
a += 192|((c>>6)&31); b += a; --M;
a += 128|(c&63); b += a; --M;
a += 128|(c&63);
} else if(c >= 0xD800 && c < 0xE000) {
c = (c&1023)+64; d = str.charCodeAt(i++) & 1023;
a += 240|((c>>8)&7); b += a; --M;
a += 128|((c>>2)&63); b += a; --M;
a += 128|((d>>6)&15)|((c&3)<<4); b += a; --M;
a += 128|(d&63); b += a; --M;
a += 128|(d&63);
} else {
a += 224|((c>>12)&15); b += a; --M;
a += 128|((c>>6)&63); b += a; --M;
a += 128|(c&63); b += a; --M;
a += 128|(c&63);
}
b += a; --M;
}
a %= 65521;
b %= 65521;
a = (15*(a>>>16)+(a&65535));
b = (15*(b>>>16)+(b&65535));
}
return (b << 16) | a;
}

View File

@ -3,9 +3,19 @@ var bits = [
[ "Wikipedia", 300286872, 1 ],
[ "foo bar baz", 398066679, 1 ],
[ "foo bar baz٪", 570688890 ],
[ "foo bar baz٪☃", 919275383],
[ "foo bar baz٪☃🍣", 1543572022],
[ "foo bar baz٪☃", 919275383 ],
[ o, 1543572022 ],
[ o+o, -2076896149 ],
[ o+o+o, 2023497376 ]
];
if(typeof module !== "undefined") module.exports = bits;
/*::
type ArrayLike = any;
type Stringifier = {(d:ArrayLike):string};
declare class ADLER32Module {
bstr(s:string):ADLER32Type;
buf(b:ABuf):ADLER32Type;
str(s:string):ADLER32Type;
};
*/

View File

@ -7,17 +7,16 @@ if(typeof require !== 'undefined') {
fs = require("fs");
} else { X = ADLER32; }
function readlines(f) { return fs.readFileSync(f, "ascii").split("\n").filter(function(f) { return !!f; }); }
function readlines(f) { return fs.readFileSync(f, "ascii").split("\n"); }
describe('adler32 bits', function() {
bits.forEach(function(i) {
var l = i[0].length;
var msg = i[0];
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);
it(msg, function() {
if(i[2] === 1) assert.equal(X.bstr(i[0]), i[1]|0);
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])), i[1]|0);
if(typeof Buffer !== 'undefined') assert.equal(X.buf(new Buffer(i[0])), L);
});
});
});
@ -29,12 +28,27 @@ if(typeof require !== 'undefined') describe("unicode", function() {
if(!fs.existsSync("./test_files/baseline." + cat + ".txt")) return;
var corpus = readlines("./test_files/baseline." + cat + ".txt");
var uctable = require("./test_files/uctable." + cat + ".js");
uctable.forEach(function(c, i) {
for(var ucidx = 0; ucidx < uctable.length; ++ucidx) {
var c = uctable[ucidx];
/* since the baselines are passed via utf8, discard invalid codes */
if(c.charCodeAt(0) >= 0xD800 && c.charCodeAt(0) < 0xE000) return;
var cc = corpus[i], dd = X.str(c);
assert.equal(dd, cc, ":" + i + ":" + c + ":" + cc + ":" + dd);
});
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 ff = X.bstr(String.fromCharCode.apply(null, new Buffer(c, "utf8")));
assert.equal(ff, cc, ":" + ucidx + ":" + c + ":" + cc + ":" + ff);
}
};
});
});
});
if(typeof require !== 'undefined') describe("corpora", function() {
require("./test_files/corpus.json").forEach(function(text) {
if(!fs.existsSync(text[1])) return;
it("should match '" + text[0] + "' (" + text[2] + ")", function() {
assert.equal(text[2], X.buf(fs.readFileSync(text[1])));
});
});
});

117
demo/browser.flow.js Normal file
View File

@ -0,0 +1,117 @@
/*jshint browser:true */
/*global ADLER32, console */
/*:: declare var ADLER32: ADLER32Module; */
var X = ADLER32;
function console_log() { if(typeof console !== 'undefined') console.log.apply(console, [].slice.call(arguments)); }
function lpad(s/*:string*/, len/*:number*/, chr/*:?string*/)/*:string*/{
var L/*:number*/ = len - s.length, C/*:string*/ = chr || " ";
if(L <= 0) return s;
return new Array(L+1).join(C) + s;
}
function is_defined(val/*:any*/, keys/*:Array<string>*/)/*:boolean*/ {
if(typeof val === "undefined") return false;
return keys.length === 0 || is_defined(val[keys[0]], keys.slice(1));
}
/*# buffer to string; IE String.fromCharCode.apply limit, manual chunk */
function make_chunk_buf_to_str(BType/*:function*/)/*:Stringifier*/ {
return function(data/*:any*/)/*:string*/ {
var o = "", l = 0, w = 10240, L = data.byteLength/w;
for(; l<L; ++l) o+=String.fromCharCode.apply(null, ((new BType(data.slice(l*w,l*w+w)))/*:any*/));
o+=String.fromCharCode.apply(null, ((new BType(data.slice(l*w)))/*:any*/));
return o;
};
}
/*# buffer to binary string */
var bstrify/*:Stringifier*/ = make_chunk_buf_to_str(Uint8Array);
/*# readAsBinaryString support */
var rABS/*:boolean*/ = is_defined(FileReader, ['prototype', 'readAsBinaryString']);
var userABS/*:HTMLInputElement*/ = (document.getElementsByName("userabs")[0]/*:any*/);
if(!rABS) {
userABS.disabled = true;
userABS.checked = false;
}
/*## Process Result */
/*:: declare class HTMLPreElement extends HTMLElement { innerText:string; } */
function process_value(val/*:ADLER32Type*/) {
var output = [];
output[0] = "Signed : " + val;
output[1] = "Unsigned : " + (val>>>0);
output[2] = "Hex value : " + lpad((val>>>0).toString(16),8,'0');
var out/*:HTMLPreElement*/ = (document.getElementById('out')/*:any*/);
var o = output.join("\n");
if(typeof out.innerText == "undefined") out.textContent = o;
else out.innerText = o;
console_log("output", new Date());
}
/*## Raw Text */
var dotxt/*:HTMLInputElement*/ = (document.getElementById('dotext')/*:any*/);
dotxt.onclick = function() {
var txt/*:HTMLTextAreaElement*/=(document.getElementById('rawdata')/*:any*/);
console_log("onload", new Date());
var wb/*:ADLER32Type*/ = X.str(txt.value);
process_value(wb);
};
/*# HTML5 */
var readcb = function(e/*:Event*/) {
console_log("onload", new Date(), rABS, false);
var target/*:FileReader*/ = (e.target/*:any*/);
var data = target.result;
var val/*:ADLER32Type*/ = rABS ? X.bstr(data) : X.str(bstrify(data));
process_value(val);
};
/*## File Input */
var handle_file = function(e/*:Event*/) {
rABS = userABS.checked;
var otarget/*:HTMLInputElement*/ = (e.target/*:any*/);
var files/*:FileList*/ = otarget.files;
var f/*:File*/ = files[0];
var reader/*:FileReader*/ = new FileReader();
reader.onload = readcb;
if(rABS) (reader/*:any*/).readAsBinaryString(f);
else reader.readAsArrayBuffer(f);
};
var xlf/*:HTMLInputElement*/ = (document.getElementById('xlf')/*:any*/);
if(xlf.addEventListener) xlf.addEventListener('change', handle_file, false);
/*## Drag and Drop File */
var handle_drop/*:EventHandler*/ = (function(e/*:DragEvent*/) {
e.stopPropagation();
e.preventDefault();
rABS = userABS.checked;
if(!e.dataTransfer) return;
var files/*:FileList*/ = e.dataTransfer.files;
var f/*:File*/ = files[0];
var reader/*:FileReader*/ = new FileReader();
reader.onload = readcb;
if(rABS) (reader/*:any*/).readAsBinaryString(f);
else reader.readAsArrayBuffer(f);
}/*:any*/);
var handle_drag/*:EventHandler*/ = (function (e/*:DragEvent*/) {
e.stopPropagation();
e.preventDefault();
if(e.dataTransfer) e.dataTransfer.dropEffect = 'copy';
}/*:any*/);
var drop/*:HTMLDivElement*/ = (document.getElementById('drop')/*:any*/);
if(drop.addEventListener) {
drop.addEventListener('dragenter', handle_drag, false);
drop.addEventListener('dragover', handle_drag, false);
drop.addEventListener('drop', handle_drop, false);
}

115
demo/browser.js Normal file
View File

@ -0,0 +1,115 @@
/*jshint browser:true */
/*global ADLER32, console */
var X = ADLER32;
function console_log() { if(typeof console !== 'undefined') console.log.apply(console, [].slice.call(arguments)); }
function lpad(s, len, chr){
var L = len - s.length, C = chr || " ";
if(L <= 0) return s;
return new Array(L+1).join(C) + s;
}
function is_defined(val, keys) {
if(typeof val === "undefined") return false;
return keys.length === 0 || is_defined(val[keys[0]], keys.slice(1));
}
function make_chunk_buf_to_str(BType) {
return function(data) {
var o = "", l = 0, w = 10240, L = data.byteLength/w;
for(; l<L; ++l) o+=String.fromCharCode.apply(null, ((new BType(data.slice(l*w,l*w+w)))));
o+=String.fromCharCode.apply(null, ((new BType(data.slice(l*w)))));
return o;
};
}
var bstrify = make_chunk_buf_to_str(Uint8Array);
var rABS = is_defined(FileReader, ['prototype', 'readAsBinaryString']);
var userABS = (document.getElementsByName("userabs")[0]);
if(!rABS) {
userABS.disabled = true;
userABS.checked = false;
}
function process_value(val) {
var output = [];
output[0] = "Signed : " + val;
output[1] = "Unsigned : " + (val>>>0);
output[2] = "Hex value : " + lpad((val>>>0).toString(16),8,'0');
var out = (document.getElementById('out'));
var o = output.join("\n");
if(typeof out.innerText == "undefined") out.textContent = o;
else out.innerText = o;
console_log("output", new Date());
}
var dotxt = (document.getElementById('dotext'));
dotxt.onclick = function() {
var txt=(document.getElementById('rawdata'));
console_log("onload", new Date());
var wb = X.str(txt.value);
process_value(wb);
};
var readcb = function(e) {
console_log("onload", new Date(), rABS, false);
var target = (e.target);
var data = target.result;
var val = rABS ? X.bstr(data) : X.str(bstrify(data));
process_value(val);
};
var handle_file = function(e) {
rABS = userABS.checked;
var otarget = (e.target);
var files = otarget.files;
var f = files[0];
var reader = new FileReader();
reader.onload = readcb;
if(rABS) (reader).readAsBinaryString(f);
else reader.readAsArrayBuffer(f);
};
var xlf = (document.getElementById('xlf'));
if(xlf.addEventListener) xlf.addEventListener('change', handle_file, false);
var handle_drop = (function(e) {
e.stopPropagation();
e.preventDefault();
rABS = userABS.checked;
if(!e.dataTransfer) return;
var files = e.dataTransfer.files;
var f = files[0];
var reader = new FileReader();
reader.onload = readcb;
if(rABS) (reader).readAsBinaryString(f);
else reader.readAsArrayBuffer(f);
});
var handle_drag = (function (e) {
e.stopPropagation();
e.preventDefault();
if(e.dataTransfer) e.dataTransfer.dropEffect = 'copy';
});
var drop = (document.getElementById('drop'));
if(drop.addEventListener) {
drop.addEventListener('dragenter', handle_drag, false);
drop.addEventListener('dragover', handle_drag, false);
drop.addEventListener('drop', handle_drop, false);
}

51
index.html Normal file
View File

@ -0,0 +1,51 @@
<!DOCTYPE html>
<!-- adler32.js (C) 2014-present SheetJS http://sheetjs.com -->
<!-- vim: set ts=2: -->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>JS-ADLER32 Live Demo</title>
<style>
#drop{
border:2px dashed #bbb;
-moz-border-radius:5px;
-webkit-border-radius:5px;
border-radius:5px;
padding:25px;
text-align:center;
font:20pt bold,"Vollkorn";color:#bbb
}
#rawdata{
width:100%;
}
</style>
</head>
<body>
<b>JS-ADLER32 Live Demo</b><br />
<a href="https://git.io/adler32">Source Code Repo</a><br />
<a href="https://git.io/adler32_issues">Issues? Something look weird? Click here and report an issue</a><br />
<div id="drop">Drop a text file to compute the ADLER-32 checksum</div>
<p><input type="file" name="xlfile" id="xlf" /> ... or click here to select a file</p>
<textarea id="rawdata">... or paste text here ......</textarea>
<input type="button" id="dotext" value="Click here to process the text"/><br />
Advanced Demo Options: <br />
Use readAsBinaryString: (when available) <input type="checkbox" name="userabs" checked><br />
<pre id="out">.</pre>
<br />
<script type="text/javascript">/* jshint browser: true */</script>
<script src="adler32.js"></script>
<script src="demo/browser.flow.js"></script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-36810333-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</body>
</html>

View File

@ -3,8 +3,8 @@ var bits = [
[ "Wikipedia", 300286872, 1 ],
[ "foo bar baz", 398066679, 1 ],
[ "foo bar baz٪", 570688890 ],
[ "foo bar baz٪☃", 919275383],
[ "foo bar baz٪☃🍣", 1543572022],
[ "foo bar baz٪☃", 919275383 ],
[ o, 1543572022 ],
[ o+o, -2076896149 ],
[ o+o+o, 2023497376 ]
];

10
misc/flow.js Normal file
View File

@ -0,0 +1,10 @@
/*::
type ArrayLike = any;
type Stringifier = {(d:ArrayLike):string};
declare class ADLER32Module {
bstr(s:string):ADLER32Type;
buf(b:ABuf):ADLER32Type;
str(s:string):ADLER32Type;
};
*/

42
misc/help.sh Executable file
View File

@ -0,0 +1,42 @@
#!/bin/bash
# make_help.sh -- process listing of targets and special items in Makefile
# Copyright (C) 2016-present SheetJS
#
# usage in makefile: pipe the output of the following command:
# @grep -hE '(^[a-zA-Z_-][ a-zA-Z_-]*:.*?|^#[#*])' $(MAKEFILE_LIST)
#
# lines starting with "## " are treated as subtitles
# lines starting with "#* " are treated as plaintext comments
# multiple targets with "## " after the ":" are rendered as separate targets
# if the presumed default target is labeled, it will be assigned a unique color
awk '
BEGIN{recipes=0;}
!/#[#*] .*$/ {next;}
{multi=0; isrecipe=0;}
/^[^#]*:/ {isrecipe=1; ++recipes;}
/^[^ :]* .*:/ {multi=1}
multi==0 && isrecipe>0 { if(recipes > 1) print; else print $0, "[default]"; next}
isrecipe == 0 {print; next}
multi>0 {
k=split($0, msg, "##"); m=split($0, a, ":"); n=split(a[1], b, " ");
for(i=1; i<=n; ++i) print b[i] ":", "##" msg[2], (recipes==1 && i==1 ? "[default]" : "")
}
END {}
' | if [[ -t 1 ]]; then
awk '
BEGIN {FS = ":.*?## "}
{color=36}
/\[default\]/ {color=35}
NF==1 && /^##/ {color=34}
NF==1 && /^#\*/ {color=20; $1 = substr($1, 4)}
{printf "\033[" color "m%-20s\033[0m %s\n", $1, $2;}
END{}' -
else
awk '
BEGIN {FS = ":.*?## "}
/^#\* / {$1 = substr($1, 4)}
{printf "%-20s %s\n", $1, $2;}
END{}' -
fi

View File

@ -5,35 +5,44 @@ OUTD=../test_files
CATURL=https://mathias.html5.org/data/unicode/8.0.0/categories/
CATF=$OUTD/uccat.txt
ECHORED() { echo -ne '\x1B[0;31m'; echo -n $1; echo -ne '\x1B[0m'; echo; }
ECHORED() { echo -ne '\x1B[0;31m'; echo -n "$1"; echo -ne '\x1B[0m'; echo; }
if [[ "$1" == "clean" ]]; then
if [ ! -d test_files ]; then cd ..; fi
if [ -d test_files ]; then cd test_files; fi
rm -f uccat.txt baseline.*.txt uctable.*.js uctable_*.py
exit
fi
# shellcheck disable=SC2164
if [ -d misc ]; then cd misc; fi
mkdir -p $OUTD
if [ ! -e $CATF ]; then curl "$CATURL" | grep "code-points" | sed 's/.*="//g;s/-.*//g' > $CATF; fi
while read line; do
while read -r line; do
JSF=uctable.${line}.js
PYF=uctable_${line}.py
BLF=baseline.${line}.txt
JSURL="https://mathias.html5.org/data/unicode/format?version=8.0.0&category=${line}&type=symbols&prepend=var+unicode%20%3D%20&append=%3Bif(typeof%20module%20!%3D%3D%20'undefined')%20module.exports%20%3D%20unicode%3B"
if [[ ! -e $OUTD/$JSF || ! -e $OUTD/$PYF || ! -e $OUTD/$BLF ]]; then
ECHORED "Processing ${line}"
if [ ! -e $JSF ]; then
rm -f $PYF $BLF ${PYF}c
for i in $JSF $PYF $BLF; do if [[ ! -e $i && -e $OUTD/$i ]]; then mv $OUTD/"$i" .; fi done
if [ ! -e "$JSF" ]; then
rm -f "$PYF" "$BLF" "${PYF}c"
echo "Downloading JS"
</dev/null curl -o $JSF "$JSURL"
</dev/null curl -o "$JSF" "$JSURL"
fi
if [ ! -e $PYF ]; then
if [ ! -e "$PYF" ]; then
echo "Building Python script"
rm -f $BLF ${PYF}c
</dev/null node make_unicode.njs ${line} | sed 's/\[ \[/uctable = \[ \[/' > $PYF
rm -f "$BLF" "${PYF}c"
</dev/null node make_unicode.njs "${line}" | sed 's/\[ \[/uctable = \[ \[/' > "$PYF"
fi
if [ ! -e $BLF ]; then
if [ ! -e "$BLF" ]; then
echo "Building Baseline text"
python make_unicode_adler.py ${line} > baseline.${line}.txt
python make_unicode_adler.py "${line}" > "baseline.${line}.txt"
fi
for i in $JSF $PYF $BLF; do if [ -e $i ]; then mv $i $OUTD/; fi; done
rm -f uctable_${line}.pyc
for i in $JSF $PYF $BLF; do if [ -e "$i" ]; then mv "$i" $OUTD/; fi; done
rm -f "uctable_${line}.pyc"
fi
done < $CATF

View File

@ -1,5 +1,14 @@
#!/usr/bin/env node
argv = process.argv.slice(2);
/* make_unicode.njs -- generate baselines for tests
* Copyright (C) 2016-present SheetJS
* vim: set ft=javascript: */
var argv = process.argv.slice(2);
var enc = require('codepage').utils.encode;
function arr(x) { return [].slice.call(enc(65001, x)); }
console.log(require('./uctable.' + argv[0]).map(arr));
var o = require('./uctable.' + argv[0]).map(arr);
/* node 6 changed default behavior for arrays */
if(+process.version.replace(/v(\d)+\..*/,"$1") >= 6) o = require("util").inspect(o, {maxArrayLength: null});
console.log(o);

View File

@ -2,7 +2,7 @@
# make_unicode_crc.py -- generate baselines for tests
# Copyright (C) 2016-present SheetJS
from zlib import adler32
from zlib import adler32
from array import array
from sys import argv, stderr, exit
from importlib import import_module

View File

@ -1,14 +1,20 @@
{
"name": "adler-32",
"version": "0.3.0",
"version": "0.4.0",
"author": "sheetjs",
"description": "Pure-JS ADLER-32",
"keywords": [ "adler32", "checksum" ],
"bin": {
"adler32": "./bin/adler32.njs"
},
"main": "./adler32",
"dependencies": {
"concat-stream":"",
"exit-on-epipe":""
},
"devDependencies": {
"mocha":"",
"xlsjs":"",
"uglify-js":"",
"codepage":""
},
"repository": { "type":"git", "url":"git://github.com/SheetJS/js-adler32.git" },
@ -21,7 +27,7 @@
"pattern": "adler32.js"
}
},
"files": ["adler32.js", "LICENSE", "README.md"],
"files": ["adler32.js", "bin/adler32.njs", "LICENSE", "README.md"],
"bugs": { "url": "https://github.com/SheetJS/js-adler32/issues" },
"license": "Apache-2.0",
"engines": { "node": ">=0.8" }

View File

@ -4,7 +4,11 @@ var c = require('ansi')(process.stdout);
function test_end() { c.horizontalAbsolute(0).write("✓"); c.write('\n'); }
function suite_end() { console.log('Fastest is ' + this.filter('fastest').pluck('name')); }
function suite_end() {
var o = this.filter('fastest');
var m = typeof o.pluck === 'undefined' ? o.map('name') : o.pluck('name');
console.log('Fastest is ' + m);
}
function test_cycle(e) { c.horizontalAbsolute(0); c.eraseLine(); c.write("→ "+e.target); }
@ -24,9 +28,9 @@ BM.prototype.run = function() {
BM.prototype.add = function(msg, test) {
this.suites.push([msg, {
onCycle: test_cycle,
onCycle: test_cycle,
onComplete: test_end,
defer: false,
defer: false,
fn: test
}]);
this.maxlen = Math.max(this.maxlen, msg.length);

34
test.js
View File

@ -7,17 +7,16 @@ if(typeof require !== 'undefined') {
fs = require("fs");
} else { X = ADLER32; }
function readlines(f) { return fs.readFileSync(f, "ascii").split("\n").filter(function(f) { return !!f; }); }
function readlines(f) { return fs.readFileSync(f, "ascii").split("\n"); }
describe('adler32 bits', function() {
bits.forEach(function(i) {
var l = i[0].length;
var msg = i[0];
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);
it(msg, function() {
if(i[2] === 1) assert.equal(X.bstr(i[0]), i[1]|0);
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])), i[1]|0);
if(typeof Buffer !== 'undefined') assert.equal(X.buf(new Buffer(i[0])), L);
});
});
});
@ -29,12 +28,27 @@ if(typeof require !== 'undefined') describe("unicode", function() {
if(!fs.existsSync("./test_files/baseline." + cat + ".txt")) return;
var corpus = readlines("./test_files/baseline." + cat + ".txt");
var uctable = require("./test_files/uctable." + cat + ".js");
uctable.forEach(function(c, i) {
for(var ucidx = 0; ucidx < uctable.length; ++ucidx) {
var c = uctable[ucidx];
/* since the baselines are passed via utf8, discard invalid codes */
if(c.charCodeAt(0) >= 0xD800 && c.charCodeAt(0) < 0xE000) return;
var cc = corpus[i], dd = X.str(c);
assert.equal(dd, cc, ":" + i + ":" + c + ":" + cc + ":" + dd);
});
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 ff = X.bstr(String.fromCharCode.apply(null, new Buffer(c, "utf8")));
assert.equal(ff, cc, ":" + ucidx + ":" + c + ":" + cc + ":" + ff);
}
};
});
});
});
if(typeof require !== 'undefined') describe("corpora", function() {
require("./test_files/corpus.json").forEach(function(text) {
if(!fs.existsSync(text[1])) return;
it("should match '" + text[0] + "' (" + text[2] + ")", function() {
assert.equal(text[2], X.buf(fs.readFileSync(text[1])));
});
});
});

3
test_files/corpus.json Normal file
View File

@ -0,0 +1,3 @@
[
["UTF-8 Corpus", "./test_files/utf8.corpus", 555857393]
]

2
test_files/utf8.corpus Normal file

File diff suppressed because one or more lines are too long