blob: 8b1c02d90e2289708182aa317e4825419008795e [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.
David Benjamin34248d42015-06-28 23:36:21 -040072 entries []uint32
Adam Langley29b18672015-02-06 11:52:16 -080073 // 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
David Benjamind27eda02015-03-05 01:19:27 -0500143 values := "kOpenSSL" + name + "Values"
144 out.WriteString("const uint32_t " + values + "[] = {\n")
Adam Langley29b18672015-02-06 11:52:16 -0800145 for _, v := range list {
146 fmt.Fprintf(out, " 0x%x,\n", v)
147 }
148 out.WriteString("};\n\n")
David Benjamin34248d42015-06-28 23:36:21 -0400149 out.WriteString("const size_t " + values + "Len = sizeof(" + values + ") / sizeof(" + values + "[0]);\n\n")
Adam Langley29b18672015-02-06 11:52:16 -0800150
David Benjamind27eda02015-03-05 01:19:27 -0500151 stringData := "kOpenSSL" + name + "StringData"
152 out.WriteString("const char " + stringData + "[] =\n \"")
Adam Langley29b18672015-02-06 11:52:16 -0800153 for i, c := range st.stringData {
154 if c == 0 {
David Benjamin32f16502015-02-09 21:44:28 -0500155 out.WriteString("\\0\"\n \"")
Adam Langley29b18672015-02-06 11:52:16 -0800156 continue
157 }
158 out.Write(st.stringData[i : i+1])
159 }
160 out.WriteString("\";\n\n")
161}
162
163type errorData struct {
David Benjamin34248d42015-06-28 23:36:21 -0400164 reasons *stringList
165 libraryMap map[string]uint32
Adam Langley29b18672015-02-06 11:52:16 -0800166}
167
168func (e *errorData) readErrorDataFile(filename string) error {
169 inFile, err := os.Open(filename)
170 if err != nil {
171 return err
172 }
173 defer inFile.Close()
174
175 scanner := bufio.NewScanner(inFile)
176 comma := []byte(",")
177
178 lineNo := 0
179 for scanner.Scan() {
180 lineNo++
181
182 line := scanner.Bytes()
183 if len(line) == 0 {
184 continue
185 }
186 parts := bytes.Split(line, comma)
David Benjamin34248d42015-06-28 23:36:21 -0400187 if len(parts) != 3 {
188 return fmt.Errorf("bad line %d in %s: found %d values but want 3", lineNo, filename, len(parts))
Adam Langley29b18672015-02-06 11:52:16 -0800189 }
190 libNum, ok := e.libraryMap[string(parts[0])]
191 if !ok {
192 return fmt.Errorf("bad line %d in %s: unknown library", lineNo, filename)
193 }
194 if libNum >= 64 {
195 return fmt.Errorf("bad line %d in %s: library value too large", lineNo, filename)
196 }
David Benjamin34248d42015-06-28 23:36:21 -0400197 key, err := strconv.ParseUint(string(parts[1]), 10 /* base */, 32 /* bit size */)
Adam Langley29b18672015-02-06 11:52:16 -0800198 if err != nil {
199 return fmt.Errorf("bad line %d in %s: %s", lineNo, filename, err)
200 }
201 if key >= 2048 {
202 return fmt.Errorf("bad line %d in %s: key too large", lineNo, filename)
203 }
David Benjamin34248d42015-06-28 23:36:21 -0400204 value := string(parts[2])
Adam Langley29b18672015-02-06 11:52:16 -0800205
206 listKey := libNum<<26 | uint32(key)<<15
207
David Benjamin34248d42015-06-28 23:36:21 -0400208 err = e.reasons.Add(listKey, value)
Adam Langley29b18672015-02-06 11:52:16 -0800209 if err != nil {
210 return err
211 }
212 }
213
214 return scanner.Err()
215}
216
217func main() {
218 e := &errorData{
Adam Langley29b18672015-02-06 11:52:16 -0800219 reasons: newStringList(),
220 libraryMap: make(map[string]uint32),
221 }
222 for i, name := range libraryNames {
223 e.libraryMap[name] = uint32(i) + 1
224 }
225
226 cwd, err := os.Open(".")
227 if err != nil {
228 panic(err)
229 }
230 names, err := cwd.Readdirnames(-1)
231 if err != nil {
232 panic(err)
233 }
234
David Benjamine8fe46a2015-02-09 21:16:58 -0500235 sort.Strings(names)
Adam Langley29b18672015-02-06 11:52:16 -0800236 for _, name := range names {
237 if !strings.HasSuffix(name, ".errordata") {
238 continue
239 }
240 if err := e.readErrorDataFile(name); err != nil {
241 panic(err)
242 }
243 }
244
245 out := os.Stdout
246
247 out.WriteString(`/* Copyright (c) 2015, Google Inc.
248 *
249 * Permission to use, copy, modify, and/or distribute this software for any
250 * purpose with or without fee is hereby granted, provided that the above
251 * copyright notice and this permission notice appear in all copies.
252 *
253 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
254 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
255 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
256 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
257 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
258 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
259 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
260
261 /* This file was generated by err_data_generate.go. */
262
263#include <openssl/base.h>
David Benjamind27eda02015-03-05 01:19:27 -0500264#include <openssl/err.h>
Adam Langley29b18672015-02-06 11:52:16 -0800265#include <openssl/type_check.h>
266
267
268`)
269
270 for i, name := range libraryNames {
Adam Langleycf310a62015-02-09 18:05:57 -0800271 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 -0800272 }
David Benjamin34248d42015-06-28 23:36:21 -0400273 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 -0800274 out.WriteString("\n")
275
Adam Langley29b18672015-02-06 11:52:16 -0800276 e.reasons.WriteTo(out, "Reason")
277}