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