David Benjamin | 3ecd0a5 | 2017-05-19 15:26:18 -0400 | [diff] [blame] | 1 | // Copyright (c) 2017, 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 |
David Benjamin | 54b04fd | 2023-01-29 11:56:25 -0500 | [diff] [blame] | 13 | // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 14 | |
David Benjamin | ece1f86 | 2023-04-24 16:14:08 -0400 | [diff] [blame] | 15 | //go:build ignore |
| 16 | |
David Benjamin | 3ecd0a5 | 2017-05-19 15:26:18 -0400 | [diff] [blame] | 17 | // embed_test_data generates a C++ source file which exports a function, |
| 18 | // GetTestData, which looks up the specified data files. |
| 19 | package main |
| 20 | |
| 21 | import ( |
| 22 | "bytes" |
David Benjamin | cbac9c3 | 2020-06-18 16:14:24 -0400 | [diff] [blame] | 23 | "flag" |
David Benjamin | 3ecd0a5 | 2017-05-19 15:26:18 -0400 | [diff] [blame] | 24 | "fmt" |
David Benjamin | 3ecd0a5 | 2017-05-19 15:26:18 -0400 | [diff] [blame] | 25 | "os" |
David Benjamin | cbac9c3 | 2020-06-18 16:14:24 -0400 | [diff] [blame] | 26 | "strings" |
David Benjamin | 3ecd0a5 | 2017-05-19 15:26:18 -0400 | [diff] [blame] | 27 | ) |
| 28 | |
David Benjamin | cbac9c3 | 2020-06-18 16:14:24 -0400 | [diff] [blame] | 29 | 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") |
| 30 | |
David Benjamin | 3ecd0a5 | 2017-05-19 15:26:18 -0400 | [diff] [blame] | 31 | func quote(in []byte) string { |
David Benjamin | 84c0c90 | 2021-02-27 11:31:39 -0500 | [diff] [blame] | 32 | var lastWasHex bool |
David Benjamin | 3ecd0a5 | 2017-05-19 15:26:18 -0400 | [diff] [blame] | 33 | var buf bytes.Buffer |
| 34 | buf.WriteByte('"') |
| 35 | for _, b := range in { |
David Benjamin | 84c0c90 | 2021-02-27 11:31:39 -0500 | [diff] [blame] | 36 | var wasHex bool |
David Benjamin | 3ecd0a5 | 2017-05-19 15:26:18 -0400 | [diff] [blame] | 37 | switch b { |
| 38 | case '\a': |
| 39 | buf.WriteString(`\a`) |
| 40 | case '\b': |
| 41 | buf.WriteString(`\b`) |
| 42 | case '\f': |
| 43 | buf.WriteString(`\f`) |
| 44 | case '\n': |
| 45 | buf.WriteString(`\n`) |
| 46 | case '\r': |
| 47 | buf.WriteString(`\r`) |
| 48 | case '\t': |
| 49 | buf.WriteString(`\t`) |
| 50 | case '\v': |
| 51 | buf.WriteString(`\v`) |
| 52 | case '"': |
| 53 | buf.WriteString(`\"`) |
Adam Langley | 3314d15 | 2018-08-08 10:27:32 -0700 | [diff] [blame] | 54 | case '\\': |
| 55 | buf.WriteString(`\\`) |
David Benjamin | 3ecd0a5 | 2017-05-19 15:26:18 -0400 | [diff] [blame] | 56 | default: |
David Benjamin | 84c0c90 | 2021-02-27 11:31:39 -0500 | [diff] [blame] | 57 | // Emit printable ASCII characters, [32, 126], as-is to minimize |
| 58 | // file size. However, if the previous character used a hex escape |
| 59 | // sequence, do not emit 0-9 and a-f as-is. C++ interprets "\x123" |
| 60 | // as a single (overflowing) escape sequence, rather than '\x12' |
| 61 | // followed by '3'. |
| 62 | isHexDigit := ('0' <= b && b <= '9') || ('a' <= b && b <= 'f') || ('A' <= b && b <= 'F') |
| 63 | if 32 <= b && b <= 126 && !(lastWasHex && isHexDigit) { |
David Benjamin | 3ecd0a5 | 2017-05-19 15:26:18 -0400 | [diff] [blame] | 64 | buf.WriteByte(b) |
| 65 | } else { |
| 66 | fmt.Fprintf(&buf, "\\x%02x", b) |
David Benjamin | 84c0c90 | 2021-02-27 11:31:39 -0500 | [diff] [blame] | 67 | wasHex = true |
David Benjamin | 3ecd0a5 | 2017-05-19 15:26:18 -0400 | [diff] [blame] | 68 | } |
| 69 | } |
David Benjamin | 84c0c90 | 2021-02-27 11:31:39 -0500 | [diff] [blame] | 70 | lastWasHex = wasHex |
David Benjamin | 3ecd0a5 | 2017-05-19 15:26:18 -0400 | [diff] [blame] | 71 | } |
| 72 | buf.WriteByte('"') |
| 73 | return buf.String() |
| 74 | } |
| 75 | |
| 76 | func main() { |
David Benjamin | cbac9c3 | 2020-06-18 16:14:24 -0400 | [diff] [blame] | 77 | flag.Parse() |
| 78 | |
| 79 | var files []string |
| 80 | if len(*fileList) != 0 { |
David Benjamin | 5511fa8 | 2022-11-12 15:52:28 +0000 | [diff] [blame] | 81 | data, err := os.ReadFile(*fileList) |
David Benjamin | cbac9c3 | 2020-06-18 16:14:24 -0400 | [diff] [blame] | 82 | if err != nil { |
| 83 | fmt.Fprintf(os.Stderr, "Error reading %s: %s.\n", *fileList, err) |
| 84 | os.Exit(1) |
| 85 | } |
| 86 | files = strings.FieldsFunc(string(data), func(r rune) bool { return r == '\r' || r == '\n' }) |
| 87 | } |
| 88 | |
| 89 | files = append(files, flag.Args()...) |
| 90 | |
David Benjamin | 3ecd0a5 | 2017-05-19 15:26:18 -0400 | [diff] [blame] | 91 | fmt.Printf(`/* Copyright (c) 2017, Google Inc. |
| 92 | * |
| 93 | * Permission to use, copy, modify, and/or distribute this software for any |
| 94 | * purpose with or without fee is hereby granted, provided that the above |
| 95 | * copyright notice and this permission notice appear in all copies. |
| 96 | * |
| 97 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 98 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 99 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
| 100 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 101 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
| 102 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
| 103 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ |
| 104 | |
| 105 | /* This file is generated by: |
| 106 | `) |
| 107 | fmt.Printf(" * go run util/embed_test_data.go") |
David Benjamin | cbac9c3 | 2020-06-18 16:14:24 -0400 | [diff] [blame] | 108 | for _, arg := range files { |
David Benjamin | 3ecd0a5 | 2017-05-19 15:26:18 -0400 | [diff] [blame] | 109 | fmt.Printf(" \\\n * %s", arg) |
| 110 | } |
| 111 | fmt.Printf(" */\n") |
| 112 | |
| 113 | fmt.Printf(` |
David Benjamin | 59e1a81 | 2017-05-24 15:56:28 -0400 | [diff] [blame] | 114 | /* clang-format off */ |
| 115 | |
David Benjamin | 3ecd0a5 | 2017-05-19 15:26:18 -0400 | [diff] [blame] | 116 | #include <stdlib.h> |
| 117 | #include <string.h> |
| 118 | |
| 119 | #include <algorithm> |
| 120 | #include <string> |
| 121 | |
| 122 | |
| 123 | `) |
| 124 | |
| 125 | // MSVC limits the length of string constants, so we emit an array of |
| 126 | // them and concatenate at runtime. We could also use a single array |
| 127 | // literal, but this is less compact. |
| 128 | const chunkSize = 8192 |
| 129 | |
David Benjamin | cbac9c3 | 2020-06-18 16:14:24 -0400 | [diff] [blame] | 130 | for i, arg := range files { |
David Benjamin | 5511fa8 | 2022-11-12 15:52:28 +0000 | [diff] [blame] | 131 | data, err := os.ReadFile(arg) |
David Benjamin | 3ecd0a5 | 2017-05-19 15:26:18 -0400 | [diff] [blame] | 132 | if err != nil { |
Adam Langley | 3314d15 | 2018-08-08 10:27:32 -0700 | [diff] [blame] | 133 | fmt.Fprintf(os.Stderr, "Error reading %s: %s.\n", arg, err) |
David Benjamin | 3ecd0a5 | 2017-05-19 15:26:18 -0400 | [diff] [blame] | 134 | os.Exit(1) |
| 135 | } |
Adam Langley | 3314d15 | 2018-08-08 10:27:32 -0700 | [diff] [blame] | 136 | fmt.Printf("static const size_t kLen%d = %d;\n\n", i, len(data)) |
| 137 | |
David Benjamin | 3ecd0a5 | 2017-05-19 15:26:18 -0400 | [diff] [blame] | 138 | fmt.Printf("static const char *kData%d[] = {\n", i) |
Adam Langley | 3314d15 | 2018-08-08 10:27:32 -0700 | [diff] [blame] | 139 | for len(data) > 0 { |
David Benjamin | 3ecd0a5 | 2017-05-19 15:26:18 -0400 | [diff] [blame] | 140 | chunk := chunkSize |
Adam Langley | 3314d15 | 2018-08-08 10:27:32 -0700 | [diff] [blame] | 141 | if chunk > len(data) { |
| 142 | chunk = len(data) |
David Benjamin | 3ecd0a5 | 2017-05-19 15:26:18 -0400 | [diff] [blame] | 143 | } |
Adam Langley | 3314d15 | 2018-08-08 10:27:32 -0700 | [diff] [blame] | 144 | fmt.Printf(" %s,\n", quote(data[:chunk])) |
| 145 | data = data[chunk:] |
David Benjamin | 3ecd0a5 | 2017-05-19 15:26:18 -0400 | [diff] [blame] | 146 | } |
| 147 | fmt.Printf("};\n") |
David Benjamin | 3ecd0a5 | 2017-05-19 15:26:18 -0400 | [diff] [blame] | 148 | } |
| 149 | |
| 150 | fmt.Printf(`static std::string AssembleString(const char **data, size_t len) { |
| 151 | std::string ret; |
| 152 | for (size_t i = 0; i < len; i += %d) { |
| 153 | size_t chunk = std::min(static_cast<size_t>(%d), len - i); |
| 154 | ret.append(data[i / %d], chunk); |
| 155 | } |
| 156 | return ret; |
| 157 | } |
| 158 | |
| 159 | /* Silence -Wmissing-declarations. */ |
| 160 | std::string GetTestData(const char *path); |
| 161 | |
| 162 | std::string GetTestData(const char *path) { |
| 163 | `, chunkSize, chunkSize, chunkSize) |
David Benjamin | cbac9c3 | 2020-06-18 16:14:24 -0400 | [diff] [blame] | 164 | for i, arg := range files { |
David Benjamin | 3ecd0a5 | 2017-05-19 15:26:18 -0400 | [diff] [blame] | 165 | fmt.Printf(" if (strcmp(path, %s) == 0) {\n", quote([]byte(arg))) |
| 166 | fmt.Printf(" return AssembleString(kData%d, kLen%d);\n", i, i) |
| 167 | fmt.Printf(" }\n") |
| 168 | } |
| 169 | fmt.Printf(` fprintf(stderr, "File not embedded: %%s.\n", path); |
| 170 | abort(); |
| 171 | } |
| 172 | `) |
| 173 | |
| 174 | } |