summaryrefslogtreecommitdiffstats
path: root/src/zcrc.js
blob: 831f8352445742b085b5808df4ae0ed355fe6b40 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
"use strict";

const CRC32_MOD = require('crc-32');

var Zmodem = module.exports;

Object.assign(
    Zmodem,
    require("./zerror"),
    require("./encode")
);

//----------------------------------------------------------------------
// BEGIN adapted from crc-js by Johannes Rudolph

var _crctab;

const
    crc_width = 16,
    crc_polynomial = 0x1021,
    crc_castmask = 0xffff,
    crc_msbmask = 1 << (crc_width - 1)
;

function _compute_crctab() {
    _crctab = new Array(256);

    var divident_shift = crc_width - 8;

    for (var divident = 0; divident < 256; divident++) {
        var currByte = (divident << divident_shift) & crc_castmask;

        for (var bit = 0; bit < 8; bit++) {

            if ((currByte & crc_msbmask) !== 0) {
                currByte <<= 1;
                currByte ^= crc_polynomial;
            }
            else {
                currByte <<= 1;
            }
        }

        _crctab[divident] = (currByte & crc_castmask);
    }
}

// END adapted from crc-js by Johannes Rudolph
//----------------------------------------------------------------------

function _updcrc(cp, crc) {
    if (!_crctab) _compute_crctab();

    return(
        _crctab[((crc >> 8) & 255)]
        ^ ((255 & crc) << 8)
        ^ cp
    );
}

function __verify(expect, got) {
    var err;

    if ( expect.join() !== got.join() ) {
        throw new Zmodem.Error("crc", got, expect);
    }
}

//TODO: use external implementation(s)
Zmodem.CRC = {

    //https://www.lammertbies.nl/comm/info/crc-calculation.html
    //CRC-CCITT (XModem)

    /**
     * Deduce a given set of octet values’ CRC16, as per the CRC16
     * variant that ZMODEM uses (CRC-CCITT/XModem).
     *
     * @param {Array} octets - The array of octet values.
     *      Each array member should be an 8-bit unsigned integer (0-255).
     *
     * @returns {Array} crc - The CRC, expressed as an array of octet values.
     */
    crc16: function crc16(octet_nums) {
        var crc = octet_nums[0];
        for (var b=1; b<octet_nums.length; b++) {
            crc = _updcrc( octet_nums[b], crc );
        }

        crc = _updcrc( 0, _updcrc(0, crc) );

        //a big-endian 2-byte sequence
        return Zmodem.ENCODELIB.pack_u16_be(crc);
    },

    /**
     * Deduce a given set of octet values’ CRC32.
     *
     * @param {Array} octets - The array of octet values.
     *      Each array member should be an 8-bit unsigned integer (0-255).
     *
     * @returns {Array} crc - The CRC, expressed as an array of octet values.
     */
    crc32: function crc32(octet_nums) {
        return Zmodem.ENCODELIB.pack_u32_le(
            CRC32_MOD.buf(octet_nums) >>> 0     //bit-shift to get unsigned
        );
    },

    /**
     * Verify a given set of octet values’ CRC16.
     * An exception is thrown on failure.
     *
     * @param {Array} bytes_arr - The array of octet values.
     *      Each array member should be an 8-bit unsigned integer (0-255).
     *
     * @param {Array} crc - The CRC to check against, expressed as
     *      an array of octet values.
     */
    verify16: function verify16(bytes_arr, got) {
        return __verify( this.crc16(bytes_arr), got );
    },

    /**
     * Verify a given set of octet values’ CRC32.
     * An exception is thrown on failure.
     *
     * @param {Array} bytes_arr - The array of octet values.
     *      Each array member should be an 8-bit unsigned integer (0-255).
     *
     * @param {Array} crc - The CRC to check against, expressed as
     *      an array of octet values.
     */
    verify32: function verify32(bytes_arr, crc) {
        try {
            __verify( this.crc32(bytes_arr), crc );
        }
        catch(err) {
            err.input = bytes_arr.slice(0);
            throw err;
        }
    },
};