|  | // Copyright (c) 2017, 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. */ | 
|  |  | 
|  | // embed_test_data generates a C++ source file which exports a function, | 
|  | // GetTestData, which looks up the specified data files. | 
|  | package main | 
|  |  | 
|  | import ( | 
|  | "bytes" | 
|  | "flag" | 
|  | "fmt" | 
|  | "io/ioutil" | 
|  | "os" | 
|  | "strings" | 
|  | ) | 
|  |  | 
|  | var fileList = flag.String("file-list", "", "if not empty, the path to a file containing a newline-separated list of files, to work around Windows command-line limits") | 
|  |  | 
|  | func quote(in []byte) string { | 
|  | var lastWasHex bool | 
|  | var buf bytes.Buffer | 
|  | buf.WriteByte('"') | 
|  | for _, b := range in { | 
|  | var wasHex bool | 
|  | switch b { | 
|  | case '\a': | 
|  | buf.WriteString(`\a`) | 
|  | case '\b': | 
|  | buf.WriteString(`\b`) | 
|  | case '\f': | 
|  | buf.WriteString(`\f`) | 
|  | case '\n': | 
|  | buf.WriteString(`\n`) | 
|  | case '\r': | 
|  | buf.WriteString(`\r`) | 
|  | case '\t': | 
|  | buf.WriteString(`\t`) | 
|  | case '\v': | 
|  | buf.WriteString(`\v`) | 
|  | case '"': | 
|  | buf.WriteString(`\"`) | 
|  | case '\\': | 
|  | buf.WriteString(`\\`) | 
|  | default: | 
|  | // Emit printable ASCII characters, [32, 126], as-is to minimize | 
|  | // file size. However, if the previous character used a hex escape | 
|  | // sequence, do not emit 0-9 and a-f as-is. C++ interprets "\x123" | 
|  | // as a single (overflowing) escape sequence, rather than '\x12' | 
|  | // followed by '3'. | 
|  | isHexDigit := ('0' <= b && b <= '9') || ('a' <= b && b <= 'f') || ('A' <= b && b <= 'F') | 
|  | if 32 <= b && b <= 126 && !(lastWasHex && isHexDigit) { | 
|  | buf.WriteByte(b) | 
|  | } else { | 
|  | fmt.Fprintf(&buf, "\\x%02x", b) | 
|  | wasHex = true | 
|  | } | 
|  | } | 
|  | lastWasHex = wasHex | 
|  | } | 
|  | buf.WriteByte('"') | 
|  | return buf.String() | 
|  | } | 
|  |  | 
|  | func main() { | 
|  | flag.Parse() | 
|  |  | 
|  | var files []string | 
|  | if len(*fileList) != 0 { | 
|  | data, err := ioutil.ReadFile(*fileList) | 
|  | if err != nil { | 
|  | fmt.Fprintf(os.Stderr, "Error reading %s: %s.\n", *fileList, err) | 
|  | os.Exit(1) | 
|  | } | 
|  | files = strings.FieldsFunc(string(data), func(r rune) bool { return r == '\r' || r == '\n' }) | 
|  | } | 
|  |  | 
|  | files = append(files, flag.Args()...) | 
|  |  | 
|  | fmt.Printf(`/* Copyright (c) 2017, 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 is generated by: | 
|  | `) | 
|  | fmt.Printf(" *   go run util/embed_test_data.go") | 
|  | for _, arg := range files { | 
|  | fmt.Printf(" \\\n *       %s", arg) | 
|  | } | 
|  | fmt.Printf(" */\n") | 
|  |  | 
|  | fmt.Printf(` | 
|  | /* clang-format off */ | 
|  |  | 
|  | #include <stdlib.h> | 
|  | #include <string.h> | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <string> | 
|  |  | 
|  |  | 
|  | `) | 
|  |  | 
|  | // MSVC limits the length of string constants, so we emit an array of | 
|  | // them and concatenate at runtime. We could also use a single array | 
|  | // literal, but this is less compact. | 
|  | const chunkSize = 8192 | 
|  |  | 
|  | for i, arg := range files { | 
|  | data, err := ioutil.ReadFile(arg) | 
|  | if err != nil { | 
|  | fmt.Fprintf(os.Stderr, "Error reading %s: %s.\n", arg, err) | 
|  | os.Exit(1) | 
|  | } | 
|  | fmt.Printf("static const size_t kLen%d = %d;\n\n", i, len(data)) | 
|  |  | 
|  | fmt.Printf("static const char *kData%d[] = {\n", i) | 
|  | for len(data) > 0 { | 
|  | chunk := chunkSize | 
|  | if chunk > len(data) { | 
|  | chunk = len(data) | 
|  | } | 
|  | fmt.Printf("    %s,\n", quote(data[:chunk])) | 
|  | data = data[chunk:] | 
|  | } | 
|  | fmt.Printf("};\n") | 
|  | } | 
|  |  | 
|  | fmt.Printf(`static std::string AssembleString(const char **data, size_t len) { | 
|  | std::string ret; | 
|  | for (size_t i = 0; i < len; i += %d) { | 
|  | size_t chunk = std::min(static_cast<size_t>(%d), len - i); | 
|  | ret.append(data[i / %d], chunk); | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* Silence -Wmissing-declarations. */ | 
|  | std::string GetTestData(const char *path); | 
|  |  | 
|  | std::string GetTestData(const char *path) { | 
|  | `, chunkSize, chunkSize, chunkSize) | 
|  | for i, arg := range files { | 
|  | fmt.Printf("  if (strcmp(path, %s) == 0) {\n", quote([]byte(arg))) | 
|  | fmt.Printf("    return AssembleString(kData%d, kLen%d);\n", i, i) | 
|  | fmt.Printf("  }\n") | 
|  | } | 
|  | fmt.Printf(`  fprintf(stderr, "File not embedded: %%s.\n", path); | 
|  | abort(); | 
|  | } | 
|  | `) | 
|  |  | 
|  | } |