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