forked from nsf/bin2go
/
bin2go.go
154 lines (128 loc) · 3.12 KB
/
bin2go.go
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
144
145
146
147
148
149
150
151
152
153
154
package main
import (
"bufio"
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"unicode"
)
var (
name = flag.String("name", "", "use this name for the variable instead of one generated based on the input")
out = flag.String("out", "", "use this filename for output instead of inputfile.go")
pkg = flag.String("pkg", "", "use this package name instead of the parent directory of the input")
)
// Exit error codes
const (
NO_ERROR = iota
WRONG_ARGS
INPUT_FAIL
OUTPUT_FAIL
)
func printUsage() {
fmt.Printf("usage: %s [-name=<name>] [-out=<path>] [-pkg=<name>] <inputfile>\n\t%s [-pkg=<name>] <inputfile>...", os.Args[0], os.Args[0])
flag.PrintDefaults()
}
func printUsageAndExit() {
flag.Usage()
os.Exit(WRONG_ARGS)
}
func readInput(filename string) []byte {
data, err := ioutil.ReadFile(filename)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to read input: %s\n", err)
os.Exit(INPUT_FAIL)
}
return data
}
func checkOutputFailure(err error) {
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to write output: %s\n", err)
os.Exit(OUTPUT_FAIL)
}
}
func writeData(filename string, data []byte, out io.Writer) {
var varname string
if *name != "" {
varname = *name
} else {
pieces := strings.FieldsFunc(filepath.Base(filename), func(r rune) bool {
return !unicode.IsLetter(r) && !unicode.IsNumber(r)
})
for _, piece := range pieces {
p := []rune(piece)
varname += string(unicode.ToUpper(p[0])) + string(p[1:])
}
}
// write header
_, err := fmt.Fprintf(out, "var %s = []byte{\n\t", varname)
checkOutputFailure(err)
lastbytei := len(data) - 1
n := 8
for i, b := range data {
// write single byte
_, err = fmt.Fprintf(out, "0x%.2x,", b)
checkOutputFailure(err)
n += 6
// if this is not the last byte
if i != lastbytei {
// be readable, break line after 78 characters
if n >= 78 {
_, err = fmt.Fprint(out, "\n\t")
checkOutputFailure(err)
n = 8
} else {
// if we're not breaking the line, insert space
// after ','
_, err = fmt.Fprint(out, " ")
checkOutputFailure(err)
}
}
}
_, err = fmt.Fprint(out, "\n}\n")
checkOutputFailure(err)
}
func writeOutput(filename string, data []byte) {
var file *os.File
var err error
// prepare output file
if *out == "" {
file, err = os.Create(filename + ".go")
checkOutputFailure(err)
defer file.Close()
} else {
file, err = os.Create(*out)
checkOutputFailure(err)
defer file.Close()
}
output := bufio.NewWriter(file)
// write package clause if any
if *pkg == "" {
path, err := filepath.Abs(*out)
checkOutputFailure(err)
_, err = fmt.Fprintf(output, "package %s\n\n", filepath.Base(filepath.Dir(path)))
checkOutputFailure(err)
} else {
_, err = fmt.Fprintf(output, "package %s\n\n", *pkg)
checkOutputFailure(err)
}
// write data
writeData(filename, data, output)
// flush
err = output.Flush()
checkOutputFailure(err)
}
func main() {
flag.Usage = printUsage
flag.Parse()
if flag.NArg() == 0 || (flag.NArg() > 1 && (*out != "" || *name != "")) {
printUsageAndExit()
}
for _, filename := range flag.Args() {
data := readInput(filename)
writeOutput(filename, data)
}
}