| /* Copyright (c) 2015, Google Inc. | |
| * | |
| * Permission to use, copy, modify, and/or distribute this software for any | |
| * purpose with or without fee is hereby granted, provided that the above | |
| * copyright notice and this permission notice appear in all copies. | |
| * | |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
| * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
| * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | |
| * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | |
| * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ | |
| package main | |
| import ( | |
| "bufio" | |
| "bytes" | |
| "errors" | |
| "flag" | |
| "fmt" | |
| "io" | |
| "os" | |
| "sort" | |
| "strconv" | |
| "strings" | |
| ) | |
| var verbose = flag.Bool("verbose", false, "If true, prints a status message at the end.") | |
| // libraryNames must be kept in sync with the enum in err.h. The generated code | |
| // will contain static assertions to enforce this. | |
| var libraryNames = []string{ | |
| "NONE", | |
| "SYS", | |
| "BN", | |
| "RSA", | |
| "DH", | |
| "EVP", | |
| "BUF", | |
| "OBJ", | |
| "PEM", | |
| "DSA", | |
| "X509", | |
| "ASN1", | |
| "CONF", | |
| "CRYPTO", | |
| "EC", | |
| "SSL", | |
| "BIO", | |
| "PKCS7", | |
| "PKCS8", | |
| "X509V3", | |
| "RAND", | |
| "ENGINE", | |
| "OCSP", | |
| "UI", | |
| "COMP", | |
| "ECDSA", | |
| "ECDH", | |
| "HMAC", | |
| "DIGEST", | |
| "CIPHER", | |
| "HKDF", | |
| "USER", | |
| } | |
| // stringList is a map from uint32 -> string which can output data for a sorted | |
| // list as C literals. | |
| type stringList struct { | |
| // entries is an array of keys and offsets into |stringData|. The | |
| // offsets are in the bottom 15 bits of each uint32 and the key is the | |
| // top 17 bits. | |
| entries []uint32 | |
| // internedStrings contains the same strings as are in |stringData|, | |
| // but allows for easy deduplication. It maps a string to its offset in | |
| // |stringData|. | |
| internedStrings map[string]uint32 | |
| stringData []byte | |
| } | |
| func newStringList() *stringList { | |
| return &stringList{ | |
| internedStrings: make(map[string]uint32), | |
| } | |
| } | |
| // offsetMask is the bottom 15 bits. It's a mask that selects the offset from a | |
| // uint32 in entries. | |
| const offsetMask = 0x7fff | |
| func (st *stringList) Add(key uint32, value string) error { | |
| if key&offsetMask != 0 { | |
| return errors.New("need bottom 15 bits of the key for the offset") | |
| } | |
| offset, ok := st.internedStrings[value] | |
| if !ok { | |
| offset = uint32(len(st.stringData)) | |
| if offset&offsetMask != offset { | |
| return errors.New("stringList overflow") | |
| } | |
| st.stringData = append(st.stringData, []byte(value)...) | |
| st.stringData = append(st.stringData, 0) | |
| st.internedStrings[value] = offset | |
| } | |
| for _, existing := range st.entries { | |
| if existing>>15 == key>>15 { | |
| panic("duplicate entry") | |
| } | |
| } | |
| st.entries = append(st.entries, key|offset) | |
| return nil | |
| } | |
| // keySlice is a type that implements sorting of entries values. | |
| type keySlice []uint32 | |
| func (ks keySlice) Len() int { | |
| return len(ks) | |
| } | |
| func (ks keySlice) Less(i, j int) bool { | |
| return (ks[i] >> 15) < (ks[j] >> 15) | |
| } | |
| func (ks keySlice) Swap(i, j int) { | |
| ks[i], ks[j] = ks[j], ks[i] | |
| } | |
| func (st *stringList) buildList() []uint32 { | |
| sort.Sort(keySlice(st.entries)) | |
| return st.entries | |
| } | |
| type stringWriter interface { | |
| io.Writer | |
| WriteString(string) (int, error) | |
| } | |
| func (st *stringList) WriteTo(out stringWriter, name string) { | |
| list := st.buildList() | |
| if *verbose { | |
| fmt.Fprintf(os.Stderr, "%s: %d bytes of list and %d bytes of string data.\n", name, 4*len(list), len(st.stringData)) | |
| } | |
| values := "kOpenSSL" + name + "Values" | |
| out.WriteString("const uint32_t " + values + "[] = {\n") | |
| for _, v := range list { | |
| fmt.Fprintf(out, " 0x%x,\n", v) | |
| } | |
| out.WriteString("};\n\n") | |
| out.WriteString("const size_t " + values + "Len = sizeof(" + values + ") / sizeof(" + values + "[0]);\n\n") | |
| stringData := "kOpenSSL" + name + "StringData" | |
| out.WriteString("const char " + stringData + "[] =\n \"") | |
| for i, c := range st.stringData { | |
| if c == 0 { | |
| out.WriteString("\\0\"\n \"") | |
| continue | |
| } | |
| out.Write(st.stringData[i : i+1]) | |
| } | |
| out.WriteString("\";\n\n") | |
| } | |
| type errorData struct { | |
| reasons *stringList | |
| libraryMap map[string]uint32 | |
| } | |
| func (e *errorData) readErrorDataFile(filename string) error { | |
| inFile, err := os.Open(filename) | |
| if err != nil { | |
| return err | |
| } | |
| defer inFile.Close() | |
| scanner := bufio.NewScanner(inFile) | |
| comma := []byte(",") | |
| lineNo := 0 | |
| for scanner.Scan() { | |
| lineNo++ | |
| line := scanner.Bytes() | |
| if len(line) == 0 { | |
| continue | |
| } | |
| parts := bytes.Split(line, comma) | |
| if len(parts) != 3 { | |
| return fmt.Errorf("bad line %d in %s: found %d values but want 3", lineNo, filename, len(parts)) | |
| } | |
| libNum, ok := e.libraryMap[string(parts[0])] | |
| if !ok { | |
| return fmt.Errorf("bad line %d in %s: unknown library", lineNo, filename) | |
| } | |
| if libNum >= 64 { | |
| return fmt.Errorf("bad line %d in %s: library value too large", lineNo, filename) | |
| } | |
| key, err := strconv.ParseUint(string(parts[1]), 10 /* base */, 32 /* bit size */) | |
| if err != nil { | |
| return fmt.Errorf("bad line %d in %s: %s", lineNo, filename, err) | |
| } | |
| if key >= 2048 { | |
| return fmt.Errorf("bad line %d in %s: key too large", lineNo, filename) | |
| } | |
| value := string(parts[2]) | |
| listKey := libNum<<26 | uint32(key)<<15 | |
| err = e.reasons.Add(listKey, value) | |
| if err != nil { | |
| return err | |
| } | |
| } | |
| return scanner.Err() | |
| } | |
| func main() { | |
| flag.Parse() | |
| e := &errorData{ | |
| reasons: newStringList(), | |
| libraryMap: make(map[string]uint32), | |
| } | |
| for i, name := range libraryNames { | |
| e.libraryMap[name] = uint32(i) + 1 | |
| } | |
| cwd, err := os.Open(".") | |
| if err != nil { | |
| panic(err) | |
| } | |
| names, err := cwd.Readdirnames(-1) | |
| if err != nil { | |
| panic(err) | |
| } | |
| sort.Strings(names) | |
| for _, name := range names { | |
| if !strings.HasSuffix(name, ".errordata") { | |
| continue | |
| } | |
| if err := e.readErrorDataFile(name); err != nil { | |
| panic(err) | |
| } | |
| } | |
| out := os.Stdout | |
| out.WriteString(`/* Copyright (c) 2015, Google Inc. | |
| * | |
| * Permission to use, copy, modify, and/or distribute this software for any | |
| * purpose with or without fee is hereby granted, provided that the above | |
| * copyright notice and this permission notice appear in all copies. | |
| * | |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
| * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
| * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | |
| * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | |
| * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ | |
| /* This file was generated by err_data_generate.go. */ | |
| #include <openssl/base.h> | |
| #include <openssl/err.h> | |
| #include <openssl/type_check.h> | |
| `) | |
| for i, name := range libraryNames { | |
| fmt.Fprintf(out, "OPENSSL_STATIC_ASSERT(ERR_LIB_%s == %d, \"library value changed\");\n", name, i+1) | |
| } | |
| fmt.Fprintf(out, "OPENSSL_STATIC_ASSERT(ERR_NUM_LIBS == %d, \"number of libraries changed\");\n", len(libraryNames)+1) | |
| out.WriteString("\n") | |
| e.reasons.WriteTo(out, "Reason") | |
| } |