Skip to content

Commit cfddd86

Browse files
committed
More tools (uniwhat, unicount), started on goreleaser
1 parent 90d4449 commit cfddd86

12 files changed

Lines changed: 591 additions & 33 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,5 @@ tmp-*
2323
venv/
2424
.venv/
2525
_work/
26+
# Added by goreleaser init:
27+
dist/

.goreleaser.yaml

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
version: 2
2+
3+
project_name: fftools
4+
5+
before:
6+
hooks:
7+
# You may remove this if you don't use go modules.
8+
- go mod tidy
9+
# you may remove this if you don't need go generate
10+
- go generate ./...
11+
12+
builds:
13+
- id: asciify
14+
main: ./cmd/asciify/asciify.go
15+
binary: asciify
16+
env:
17+
- CGO_ENABLED=0
18+
goos:
19+
- linux
20+
- windows
21+
- darwin
22+
23+
- id: asciitable
24+
main: ./cmd/asciitable/asciitable.go
25+
binary: asciitable
26+
env:
27+
- CGO_ENABLED=0
28+
goos:
29+
- linux
30+
- windows
31+
- darwin
32+
33+
- id: bytecount
34+
main: ./cmd/bytecount/bytecount.go
35+
binary: bytecount
36+
env:
37+
- CGO_ENABLED=0
38+
goos:
39+
- linux
40+
- windows
41+
- darwin
42+
43+
- id: certinfo
44+
main: ./cmd/certinfo/certinfo.go
45+
binary: certinfo
46+
env:
47+
- CGO_ENABLED=0
48+
goos:
49+
- linux
50+
- windows
51+
- darwin
52+
53+
- id: hexdumpc
54+
main: ./cmd/hexdumpc/hexdumpc.go
55+
binary: hexdumpc
56+
env:
57+
- CGO_ENABLED=0
58+
goos:
59+
- linux
60+
- windows
61+
- darwin
62+
63+
- id: unicount
64+
main: ./cmd/unicount/unicount.go
65+
binary: unicount
66+
env:
67+
- CGO_ENABLED=0
68+
goos:
69+
- linux
70+
- windows
71+
- darwin
72+
73+
- id: uniwhat
74+
main: ./cmd/uniwhat/uniwhat.go
75+
binary: uniwhat
76+
env:
77+
- CGO_ENABLED=0
78+
goos:
79+
- linux
80+
- windows
81+
- darwin
82+
83+
archives:
84+
- formats: [tar.gz]
85+
# this name template makes the OS and Arch compatible with the results of `uname`.
86+
name_template: >-
87+
{{ .ProjectName }}_
88+
{{- title .Os }}_
89+
{{- if eq .Arch "amd64" }}x86_64
90+
{{- else if eq .Arch "386" }}i386
91+
{{- else }}{{ .Arch }}{{ end }}
92+
{{- if .Arm }}v{{ .Arm }}{{ end }}
93+
# use zip for windows archives
94+
format_overrides:
95+
- goos: windows
96+
formats: [zip]
97+
ids:
98+
- asciify
99+
- asciitable
100+
- bytecount
101+
- certinfo
102+
- hexdumpc
103+
- unicount
104+
- uniwhat
105+
106+
nfpms:
107+
- id: fftools
108+
package_name: fftools
109+
ids:
110+
- asciify
111+
- asciitable
112+
- bytecount
113+
- certinfo
114+
- hexdumpc
115+
- unicount
116+
- uniwhat
117+
vendor: FileFormatInfo
118+
homepage: "https://www.fileformat.info/"
119+
maintainer: Andrew Marcuse <fileformat@gmail.com>
120+
description: |-
121+
Utilities for analyzing, viewing and fixing file formats.
122+
license: GPL-3.0-and-later
123+
formats:
124+
- deb
125+
- rpm
126+
127+
release:
128+
github:
129+
owner: FileFormatInfo
130+
name: fftools
131+
132+
report_sizes: true
133+
134+
source:
135+
enabled: true
136+
name_template: "{{ .ProjectName }}.src"
137+
138+
upx:
139+
- enabled: true
140+
141+
changelog:
142+
sort: asc
143+
filters:
144+
exclude:
145+
- "^docs:"
146+
- "^test:"
147+
148+
release:
149+
footer: >-
150+
151+
---
152+
153+
Released by [GoReleaser](https://github.com/goreleaser/goreleaser).

README.md

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,35 @@
11
# File Format Tools [<img alt="Logo for fftools" src="docs/favicon.svg" height="96" align="right"/>](https://www.fileformat.info/)
22

3+
4+
## Programs
5+
6+
- `asciify`: converts to ASCII using [anyascii](https://github.com/anyascii/anyascii)
7+
- `asciitable`: prints out an table of ASCII characters
8+
- `bytecount`: counts the number of occurrences of each byte
9+
- `certinfo`: print info about an x509 (aka SSL/HTTPS) certificate
10+
- `hexdumpc`: generate canonical hexdump (`hexdump -C`) output in case you don't have [`hexdump`](https://man7.org/linux/man-pages/man1/hexdump.1.html) installed
11+
- `unicount`: count Unicode codepoints in a file
12+
- `uniwhat`: print the names of each Unicode character in a file
13+
314
## Credits
415

516
[![Git](https://www.vectorlogo.zone/logos/git-scm/git-scm-ar21.svg)](https://git-scm.com/ "Version control")
617
[![Github](https://www.vectorlogo.zone/logos/github/github-ar21.svg)](https://github.com/ "Code hosting")
718
[![golang](https://www.vectorlogo.zone/logos/golang/golang-ar21.svg)](https://golang.org/ "Programming language")
819
[![svgrepo](https://www.vectorlogo.zone/logos/svgrepo/svgrepo-ar21.svg)](https://www.svgrepo.com/svg/276165/gardening-tools-rake "Icon")
920

10-
## To Do
21+
## Scripts To Do
1122

12-
- [x] `asciify`: converts to ASCII using [anyascii](https://github.com/anyascii/anyascii)
13-
- [x] `asciitable`: prints out an table of ASCII characters
14-
- [x] `bytecount`: counts the number of occurrences of each byte
15-
- [x] `certinfo`: print info about an x509 (aka SSL/HTTPS) certificate
1623
- [ ] `ghash`: calculate various [hashes available in the Go standard library](https://pkg.go.dev/crypto#Hash)
17-
- [x] `hexdumpc`: generate canonical hexdump (`hexdump -C`) output in case you don't have [`hexdump`](https://man7.org/linux/man-pages/man1/hexdump.1.html) installed
24+
- [ ] `body`: prints specific lines of a file (in between `head` and `tail`)
1825
- [ ] `trilobyte`: translates bytes according to a map
1926
- [ ] `ustrings`: like the standard [`strings`](https://man7.org/linux/man-pages/man1/strings.1.html) utility, but with Unicode support
27+
- [ ] `utf8ify`: convert to UTF-8
2028
- [ ] `unhexdump`: convert the (edited) output of [`hexdump -C`](https://man7.org/linux/man-pages/man1/hexdump.1.html) back to binary
21-
- [ ] proper command line parsing (cobra)
29+
30+
31+
## General
32+
2233
- [ ] man pages
23-
- [ ] distribution packages
34+
- [ ] goreleaser
35+
- [ ] [release security](https://github.com/goreleaser/example-secure)

bin/build.sh

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#!/usr/bin/env bash
2+
#
3+
# build binaries
4+
#
5+
6+
set -o errexit
7+
set -o pipefail
8+
set -o nounset
9+
10+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11+
REPO_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
12+
13+
DIST_DIR="${REPO_DIR}/dist"
14+
15+
echo "INFO: starting at $(date -u +%Y-%m-%dT%H:%M:%SZ)"
16+
17+
if [ ! -d "${DIST_DIR}" ]; then
18+
echo "INFO: creating dist directory ${DIST_DIR}"
19+
mkdir "${REPO_DIR}/dist"
20+
fi
21+
22+
FILES=$(ls "${REPO_DIR}/cmd")
23+
24+
for f in $FILES; do
25+
if [ -f "${DIST_DIR}/${f}" ]; then
26+
echo "WARNING: file ${DIST_DIR}/${f} already exists"
27+
continue
28+
fi
29+
echo "INFO: compiling ${f} to dist directory"
30+
go build -o "${DIST_DIR}/${f}" "${REPO_DIR}/cmd/${f}"
31+
done
32+
33+
echo "INFO: complete at $(date -u +%Y-%m-%dT%H:%M:%SZ)"

bin/clean.sh

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/usr/bin/env bash
2+
#
3+
# clean up build artifacts
4+
#
5+
6+
set -o errexit
7+
set -o pipefail
8+
set -o nounset
9+
10+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11+
REPO_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
12+
13+
DIST_DIR="${REPO_DIR}/dist"
14+
15+
echo "INFO: starting at $(date -u +%Y-%m-%dT%H:%M:%SZ)"
16+
17+
if [ -d "${DIST_DIR}" ]; then
18+
echo "INFO: removing dist directory ${DIST_DIR}"
19+
rm -rf "${DIST_DIR}"
20+
else
21+
echo "INFO: dist directory ${DIST_DIR} does not exist, nothing to clean"
22+
fi
23+
24+
echo "INFO: complete at $(date -u +%Y-%m-%dT%H:%M:%SZ)"

cmd/ghash/ghash.go

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ import (
88
_ "crypto/sha256"
99
_ "crypto/sha3"
1010
_ "crypto/sha512"
11+
"hash"
12+
"io"
13+
"regexp"
14+
"strings"
1115

1216
"fmt"
1317
"os"
@@ -20,7 +24,16 @@ import (
2024
"github.com/spf13/pflag"
2125
)
2226

23-
func printHashes(fileName string, hashes []string) error {
27+
// struct with name and hash
28+
type Hasher struct {
29+
name string
30+
hash hash.Hash
31+
}
32+
33+
// map of name to Hasher
34+
var hasherMap = map[string]Hasher{}
35+
36+
func printHashes(fileName string, hashers []Hasher) error {
2437
// Open the file
2538
file, err := os.Open(fileName)
2639
if err != nil {
@@ -30,29 +43,82 @@ func printHashes(fileName string, hashes []string) error {
3043

3144
reader := bufio.NewReader(file)
3245

46+
// Read the file in chunks and update the hashes
47+
buf := make([]byte, 64*1024)
48+
for {
49+
n, err := reader.Read(buf)
50+
if n > 0 {
51+
for _, h := range hashers {
52+
h.hash.Write(buf[:n])
53+
}
54+
}
55+
if err != nil {
56+
if err == io.EOF {
57+
break
58+
}
59+
return err
60+
}
61+
}
62+
63+
// Print the results
64+
for _, h := range hashers {
65+
if len(hashers) > 1 {
66+
fmt.Printf("%x: %s %s\n", h.hash.Sum(nil), h.name, fileName)
67+
} else {
68+
fmt.Printf("%x: %s\n", h.hash.Sum(nil), fileName)
69+
}
70+
}
71+
3372
return nil
3473
}
3574

75+
var nonAlphaNumeric = regexp.MustCompile(`[^a-zA-Z0-9]`)
76+
3677
func main() {
37-
var hashes []string
78+
var hashNames []string
3879
var list bool
39-
pflag.StringArrayVar(&hashes, "hash", []string{}, "Hash algorithms to use (e.g., sha256, sha512)")
80+
pflag.StringArrayVar(&hashNames, "hash", []string{}, "Hash algorithms to use (e.g., sha256, sha512)")
4081
pflag.BoolVar(&list, "list", false, "List available hash algorithms")
4182
//LATER: output format
4283

4384
pflag.Parse()
4485

4586
if list {
4687
for i := crypto.MD4; i <= crypto.BLAKE2b_512; i++ {
88+
hashName := nonAlphaNumeric.ReplaceAllString(strings.ToLower(i.String()), "")
4789
if i.Available() {
48-
fmt.Fprintf(os.Stdout, "%s: %s\n", i, "true")
90+
fmt.Fprintf(os.Stdout, "%s: %s\n", hashName, "true")
4991
} else {
50-
fmt.Fprintf(os.Stdout, "%s: %s\n", i, "false")
92+
fmt.Fprintf(os.Stdout, "%s: %s\n", hashName, "false")
5193
}
5294
}
5395
return
5496
}
5597

98+
// build hashers map
99+
for i := crypto.MD4; i <= crypto.BLAKE2b_512; i++ {
100+
if i.Available() {
101+
hashName := nonAlphaNumeric.ReplaceAllString(strings.ToLower(i.String()), "")
102+
theHash := Hasher{name: hashName, hash: i.New()}
103+
hasherMap[hashName] = theHash
104+
hasherMap[strings.ToLower(i.String())] = theHash
105+
}
106+
}
107+
108+
var hashers = []Hasher{}
109+
if len(hashNames) == 0 {
110+
hashers = append(hashers, hasherMap["sha256"])
111+
} else {
112+
for _, name := range hashNames {
113+
var h = hasherMap[name]
114+
if h.hash == nil {
115+
fmt.Fprintf(os.Stderr, "Unknown or unavailable hash algorithm: %s\n", name)
116+
os.Exit(1)
117+
}
118+
hashers = append(hashers, h)
119+
}
120+
}
121+
56122
args := pflag.Args()
57123
if len(args) == 0 {
58124
args = []string{"-"}
@@ -62,7 +128,7 @@ func main() {
62128
arg = "/dev/stdin"
63129
}
64130

65-
if err := printHashes(arg, hashes); err != nil {
131+
if err := printHashes(arg, hashers); err != nil {
66132
panic(err)
67133
}
68134
}

0 commit comments

Comments
 (0)