blob: ae7135fae451ae3dc8eefc58d3878700be61162e [file] [log] [blame]
David Benjamin3ecd0a52017-05-19 15:26:18 -04001// 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 Benjamin54b04fd2023-01-29 11:56:25 -050013// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
David Benjaminece1f862023-04-24 16:14:08 -040015//go:build ignore
16
David Benjamin3ecd0a52017-05-19 15:26:18 -040017// embed_test_data generates a C++ source file which exports a function,
18// GetTestData, which looks up the specified data files.
19package main
20
21import (
22 "bytes"
David Benjamincbac9c32020-06-18 16:14:24 -040023 "flag"
David Benjamin3ecd0a52017-05-19 15:26:18 -040024 "fmt"
David Benjamin3ecd0a52017-05-19 15:26:18 -040025 "os"
David Benjamincbac9c32020-06-18 16:14:24 -040026 "strings"
David Benjamin3ecd0a52017-05-19 15:26:18 -040027)
28
David Benjamincbac9c32020-06-18 16:14:24 -040029var 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 Benjamin3ecd0a52017-05-19 15:26:18 -040031func quote(in []byte) string {
David Benjamin84c0c902021-02-27 11:31:39 -050032 var lastWasHex bool
David Benjamin3ecd0a52017-05-19 15:26:18 -040033 var buf bytes.Buffer
34 buf.WriteByte('"')
35 for _, b := range in {
David Benjamin84c0c902021-02-27 11:31:39 -050036 var wasHex bool
David Benjamin3ecd0a52017-05-19 15:26:18 -040037 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 Langley3314d152018-08-08 10:27:32 -070054 case '\\':
55 buf.WriteString(`\\`)
David Benjamin3ecd0a52017-05-19 15:26:18 -040056 default:
David Benjamin84c0c902021-02-27 11:31:39 -050057 // 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 Benjamin3ecd0a52017-05-19 15:26:18 -040064 buf.WriteByte(b)
65 } else {
66 fmt.Fprintf(&buf, "\\x%02x", b)
David Benjamin84c0c902021-02-27 11:31:39 -050067 wasHex = true
David Benjamin3ecd0a52017-05-19 15:26:18 -040068 }
69 }
David Benjamin84c0c902021-02-27 11:31:39 -050070 lastWasHex = wasHex
David Benjamin3ecd0a52017-05-19 15:26:18 -040071 }
72 buf.WriteByte('"')
73 return buf.String()
74}
75
76func main() {
David Benjamincbac9c32020-06-18 16:14:24 -040077 flag.Parse()
78
79 var files []string
80 if len(*fileList) != 0 {
David Benjamin5511fa82022-11-12 15:52:28 +000081 data, err := os.ReadFile(*fileList)
David Benjamincbac9c32020-06-18 16:14:24 -040082 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 Benjamin3ecd0a52017-05-19 15:26:18 -040091 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 Benjamincbac9c32020-06-18 16:14:24 -0400108 for _, arg := range files {
David Benjamin3ecd0a52017-05-19 15:26:18 -0400109 fmt.Printf(" \\\n * %s", arg)
110 }
111 fmt.Printf(" */\n")
112
113 fmt.Printf(`
David Benjamin59e1a812017-05-24 15:56:28 -0400114/* clang-format off */
115
David Benjamin3ecd0a52017-05-19 15:26:18 -0400116#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 Benjamincbac9c32020-06-18 16:14:24 -0400130 for i, arg := range files {
David Benjamin5511fa82022-11-12 15:52:28 +0000131 data, err := os.ReadFile(arg)
David Benjamin3ecd0a52017-05-19 15:26:18 -0400132 if err != nil {
Adam Langley3314d152018-08-08 10:27:32 -0700133 fmt.Fprintf(os.Stderr, "Error reading %s: %s.\n", arg, err)
David Benjamin3ecd0a52017-05-19 15:26:18 -0400134 os.Exit(1)
135 }
Adam Langley3314d152018-08-08 10:27:32 -0700136 fmt.Printf("static const size_t kLen%d = %d;\n\n", i, len(data))
137
David Benjamin3ecd0a52017-05-19 15:26:18 -0400138 fmt.Printf("static const char *kData%d[] = {\n", i)
Adam Langley3314d152018-08-08 10:27:32 -0700139 for len(data) > 0 {
David Benjamin3ecd0a52017-05-19 15:26:18 -0400140 chunk := chunkSize
Adam Langley3314d152018-08-08 10:27:32 -0700141 if chunk > len(data) {
142 chunk = len(data)
David Benjamin3ecd0a52017-05-19 15:26:18 -0400143 }
Adam Langley3314d152018-08-08 10:27:32 -0700144 fmt.Printf(" %s,\n", quote(data[:chunk]))
145 data = data[chunk:]
David Benjamin3ecd0a52017-05-19 15:26:18 -0400146 }
147 fmt.Printf("};\n")
David Benjamin3ecd0a52017-05-19 15:26:18 -0400148 }
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. */
160std::string GetTestData(const char *path);
161
162std::string GetTestData(const char *path) {
163`, chunkSize, chunkSize, chunkSize)
David Benjamincbac9c32020-06-18 16:14:24 -0400164 for i, arg := range files {
David Benjamin3ecd0a52017-05-19 15:26:18 -0400165 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}