// 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" "fmt" "io" "os" "path" "sort" "strconv" ) // 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", "TRUST_TOKEN", "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 } func (st *stringList) buildList() []uint32 { sort.Slice(st.entries, func(i, j int) bool { return (st.entries[i] >> 15) < (st.entries[j] >> 15) }) return st.entries } type stringWriter interface { io.Writer WriteString(string) (int, error) } func (st *stringList) WriteTo(out stringWriter, name string) { list := st.buildList() 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() } type ErrDataTask struct { TargetName string Inputs []string } func (t *ErrDataTask) Destination() string { return path.Join("gen", t.TargetName, "err_data.c") } func (t *ErrDataTask) Run() ([]byte, error) { e := &errorData{ reasons: newStringList(), libraryMap: make(map[string]uint32), } for i, name := range libraryNames { e.libraryMap[name] = uint32(i) + 1 } for _, input := range t.Inputs { if err := e.readErrorDataFile(input); err != nil { return nil, err } } var out bytes.Buffer 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 go run ./util/pregenerate. */ #include #include #include `) for i, name := range libraryNames { fmt.Fprintf(&out, "static_assert(ERR_LIB_%s == %d, \"library value changed\");\n", name, i+1) } fmt.Fprintf(&out, "static_assert(ERR_NUM_LIBS == %d, \"number of libraries changed\");\n", len(libraryNames)+1) out.WriteString("\n") e.reasons.WriteTo(&out, "Reason") return out.Bytes(), nil }