| // 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 <openssl/base.h> | 
 | #include <openssl/err.h> | 
 |  | 
 | #include <assert.h> | 
 |  | 
 | `) | 
 |  | 
 | 	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 | 
 | } |