├── LICENSE
├── README.md
└── lzb
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2019, F. Aragon
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5 |
6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7 |
8 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
9 |
10 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
11 |
12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | LZB: LZ77 data compression and other utilities in pure Bash language
2 | ===
3 |
4 | LZB is a data compression/decompression utility written in Bash language,
5 | using no external programs. It also includes additional utilities:
6 |
7 | - CRC-32
8 | - hexadecimal encoding/decoding
9 | - base64 encoding/decoding
10 | - "head" and "cut" commands
11 |
12 | Key points:
13 |
14 | * Small: 11KB (including comments)
15 | * Efficient: e.g. 1111111111 is reduced to 6 bytes. 20 x "1" to 7 bytes, 1280 to 8 bytes, etc.
16 | * Platform-independent: it works in any platform supported by Bash 4 or later
17 | * Complete: it supports unlimited file size for compression and decompression
18 | * Vintage: compress and decompress at 1981 speeds!
19 |
20 | Compatibility
21 | ===
22 |
23 | The requirement of Bash 4 or later is because of the usage of associative
24 | arrays. I.e. this should work in most Linux and Unix distributions released
25 | after 2009 (I've tested it with the default 'bash' command in Ubuntu 18.04).
26 |
27 | Overview
28 | ===
29 |
30 | How to install, example:
31 | ```
32 | sudo cp lzb /usr/local/bin # Installation
33 | sudo rm /usr/local/bin/lzb # Uninstallation
34 | ```
35 | Syntax:
36 | ```
37 | lzb [-d|-crc32|-hex|-dhex|-b64|-db64|-h]
38 | ```
39 | Help:
40 | ```
41 | lzb -h
42 | ```
43 | Compression example:
44 | ```
45 | lzb input.lzb
46 | ```
47 | Decompression example:
48 | ```
49 | lzb -d output
50 | ```
51 | Compression and decompression cycle example:
52 | ```
53 | lzb output
54 | diff input output
55 | ```
56 | CRC-32:
57 | ```
58 | lzb -crc32 output
63 | ```
64 | Hexadecimal decoding:
65 | ```
66 | lzb -dhex output
67 | ```
68 | Base64 encoding:
69 | ```
70 | lzb -b64 output
71 | ```
72 | Base64 decoding:
73 | ```
74 | lzb -db64 output
75 | ```
76 | 'head' command (get first N bytes):
77 | ```
78 | lzb -head N output
79 | ```
80 | 'cut' command (skip first N bytes, and take next M bytes):
81 | ```
82 | lzb -cut N M output
83 | ```
84 |
85 | Internals
86 | ===
87 |
88 | LZB is a rewrite in Bash of the libsrt's library 'enc' example, not
89 | being compatible with its format, because of simplicity (the Bash version
90 | is hundred thousands times slower than the C version, and probably million
91 | times slower as the buffer size is increased). E.g. libsrt library 'enc'
92 | example has a infinite-size dictionary ("-ezh" flag) which is not supported
93 | by this program, nor the LUT tuning for speed, etc.
94 |
95 | [libsrt repository](https://github.com/faragon/libsrt)
96 |
97 | [libsrt LZ77 implementation](https://github.com/faragon/libsrt/blob/master/src/saux/senc.c)
98 |
99 | Editing the 'lzb' file you can change the LZ_BUF_SIZE variable value,
100 | for changing the data compression buffer size. The buffer size is related
101 | to the compression window: that means that the default 16384-byte buffer
102 | allows to locate patterns in that context. Increasing that value makes
103 | the compressor to reach more distant patterns, at the cost of execution
104 | speed. You can also reduce that value for speed-up, e.g. reducing it to
105 | 4096 (or to 3333, it is not restricted to powers of two). I'll probably
106 | add a parameter for selecting compression ratio, too.
107 |
108 | Bash is not good handling binary data, but it is able to read and write it,
109 | so for convenience, the data is converted on the fly from raw to hexadecimal,
110 | doing all the compression/decompression in hexadecimal, having a
111 | post-process step from hexadecimal to raw, for writing the output. Both
112 | the pre-process and the post-process are done using pipes.
113 |
114 | License
115 | ===
116 |
117 | Copyright (c) 2019, F. Aragon. All rights reserved.
118 | Released under the BSD 3-Clause License (see the LICENSE file included).
119 |
120 | Contact
121 | ===
122 |
123 | email: faragon.github (GMail account, add @gmail.com)
124 |
--------------------------------------------------------------------------------
/lzb:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # lzb
4 | #
5 | # LZ77 data compression an other utilities in pure Bash language
6 | #
7 | # Based on https://github.com/faragon/libsrt
8 | #
9 | # Copyright (c) 2019 F. Aragon. All rights reserved.
10 | # Released under the BSD 3-Clause License (see the LICENSE file)
11 | #
12 |
13 | globals() {
14 | LC_ALL=C # ANSI C locale (disables Unicode support, ~20% speed-up)
15 | LZ_BUF_SIZE=16384 # The bigger, the slower, but more compression
16 | HEX_BUF_SIZE=$((LZ_BUF_SIZE * 2))
17 | g_out="" # global variable for handling decompression output
18 | LZOP_BITS=2 ; LZOP_MASK=$(((1 << LZOP_BITS) - 1))
19 | LZOP_RV_LS_MASK=1 ; LZOP_RV_LS=0 ; LZOP_RV_LV=1 ; LZOP_LV=3
20 | LZOP_RV_LS_LBITS=2
21 | LZOP_RV_LS_LMASK=$(((1 << LZOP_RV_LS_LBITS) - 1))
22 | LZOP_RV_LS_LSHIFT=$LZOP_BITS
23 | LZOP_RV_LS_LRANGE=$((LZOP_RV_LS_LBITS ? LZOP_RV_LS_LMASK + 1 : 0))
24 | LZOP_RV_LS_DBITS=$((64 - LZOP_RV_LS_LBITS - LZOP_BITS))
25 | LZOP_RV_LS_DMASK=$(((1 << LZOP_RV_LS_DBITS) - 1))
26 | LZOP_RV_LS_DSHIFT=$((LZOP_RV_LS_LBITS + LZOP_BITS))
27 | LZOP_RV_LS_DRANGE=$((LZOP_RV_LS_DBITS ? LZOP_RV_LS_DMASK + 1 : 0))
28 | LZOP_BRK_LEN=1000000000000
29 | }
30 |
31 | enc_st_lit() {
32 | local size=$(((${#1}) / 2)) ; local sm1=$(($size - 1))
33 | st_pk64 $(((sm1 << $LZOP_BITS) | LZOP_LV))
34 | echo -n $1
35 | }
36 |
37 | enc_st_ref() {
38 | local dm1=$1 lm4=$2
39 | if ((dm1 < LZOP_RV_LS_DRANGE && lm4 < LZOP_RV_LS_LRANGE)) ; then
40 | st_pk64 $(((dm1 << LZOP_RV_LS_DSHIFT) | \
41 | (lm4 << LZOP_RV_LS_LSHIFT) | LZOP_RV_LS))
42 | else
43 | st_pk64 $(((lm4 << LZOP_BITS) | LZOP_RV_LV)) ; st_pk64 $dm1
44 | fi
45 | }
46 |
47 | enc_st_blk_brk() { enc_st_ref 0 $((LZOP_BRK_LEN - 4)) ; }
48 |
49 | # Encoding/compression function
50 | lzb_enc() {
51 | declare -A lut
52 | local buf clx clxs d1 i l lg last len l1 plit w32
53 | for ((lg = 0; ; lg=$((lg + l)))) ; do
54 | # Reset LUT of references and load the buffer
55 | lut=() ; read -N $HEX_BUF_SIZE buf ; l=${#buf}
56 |
57 | # Input < 8 bytes: store (16 is for the hex representation)
58 | if ((l < 16)) ; then
59 | if ((l > 0)) ; then enc_st_lit $buf ; fi ; break ; fi
60 |
61 | # Insert block separator between compressed blocks
62 | if ((lg > 0)) ; then enc_st_blk_brk ; fi
63 |
64 | lut[${buf:0:8}]=0 # first 32-bit chunk
65 |
66 | # Data compression loop
67 | smx=$((l - 8))
68 | for ((i = 8, plit = 0; i <= smx;)) ; do
69 | w32=${buf:$i:8} # Load 4 bytes (in hex)
70 | last=$((${lut[$w32]} + 0)) # LUT lookup
71 | lut[$w32]=$i # LUT update with w32 load index
72 |
73 | # No match: skip byte and continue
74 | if [[ $w32 != ${buf:$last:8} ]] ; then
75 | i=$((i + 2)) ; continue ; fi
76 |
77 | # Match: compare to find the longest match
78 | len=8 ; for clxs in 8192 128 8 ; do
79 | clx=$((((l - i) / clxs) * clxs))
80 | for ((; len < clx; len += clxs)) ; do
81 | if [[ ${buf:$((i + len)):$clxs} != \
82 | ${buf:$((last + len)):$clxs} ]]
83 | then break ; fi ; done ; done
84 | for ((; len < l; len += 2)) ; do
85 | if [[ ${buf:$((i + len)):2} != \
86 | ${buf:$((last + len)):2} ]] ; then
87 | break ; fi ; done
88 |
89 | # Avoid encoding short distant references
90 | l1=$(((len / 2) - 4)) ; d1=$((((i - last) / 2) - 1))
91 |
92 | # Store pending literals
93 | if ((plit != i)) ; then
94 | enc_st_lit ${buf:plit:$((i - plit))} ; fi
95 |
96 | # Store reference
97 | enc_st_ref $d1 $l1 ; i=$((i + len)) ; plit=$i
98 | done
99 |
100 | # Store pending literals
101 | if (((l - plit) > 0)) ; then
102 | enc_st_lit ${buf:plit:$((l - plit))} ; fi
103 | done
104 | lut=()
105 | }
106 |
107 | reccpy1() {
108 | local gs0=$((${#g_out} - $1)) i len=$2
109 | for ((i = 0; i < len; i += 2)) ; do
110 | g_out+=${g_out:$((gs0 + i)):2} ; done
111 | }
112 |
113 | reccpy() { # recursive copy (i.e. allowing references to future data)
114 | local dist=$1 i n=$2 ; local gs0=$((${#g_out} - $dist))
115 | if ((dist > n)) ; then g_out+=${g_out:$gs0:$n} # Non-overlapped copy
116 | else reccpy1 $dist $len ; fi # Overlapped copy
117 | }
118 |
119 | dec_ld_ref() {
120 | local dist=$(($1 * 2)) len=$(($2 * 2)) ; reccpy $dist $len ; }
121 |
122 | dec_ld_lit() { # $1: literal count
123 | local aux ; read -N $(($1 * 2)) aux ; g_out+=$aux ; }
124 |
125 | # Decoding/decompression function
126 | lzb_dec() {
127 | local op len dist
128 | # Opcode processing loop (literal and reference opcodes)
129 | for ((;;)) ; do
130 | op=$(ld_pk64)
131 | if [ "$op" == "" ] ; then break ; fi
132 | if (((op & LZOP_MASK) == LZOP_LV)) ; then
133 | len=$(((op >> LZOP_BITS) + 1))
134 | #echo "LZOP_LV ($len)" >&2
135 | dec_ld_lit $len
136 | continue
137 | fi
138 | if (((op & LZOP_RV_LS_MASK) == LZOP_RV_LS)) ; then
139 | len=$((((op >> LZOP_RV_LS_LSHIFT) & \
140 | LZOP_RV_LS_LMASK) + 4))
141 | dist=$((((op >> LZOP_RV_LS_DSHIFT) & \
142 | LZOP_RV_LS_DMASK) + 1))
143 | #echo "LZOP_RV_LS ($dist, $len)" >&2
144 | else
145 | # LZOP_RV_LV
146 | len=$(((op >> LZOP_BITS) + 4))
147 | dist=$(($(ld_pk64) + 1))
148 | if ((dist == 1 && len == LZOP_BRK_LEN)) ; then
149 | echo -n $g_out ; g_out= ; continue
150 | #echo "LZOP BRK" >&2
151 | fi
152 | #echo "LZOP_RV_LV ($dist, $len)" >&2
153 | fi
154 |
155 | dec_ld_ref $dist $len
156 | done
157 | echo -n $g_out ; g_out=
158 | }
159 |
160 | # Misc utilities
161 |
162 | crc32() {
163 | local b c=$((0xffffffff))
164 | while read -N 2 b ; do
165 | c=$((c ^ 0x$b))
166 | c=$((((c & 1) * 0xedb88320) ^ (c >> 1)))
167 | c=$((((c & 1) * 0xedb88320) ^ (c >> 1)))
168 | c=$((((c & 1) * 0xedb88320) ^ (c >> 1)))
169 | c=$((((c & 1) * 0xedb88320) ^ (c >> 1)))
170 | c=$((((c & 1) * 0xedb88320) ^ (c >> 1)))
171 | c=$((((c & 1) * 0xedb88320) ^ (c >> 1)))
172 | c=$((((c & 1) * 0xedb88320) ^ (c >> 1)))
173 | c=$((((c & 1) * 0xedb88320) ^ (c >> 1)))
174 | done
175 | printf "%08x\n" $((0xffffffff & ~c))
176 | }
177 |
178 | b64_luts() {
179 | declare -g -A d e
180 | local c i j=0 p=printf
181 | for ((i = 65; i <= 90; i++, j++)) ; do
182 | c=$(st8 $i) ; e[$j]=$c ; d[$($p "\x$c")]=$j ; done
183 | for ((i = 97; i <= 122; i++, j++)) ; do
184 | c=$(st8 $i) ; e[$j]=$c ; d[$($p "\x$c")]=$j ; done
185 | for ((i = 48; i <= 57; i++, j++)) ; do
186 | c=$(st8 $i) ; e[$j]=$c ; d[$($p "\x$c")]=$j ; done
187 | for i in 43 47 ; do
188 | c=$(st8 $i) ; e[$j]=$c ; d[$($p "\x$c")]=$j ; j=$((j+1)) ; done
189 | d[=]=-1
190 | }
191 |
192 | enc_b64() {
193 | local c ; b64_luts
194 | while read -N 6 c ; do
195 | printf "\x${e[$((0x${c:0:2} >> 2))]}"
196 | printf "\x${e[$(((0x${c:0:2} & 3) << 4 | (0x${c:2:2}) >> 4))]}"
197 | printf "\x${e[$(((0x${c:2:2} & 15) << 2 | 0x${c:4:2} >> 6))]}"
198 | printf "\x${e[$((0x${c:4:2} & 0x3f))]}"
199 | done
200 | if ((${#c} == 4)) ; then
201 | printf "\x${e[$((0x${c:0:2} >> 2))]}"
202 | printf "\x${e[$(((0x${c:0:2} & 3) << 4 | (0x${c:2:2}) >> 4))]}"
203 | printf "\x${e[$(((0x${c:2:2} & 15) << 2))]}="
204 | elif ((${#c} == 2)) ; then
205 | printf "\x${e[$((0x${c:0:2} >> 2))]}"
206 | printf "\x${e[$(((0x${c:0:2} & 3) << 4))]}=="
207 | fi
208 | }
209 |
210 | dec_b64() {
211 | local i r s t u ; b64_luts
212 | while read -N 4 i ; do
213 | r=${d[${i:0:1}]} ; s=${d[${i:1:1}]}
214 | t=${d[${i:2:1}]} ; u=${d[${i:3:1}]}
215 | if ((u >= 0)) ; then
216 | st8 $((r << 2 | s >> 4)) ; st8 $((s << 4 | t >> 2))
217 | st8 $(((t << 6) | u)) ; continue
218 | fi
219 | st8 $((r << 2 | s >> 4))
220 | if ((t >= 0)) ; then st8 $((s << 4 | t >> 2)) ; fi
221 | break
222 | done
223 | }
224 |
225 | cut() {
226 | local bs=$((64 * 1024)) off=$(($1 * 2)) size=$((($2 + 0) * 2))
227 | local sdb=$(((size / bs) * bs)) c i
228 | if ((off)) ; then read -N $off ; fi
229 | if ((size == 0)) ; then
230 | while read -N $bs c ; do echo -n "$c" ; done
231 | echo -n "$c" ; return ; fi
232 | for ((i = 0; i < sdb; i+=bs)) ; do
233 | if ! read -N $bs c ; then echo -n "$c" ; return ; fi
234 | echo -n "$c" ; done
235 | i=$((size - i)) ; if ((i)) ; then read -N $i c ; echo -n "$c" ; fi
236 | }
237 |
238 | head() { local s=$(($1 + 0)) ; if ((s == 0)) ; then return ; fi ; cut 0 $@ ; }
239 |
240 | # Helper functions
241 |
242 | st8() { printf %02x $(($1 & 0xff)) ; }
243 | st16() { printf %02x%02x $(($1 & 0xff)) $((($1 >> 8) & 0xff)) ; }
244 | st24() { printf %02x%02x%02x $(($1 & 0xff)) $((($1 >> 8) & 0xff)) \
245 | $((($1 >> 16) & 0xff)) ; }
246 | st32() { printf %02x%02x%02x%02x $(($1 & 0xff)) $((($1 >> 8) & 0xff)) \
247 | $((($1 >> 16) & 0xff)) $((($1 >> 24) & 0xff)) ; }
248 | st40() { st8 $(($1 & 0xff)) ; st32 $(($1 >> 8)) ; }
249 | st48() { st16 $(($1 & 0xffff)) ; st32 $(($1 >> 16)) ; }
250 | st56() { st24 $(($1 & 0xffffff)) ; st32 $(($1 >> 24)) ; }
251 | st64() { st32 $(($1 & 0xffffffff)) ; st32 $(($1 >> 32)) ; }
252 | ld8() { echo -n "$((0x${1:0:2}))" ; }
253 | ld16() { echo -n "$((0x${1:2:2}${1:0:2}))" ; }
254 | ld24() { echo -n "$((0x${1:4:2}${1:2:2}${1:0:2}))" ; }
255 | ld32() { echo -n "$((0x${1:6:2}${1:4:2}${1:2:2}${1:0:2}))" ; }
256 | ld40() { echo -n "$((0x${1:8:2}${1:6:2}${1:4:2}${1:2:2}${1:0:2}))" ; }
257 | ld48() { echo -n "$((0x${1:10:2}${1:8:2}${1:6:2}${1:4:2}${1:2:2}${1:0:2}))" ; }
258 | ld56() { echo -n "$((0x${1:12:2}${1:10:2}${1:8:2}${1:6:2}${1:4:2}${1:2:2}${1:0:2}))" ; }
259 | ld64() { echo -n "$((0x${1:14:2}${1:12:2}${1:10:2}${1:8:2}${1:6:2}${1:4:2}${1:2:2}${1:0:2}))" ; }
260 | enc_hex() { local LC_ALL=C IFS=""
261 | while read -r -d '' -n 1 c ; do printf "%02x" "'$c" ; done ; }
262 | dec_hex() { while read -d '' -n 2 hl ; do printf "\x$hl" ; done ; }
263 | binop() { enc_hex | $@ | dec_hex ; }
264 | st_pk64() {
265 | local v=$(($1 + 0))
266 | if ((v <= 0x7f)) ; then st8 $((v << 1 | 1)) ; return ; fi
267 | if ((v <= 0x3fff)) ; then st16 $((v << 2 | 2)) ; return ; fi
268 | if ((v <= 0x1fffff)) ; then st24 $((v << 3 | 4)) ; return ; fi
269 | if ((v <= 0xfffffff)) ; then st32 $((v << 4 | 8)) ; return ; fi
270 | if ((v <= 0x7ffffffff)) ; then st40 $((v << 5 | 16)) ; return ; fi
271 | if ((v <= 0x3ffffffffff)) ; then st48 $((v << 6 | 32)) ; return ; fi
272 | if ((v <= 0x1ffffffffffff)) ; then st56 $((v << 7 | 64)) ; return ; fi
273 | st8 128 ; st64 $v
274 | }
275 | sz_pk64() {
276 | local h=$1
277 | if ((h & 1)) ; then echo -n 1 ; return ; fi
278 | if ((h & 2)) ; then echo -n 2 ; return ; fi
279 | if ((h & 4)) ; then echo -n 3 ; return ; fi
280 | if ((h & 8)) ; then echo -n 4 ; return ; fi
281 | if ((h & 16)) ; then echo -n 5 ; return ; fi
282 | if ((h & 32)) ; then echo -n 6 ; return ; fi
283 | if ((h & 64)) ; then echo -n 7 ; return ; fi
284 | if ((h & 128)) ; then echo -n 9 ; return ; fi
285 | echo -n 0
286 | }
287 | ld_pk64() {
288 | local a b h ; read -N 2 a ; h=$(ld8 $a)
289 | case "$(sz_pk64 $h)" in
290 | 1) echo -n $((h >> 1)) ;;
291 | 2) read -N 2 b ; echo -n $(($(ld16 $a$b) >> 2)) ; return ;;
292 | 3) read -N 4 b ; echo -n $(($(ld24 $a$b) >> 3)) ; return ;;
293 | 4) read -N 6 b ; echo -n $(($(ld32 $a$b) >> 4)) ; return ;;
294 | 5) read -N 8 b ; echo -n $(($(ld40 $a$b) >> 5)) ; return ;;
295 | 6) read -N 10 b ; echo -n $(($(ld48 $a$b) >> 6)) ; return ;;
296 | 7) read -N 12 b ; echo -n $(($(ld56 $a$b) >> 7)) ; return ;;
297 | 9) read -N 16 b ; echo -n $(($(ld64 $b))) ; return ;;
298 | esac
299 | }
300 | show_help() {
301 | local P IFS='/' ; for P in $1 ; do continue ; done
302 | echo -e "LZB data compression and other tools" >&2
303 | echo -e "Copyright (c) 2019 F. Aragon. All rights reserved." >&2
304 | echo -e "Released under the BSD 3-Clause License" >&2
305 | echo -e "Syntax: $P [-d|-crc32|-h]\nExamples:" >&2
306 | echo -e "\tCompress: $P out" >&2
307 | echo -e "\tDecompress: $P -d out" >&2
308 | echo -e "\tCRC-32: $P -crc32 out" >&2
309 | echo -e "\tHex encoding: $P -hex out" >&2
310 | echo -e "\tHex decoding: $P -dhex out" >&2
311 | echo -e "\tBase64 encoding: $P -b64 out" >&2
312 | echo -e "\tBase64 decoding: $P -db64 out" >&2
313 | echo -e "\t'head' (get first N bytes): $P -head N out" >&2
314 | echo -e "\t'cut' (skip N bytes, get M bytes): $P -cut N M out" >&2
315 | echo -e "\tHelp: $P -h" >&2
316 | echo -e "\tInstallation: sudo cp lzb /usr/local/bin" >&2 ; }
317 | syntax_error() {
318 | echo "Syntax error (!)" >&2 ; show_help $1 ; }
319 |
320 | # main program start
321 |
322 | globals
323 |
324 | if (($# == 0)) ; then
325 | binop lzb_enc
326 | else case $1 in
327 | -h) show_help $0 ;; -d) binop lzb_dec ;; -crc32) enc_hex | crc32 ;;
328 | -hex) enc_hex ;; -dhex) dec_hex ;; -b64) enc_hex | enc_b64 ;;
329 | -db64) dec_b64 | dec_hex ;; -cut) binop cut ${@:2} ;;
330 | -head) binop head ${@:2} ;; *) syntax_error $0
331 | esac
332 | fi
333 |
--------------------------------------------------------------------------------