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