-
Notifications
You must be signed in to change notification settings - Fork 12
/
cksum16
executable file
·105 lines (92 loc) · 2.8 KB
/
cksum16
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
#!/bin/bash
#
# Calculates the CRC-16 checksum of a string
# like cksum does for CRC32
#
# Copyright (C) 2011 Rodrigo Silva (MestreLion) <linux@rodrigosilva.com>
# License: GPLv3 or later, at your choice. See <http://www.gnu.org/licenses/gpl>
#
# References:
# 0x10 blog: <http://zeroxten.blogspot.com/search/label/crc16>
# Wine's winemenubuilder: <http://source.winehq.org/git/wine.git>
# The wise, friendly and helpful #bash gurus: <irc://irc.freenet.org/#bash>
#
# NOTE: Newlines are properly handled, but last newline is stripped off
# NOTE: NUL chars are stripped off before computing
# TODO: Test how non-ASCI chars are handled
# FIXME: Decent usage explaining options and behaviour
self="${0##*/}"
error() {
local msg="$1"
printf "%s: %s\nTry '%s --help' for more information\n" \
"$self" "$msg" "$self" >&2
exit 1
}
usage() {
printf "Print CRC-16 checksum (and optionally the byte count) of STRING\n\n"
printf "Usage: %s [--hex|--dec|--format FORMAT] [--count] [STRING]\n\n" "$self"
printf "Default format is decimal. If no string or -, reads from stdin\n"
printf "NULs and last newline are ignored. Use for texts, not binary data.\n"
exit
}
crc16()
(
export LC_ALL=C
local string="$1"
local format="${2:-"%d"}"
local crc=0
local i j xor_poly
for ((i=0; i<${#string}; i++)); do
c=$(printf "%d" "'${string:i:1}")
for ((j=0; j<8; c>>=1, j++)); do
(( xor_poly = (c ^ crc) & 1 ))
(( crc >>= 1 ))
(( xor_poly )) && (( crc ^= 0xA001 ))
done
done
printf "$format" "$crc"
)
while [[ $# -gt 0 ]]; do
arg="$1"; shift
case "$arg" in
-h|--help ) usage ;;
-x|--hex ) format="%04X" ;;
-d|--dec ) format="%d" ;;
-f|--format) format="$1"; shift ;;
-c|--count ) count=1 ;;
-- ) string="$1" ; break ;;
- ) string=$( cat ) ; done=1 ; break ;;
-* ) error "unrecognized option '$arg'" ;;
* ) string="$arg" ; done=1 ; break ;;
esac
done
[[ "$done" || "$string" ]] || string=$( cat )
# Expected command-line behaviour table:
# <none> => str = stdin
# - => str = stdin
# something => str = something
# -- <none> => str = stdin
# -- someth => str = something
[[ "$string" ]] || error "missing string"
crc16 "$string" "$format"
[[ "$count" ]] && printf " %d" "${#string}"
printf "\n"
#Original function from winemenubuilder.c (for reference)
#static unsigned short crc16(const char* string)
#{
# unsigned short crc = 0;
# int i, j, xor_poly;
#
# for (i = 0; string[i] != 0; i++)
# {
# char c = string[i];
# for (j = 0; j < 8; c >>= 1, j++)
# {
# xor_poly = (c ^ crc) & 1;
# crc >>= 1;
# if (xor_poly)
# crc ^= 0xa001;
# }
# }
# return crc;
#}