├── 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 | --------------------------------------------------------------------------------