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