blob: ca20904751effe7e1470faf6f10a3c0c1f28bbc1 [file] [log] [blame]
Adam Langley29b18672015-02-06 11:52:16 -08001/* Copyright (c) 2015, Google Inc.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
15package main
16
17import (
18 "bufio"
19 "bytes"
20 "errors"
21 "fmt"
22 "io"
23 "os"
24 "sort"
25 "strconv"
26 "strings"
27)
28
29// libraryNames must be kept in sync with the enum in err.h. The generated code
30// will contain static assertions to enforce this.
31var libraryNames = []string{
32 "NONE",
33 "SYS",
34 "BN",
35 "RSA",
36 "DH",
37 "EVP",
38 "BUF",
39 "OBJ",
40 "PEM",
41 "DSA",
42 "X509",
43 "ASN1",
44 "CONF",
45 "CRYPTO",
46 "EC",
47 "SSL",
48 "BIO",
49 "PKCS7",
50 "PKCS8",
51 "X509V3",
52 "RAND",
53 "ENGINE",
54 "OCSP",
55 "UI",
56 "COMP",
57 "ECDSA",
58 "ECDH",
59 "HMAC",
60 "DIGEST",
61 "CIPHER",
62 "USER",
63 "HKDF",
64}
65
66// stringList is a map from uint32 -> string which can output data for a sorted
67// list as C literals.
68type stringList struct {
69 // entries is an array of keys and offsets into |stringData|. The
70 // offsets are in the bottom 15 bits of each uint32 and the key is the
71 // top 17 bits.
72 entries []uint32
73 // internedStrings contains the same strings as are in |stringData|,
74 // but allows for easy deduplication. It maps a string to its offset in
75 // |stringData|.
76 internedStrings map[string]uint32
77 stringData []byte
78}
79
80func newStringList() *stringList {
81 return &stringList{
82 internedStrings: make(map[string]uint32),
83 }
84}
85
86// offsetMask is the bottom 15 bits. It's a mask that selects the offset from a
87// uint32 in entries.
88const offsetMask = 0x7fff
89
90func (st *stringList) Add(key uint32, value string) error {
91 if key&offsetMask != 0 {
92 return errors.New("need bottom 15 bits of the key for the offset")
93 }
94 offset, ok := st.internedStrings[value]
95 if !ok {
96 offset = uint32(len(st.stringData))
97 if offset&offsetMask != offset {
98 return errors.New("stringList overflow")
99 }
100 st.stringData = append(st.stringData, []byte(value)...)
101 st.stringData = append(st.stringData, 0)
102 st.internedStrings[value] = offset
103 }
104
105 for _, existing := range st.entries {
106 if existing>>15 == key>>15 {
107 panic("duplicate entry")
108 }
109 }
110 st.entries = append(st.entries, key|offset)
111 return nil
112}
113
114// keySlice is a type that implements sorting of entries values.
115type keySlice []uint32
116
117func (ks keySlice) Len() int {
118 return len(ks)
119}
120
121func (ks keySlice) Less(i, j int) bool {
122 return (ks[i] >> 15) < (ks[j] >> 15)
123}
124
125func (ks keySlice) Swap(i, j int) {
126 ks[i], ks[j] = ks[j], ks[i]
127}
128
129func (st *stringList) buildList() []uint32 {
130 sort.Sort(keySlice(st.entries))
131 return st.entries
132}
133
134type stringWriter interface {
135 io.Writer
136 WriteString(string) (int, error)
137}
138
139func (st *stringList) WriteTo(out stringWriter, name string) {
140 list := st.buildList()
141 fmt.Fprintf(os.Stderr, "%s: %d bytes of list and %d bytes of string data.\n", name, 4*len(list), len(st.stringData))
142
143 out.WriteString("static const uint32_t k" + name + "Values[] = {\n")
144 for _, v := range list {
145 fmt.Fprintf(out, " 0x%x,\n", v)
146 }
147 out.WriteString("};\n\n")
148
David Benjamin32f16502015-02-09 21:44:28 -0500149 out.WriteString("static const char k" + name + "StringData[] =\n \"")
Adam Langley29b18672015-02-06 11:52:16 -0800150 for i, c := range st.stringData {
151 if c == 0 {
David Benjamin32f16502015-02-09 21:44:28 -0500152 out.WriteString("\\0\"\n \"")
Adam Langley29b18672015-02-06 11:52:16 -0800153 continue
154 }
155 out.Write(st.stringData[i : i+1])
156 }
157 out.WriteString("\";\n\n")
158}
159
160type errorData struct {
161 functions, reasons *stringList
162 libraryMap map[string]uint32
163}
164
165func (e *errorData) readErrorDataFile(filename string) error {
166 inFile, err := os.Open(filename)
167 if err != nil {
168 return err
169 }
170 defer inFile.Close()
171
172 scanner := bufio.NewScanner(inFile)
173 comma := []byte(",")
174
175 lineNo := 0
176 for scanner.Scan() {
177 lineNo++
178
179 line := scanner.Bytes()
180 if len(line) == 0 {
181 continue
182 }
183 parts := bytes.Split(line, comma)
184 if len(parts) != 4 {
185 return fmt.Errorf("bad line %d in %s: found %d values but want 4", lineNo, filename, len(parts))
186 }
187 libNum, ok := e.libraryMap[string(parts[0])]
188 if !ok {
189 return fmt.Errorf("bad line %d in %s: unknown library", lineNo, filename)
190 }
191 if libNum >= 64 {
192 return fmt.Errorf("bad line %d in %s: library value too large", lineNo, filename)
193 }
194 key, err := strconv.ParseUint(string(parts[2]), 10 /* base */, 32 /* bit size */)
195 if err != nil {
196 return fmt.Errorf("bad line %d in %s: %s", lineNo, filename, err)
197 }
198 if key >= 2048 {
199 return fmt.Errorf("bad line %d in %s: key too large", lineNo, filename)
200 }
201 value := string(parts[3])
202
203 listKey := libNum<<26 | uint32(key)<<15
204
205 switch string(parts[1]) {
206 case "function":
207 err = e.functions.Add(listKey, value)
208 case "reason":
209 err = e.reasons.Add(listKey, value)
210 default:
211 return fmt.Errorf("bad line %d in %s: bad value type", lineNo, filename)
212 }
213
214 if err != nil {
215 return err
216 }
217 }
218
219 return scanner.Err()
220}
221
222func main() {
223 e := &errorData{
224 functions: newStringList(),
225 reasons: newStringList(),
226 libraryMap: make(map[string]uint32),
227 }
228 for i, name := range libraryNames {
229 e.libraryMap[name] = uint32(i) + 1
230 }
231
232 cwd, err := os.Open(".")
233 if err != nil {
234 panic(err)
235 }
236 names, err := cwd.Readdirnames(-1)
237 if err != nil {
238 panic(err)
239 }
240
David Benjamine8fe46a2015-02-09 21:16:58 -0500241 sort.Strings(names)
Adam Langley29b18672015-02-06 11:52:16 -0800242 for _, name := range names {
243 if !strings.HasSuffix(name, ".errordata") {
244 continue
245 }
246 if err := e.readErrorDataFile(name); err != nil {
247 panic(err)
248 }
249 }
250
251 out := os.Stdout
252
253 out.WriteString(`/* Copyright (c) 2015, Google Inc.
254 *
255 * Permission to use, copy, modify, and/or distribute this software for any
256 * purpose with or without fee is hereby granted, provided that the above
257 * copyright notice and this permission notice appear in all copies.
258 *
259 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
260 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
261 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
262 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
263 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
264 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
265 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
266
267 /* This file was generated by err_data_generate.go. */
268
269#include <openssl/base.h>
270#include <openssl/type_check.h>
271
272
273`)
274
275 for i, name := range libraryNames {
Adam Langleycf310a62015-02-09 18:05:57 -0800276 fmt.Fprintf(out, "OPENSSL_COMPILE_ASSERT(ERR_LIB_%s == %d, library_values_changed_%d);\n", name, i+1, i+1)
Adam Langley29b18672015-02-06 11:52:16 -0800277 }
Adam Langleycf310a62015-02-09 18:05:57 -0800278 fmt.Fprintf(out, "OPENSSL_COMPILE_ASSERT(ERR_NUM_LIBS == %d, library_values_changed_num);\n", len(libraryNames) + 1)
Adam Langley29b18672015-02-06 11:52:16 -0800279 out.WriteString("\n")
280
281 e.functions.WriteTo(out, "Function")
282 e.reasons.WriteTo(out, "Reason")
283}