Skip to content

Commit

Permalink
version bump 1.0.0: running hash
Browse files Browse the repository at this point in the history
  • Loading branch information
SheetJSDev committed Oct 13, 2016
1 parent b692b3f commit 318cb4e
Show file tree
Hide file tree
Showing 28 changed files with 802 additions and 139 deletions.
5 changes: 5 additions & 0 deletions .flowconfig
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,18 @@
.*/perf/.*

.*/demo/browser.js
.*/shim.js

[include]
adler32.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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ test_files/*.py
test_files/*.js
test_files/baseline*
misc/coverage.html
ctest/sauce*
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ LIB=adler32
REQS=
ADDONS=
AUXTARGETS=demo/browser.js
CMDS=bin/adler32.njs
HTMLLINT=index.html

ULIB=$(shell echo $(LIB) | tr a-z A-Z)
Expand Down Expand Up @@ -31,12 +32,13 @@ clean: clean-baseline ## Remove targets and build artifacts

.PHONY: test mocha
test mocha: test.js $(TARGET) baseline ## Run test suite
mocha -R spec -t 20000
mocha -R spec -t 30000

.PHONY: ctest
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
Expand All @@ -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)
Expand All @@ -68,7 +71,7 @@ flow: lint ## Run flow checker
cov: misc/coverage.html ## Run coverage test

misc/coverage.html: $(TARGET) test.js
mocha --require blanket -R html-cov -t 20000 > $@
mocha --require blanket -R html-cov -t 30000 > $@

.PHONY: coveralls
coveralls: ## Coverage Test + Send to coveralls.io
Expand Down
64 changes: 47 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,63 @@
# adler32

Signed ADLER-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/adler-32):

npm install adler-32
```bash
$ npm install adler-32
```

In the browser:

<script lang="javascript" src="adler32.js"></script>
```html
<script lang="javascript" src="adler32.js"></script>
```

The browser exposes a variable ADLER32
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.

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_ADLER`.

## Usage

- `ADLER32.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)
In all cases, the relevant function takes an argument representing data and an
optional second argument representing the starting "seed" (for running hash).

The return value is a signed 32-bit integer.

- `ADLER32.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).

- `ADLER32.bstr(binary string)` interprets the argument as a binary string where
the `i`-th byte is `str.charCodeAt(i)`
- `ADLER32.bstr(binary string[, seed])` assumes the argument as a binary string
where byte `i` is the low byte of the UCS-2 char: `str.charCodeAt(i) & 0xFF`

- `ADLER32.str(string)` interprets the argument as a standard JS string
- `ADLER32.str(string)` assumes the argument as a standard JS string and
calculates the hash of the UTF-8 encoding.

For example:

```js
// var ADLER32 = require('adler-32'); // uncomment if in node
ADLER32.str("SheetJS") // 176947863
ADLER32.bstr("SheetJS") // 176947863
ADLER32.buf([ 83, 104, 101, 101, 116, 74, 83 ]) // 176947863

adler32 = ADLER32.buf([83, 104]) // 17825980 "Sh"
adler32 = ADLER32.str("eet", adler32) // 95486458 "Sheet"
ADLER32.bstr("JS", adler32) // 176947863 "SheetJS"

[ADLER32.str("\u2603"), ADLER32.str("\u0003")] // [ 73138686, 262148 ]
[ADLER32.bstr("\u2603"), ADLER32.bstr("\u0003")] // [ 262148, 262148 ]
[ADLER32.buf([0x2603]), ADLER32.buf([0x0003])] // [ 262148, 262148 ]
```

## Testing

Expand All @@ -39,7 +70,7 @@ To update the browser artifacts, run `make ctest`.

To generate the bits file, use the `adler32` function from python zlib:

```
```python
>>> from zlib import adler32
>>> x="foo bar baz٪☃🍣"
>>> adler32(x)
Expand All @@ -52,15 +83,15 @@ To generate the bits file, use the `adler32` function from python zlib:

The included `adler32.njs` script can process files or stdin:

```
```bash
$ echo "this is a test" > t.txt
$ bin/adler32.njs t.txt
726861088
```

For comparison, the included `adler32.py` script uses python zlib:

```
```bash
$ bin/adler32.py t.txt
726861088
```
Expand All @@ -70,8 +101,6 @@ $ bin/adler32.py t.txt
`make perf` will run algorithmic performance tests (which should justify certain
decisions in the code).

[js-crc](http://git.io/crc32) has more performance notes

Bit twiddling is much faster than taking the mod on Safari and older Firefoxes.
Instead of taking the literal mod 65521, it is faster to keep it in the integers
by bit-shifting: `65536 ~ 15 mod 65521` so for nonnegative integer `a`:
Expand All @@ -87,7 +116,7 @@ The mod is taken at the very end, since the intermediate result may exceed 65521

The magic numbers were chosen so as to not overflow a 31-bit integer:

```
```mathematica
F[n_] := Reduce[x*(x + 1)*n/2 + (x + 1)*(65521) < (2^31 - 1) && x > 0, x, Integers]
F[255] (* bstr: x \[Element] Integers && 1 <= x <= 3854 *)
F[127] (* ascii: x \[Element] Integers && 1 <= x <= 5321 *)
Expand All @@ -102,9 +131,10 @@ granted by the Apache 2.0 license are reserved by the Original Author.

## Badges

[![Sauce Test Status](https://saucelabs.com/browser-matrix/adler32.svg)](https://saucelabs.com/u/adler32)

[![Build Status](https://travis-ci.org/SheetJS/js-adler32.svg?branch=master)](https://travis-ci.org/SheetJS/js-adler32)

[![Coverage Status](https://coveralls.io/repos/SheetJS/js-adler32/badge.png?branch=master)](https://coveralls.io/r/SheetJS/js-adler32?branch=master)
[![Coverage Status](http://img.shields.io/coveralls/SheetJS/js-adler32/master.svg)](https://coveralls.io/r/SheetJS/js-adler32?branch=master)

[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-adler32?pixel)](https://github.com/SheetJS/js-adler32)

20 changes: 10 additions & 10 deletions adler32.flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,20 @@ var ADLER32;
}
/*jshint ignore:end */
}(function(ADLER32) {
ADLER32.version = '0.4.0';
ADLER32.version = '1.0.0';
/*::
type ADLER32Type = number;
type ABuf = Array<number> | Buffer;
*/
/*# 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));
function adler32_bstr(bstr/*:string*/, seed/*:?ADLER32Type*/)/*:ADLER32Type*/ {
var a = 1, b = 0, L = bstr.length, M = 0;
if(typeof seed === 'number') { a = seed & 0xFFFF; b = seed >>> 16; }
for(var i = 0; i < L;) {
M = Math.min(L-i, 3850)+i;
for(;i<M;i++) {
a += bstr.charCodeAt(i);
a += bstr.charCodeAt(i)&0xFF;
b += a;
}
a = (15*(a>>>16)+(a&65535));
Expand All @@ -47,12 +45,13 @@ function adler32_bstr(bstr/*:string*/)/*:ADLER32Type*/ {
return ((b%65521) << 16) | (a%65521);
}

function adler32_buf(buf/*:ABuf*/)/*:ADLER32Type*/ {
function adler32_buf(buf/*:ABuf*/, seed/*:?ADLER32Type*/)/*:ADLER32Type*/ {
var a = 1, b = 0, L = buf.length, M = 0;
if(typeof seed === 'number') { a = seed & 0xFFFF; b = (seed >>> 16) & 0xFFFF; }
for(var i = 0; i < L;) {
M = Math.min(L-i, 3850)+i;
for(;i<M;i++) {
a += buf[i];
a += buf[i]&0xFF;
b += a;
}
a = (15*(a>>>16)+(a&65535));
Expand All @@ -62,8 +61,9 @@ function adler32_buf(buf/*:ABuf*/)/*:ADLER32Type*/ {
}

/*# much much faster to intertwine utf8 and adler */
function adler32_str(str/*:string*/)/*:ADLER32Type*/ {
function adler32_str(str/*:string*/, seed/*:?ADLER32Type*/)/*:ADLER32Type*/ {
var a = 1, b = 0, L = str.length, M = 0, c = 0, d = 0;
if(typeof seed === 'number') { a = seed & 0xFFFF; b = seed >>> 16; }
for(var i = 0; i < L;) {
M = Math.min(L-i, 3850);
while(M>0) {
Expand All @@ -88,7 +88,7 @@ function adler32_str(str/*:string*/)/*:ADLER32Type*/ {
a = (15*(a>>>16)+(a&65535));
b = (15*(b>>>16)+(b&65535));
}
return (b << 16) | a;
return ((b%65521) << 16) | (a%65521);
}
ADLER32.bstr = adler32_bstr;
ADLER32.buf = adler32_buf;
Expand Down
20 changes: 10 additions & 10 deletions adler32.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,14 @@ var ADLER32;
}
/*jshint ignore:end */
}(function(ADLER32) {
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));
ADLER32.version = '1.0.0';
function adler32_bstr(bstr, seed) {
var a = 1, b = 0, L = bstr.length, M = 0;
if(typeof seed === 'number') { a = seed & 0xFFFF; b = seed >>> 16; }
for(var i = 0; i < L;) {
M = Math.min(L-i, 3850)+i;
for(;i<M;i++) {
a += bstr.charCodeAt(i);
a += bstr.charCodeAt(i)&0xFF;
b += a;
}
a = (15*(a>>>16)+(a&65535));
Expand All @@ -39,12 +37,13 @@ function adler32_bstr(bstr) {
return ((b%65521) << 16) | (a%65521);
}

function adler32_buf(buf) {
function adler32_buf(buf, seed) {
var a = 1, b = 0, L = buf.length, M = 0;
if(typeof seed === 'number') { a = seed & 0xFFFF; b = (seed >>> 16) & 0xFFFF; }
for(var i = 0; i < L;) {
M = Math.min(L-i, 3850)+i;
for(;i<M;i++) {
a += buf[i];
a += buf[i]&0xFF;
b += a;
}
a = (15*(a>>>16)+(a&65535));
Expand All @@ -53,8 +52,9 @@ function adler32_buf(buf) {
return ((b%65521) << 16) | (a%65521);
}

function adler32_str(str) {
function adler32_str(str, seed) {
var a = 1, b = 0, L = str.length, M = 0, c = 0, d = 0;
if(typeof seed === 'number') { a = seed & 0xFFFF; b = seed >>> 16; }
for(var i = 0; i < L;) {
M = Math.min(L-i, 3850);
while(M>0) {
Expand All @@ -79,7 +79,7 @@ function adler32_str(str) {
a = (15*(a>>>16)+(a&65535));
b = (15*(b>>>16)+(b&65535));
}
return (b << 16) | a;
return ((b%65521) << 16) | (a%65521);
}
ADLER32.bstr = adler32_bstr;
ADLER32.buf = adler32_buf;
Expand Down
Loading

0 comments on commit 318cb4e

Please sign in to comment.