// Copyright (c) 2017, Google Inc.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
// embed_test_data generates a C++ source file which exports a function,
// GetTestData, which looks up the specified data files.
package main
import (
"bytes"
"flag"
"fmt"
"io/ioutil"
"os"
"strings"
)
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" )
func quote ( in [ ] byte ) string {
var lastWasHex bool
var buf bytes . Buffer
buf . WriteByte ( '"' )
for _ , b := range in {
var wasHex bool
switch b {
case '\a' :
buf . WriteString ( ` \a ` )
case '\b' :
buf . WriteString ( ` \b ` )
case '\f' :
buf . WriteString ( ` \f ` )
case '\n' :
buf . WriteString ( ` \n ` )
case '\r' :
buf . WriteString ( ` \r ` )
case '\t' :
buf . WriteString ( ` \t ` )
case '\v' :
buf . WriteString ( ` \v ` )
case '"' :
buf . WriteString ( ` \" ` )
case '\\' :
buf . WriteString ( ` \\ ` )
default :
// Emit printable ASCII characters, [32, 126], as-is to minimize
// file size. However, if the previous character used a hex escape
// sequence, do not emit 0-9 and a-f as-is. C++ interprets "\x123"
// as a single (overflowing) escape sequence, rather than '\x12'
// followed by '3'.
isHexDigit := ( '0' <= b && b <= '9' ) || ( 'a' <= b && b <= 'f' ) || ( 'A' <= b && b <= 'F' )
if 32 <= b && b <= 126 && ! ( lastWasHex && isHexDigit ) {
buf . WriteByte ( b )
} else {
fmt . Fprintf ( & buf , "\\x%02x" , b )
wasHex = true
}
}
lastWasHex = wasHex
}
buf . WriteByte ( '"' )
return buf . String ( )
}
func main ( ) {
flag . Parse ( )
var files [ ] string
if len ( * fileList ) != 0 {
data , err := ioutil . ReadFile ( * fileList )
if err != nil {
fmt . Fprintf ( os . Stderr , "Error reading %s: %s.\n" , * fileList , err )
os . Exit ( 1 )
}
files = strings . FieldsFunc ( string ( data ) , func ( r rune ) bool { return r == '\r' || r == '\n' } )
}
files = append ( files , flag . Args ( ) ... )
fmt . Printf ( ` / * Copyright ( c ) 2017 , Google Inc .
*
* Permission to use , copy , modify , and / or distribute this software for any
* purpose with or without fee is hereby granted , provided that the above
* copyright notice and this permission notice appear in all copies .
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS . IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL , DIRECT , INDIRECT , OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE , DATA OR PROFITS , WHETHER IN AN ACTION
* OF CONTRACT , NEGLIGENCE OR OTHER TORTIOUS ACTION , ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE . * /
/ * This file is generated by :
` )
fmt . Printf ( " * go run util/embed_test_data.go" )
for _ , arg := range files {
fmt . Printf ( " \\\n * %s" , arg )
}
fmt . Printf ( " */\n" )
fmt . Printf ( `
/* clang-format off */
# include < stdlib . h >
# include < string . h >
# include < algorithm >
# include < string >
` )
// MSVC limits the length of string constants, so we emit an array of
// them and concatenate at runtime. We could also use a single array
// literal, but this is less compact.
const chunkSize = 8192
for i , arg := range files {
data , err := ioutil . ReadFile ( arg )
if err != nil {
fmt . Fprintf ( os . Stderr , "Error reading %s: %s.\n" , arg , err )
os . Exit ( 1 )
}
fmt . Printf ( "static const size_t kLen%d = %d;\n\n" , i , len ( data ) )
fmt . Printf ( "static const char *kData%d[] = {\n" , i )
for len ( data ) > 0 {
chunk := chunkSize
if chunk > len ( data ) {
chunk = len ( data )
}
fmt . Printf ( " %s,\n" , quote ( data [ : chunk ] ) )
data = data [ chunk : ]
}
fmt . Printf ( "};\n" )
}
fmt . Printf ( ` static std : : string AssembleString ( const char * * data , size_t len ) {
std : : string ret ;
for ( size_t i = 0 ; i < len ; i += % d ) {
size_t chunk = std : : min ( static_cast < size_t > ( % d ) , len - i ) ;
ret . append ( data [ i / % d ] , chunk ) ;
}
return ret ;
}
/* Silence -Wmissing-declarations. */
std : : string GetTestData ( const char * path ) ;
std : : string GetTestData ( const char * path ) {
` , chunkSize , chunkSize , chunkSize )
for i , arg := range files {
fmt . Printf ( " if (strcmp(path, %s) == 0) {\n" , quote ( [ ] byte ( arg ) ) )
fmt . Printf ( " return AssembleString(kData%d, kLen%d);\n" , i , i )
fmt . Printf ( " }\n" )
}
fmt . Printf ( ` fprintf ( stderr , "File not embedded: %%s.\n" , path ) ;
abort ( ) ;
}
` )
}