diff --git a/README.md b/README.md
index 4db2921..2ef84bb 100644
--- a/README.md
+++ b/README.md
@@ -4,45 +4,10 @@ This tool converts any file into managable Go source code. Useful for embedding
binary data into a go program. The file data is optionally gzip compressed
before being converted to a raw byte slice.
+
### Usage
-The simplest invocation is to pass it only the input file name.
-The output file and code settings are inferred from this automatically.
-
- $ go-bindata testdata/gophercolor.png
- [w] No output file specified. Using 'testdata/gophercolor.png.go'.
- [w] No package name specified. Using 'main'.
- [w] No function name specified. Using 'testdata_gophercolor_png'.
-
-This creates the `testdata/gophercolor.png.go` file which has a package
-declaration with name `main` and one function named `testdata_gophercolor_png` with
-the following signature:
-
-```go
-func testdata_gophercolor_png() []byte
-```
-
-You can now simply include the new .go file in your program and call
-`testdata_gophercolor_png()` to get the (uncompressed) image data. The function panics
-if something went wrong during decompression. See the testdata directory for
-example input and output files for various modes.
-
-Aternatively, you can pipe the input file data into stdin. `go-bindata` will
-then spit out the generated Go code to stdout. This does require explicitly
-naming the desired function name, as it can not be inferred from the
-input data. The package name will still default to 'main'.
-
- $ cat testdata/gophercolor.png | go-bindata -f gophercolor_png | gofmt
-
-Invoke the program with the `-h` flag for more options.
-
-In order to strip off a part of the generated function name, we can use the `-prefix` flag.
-In the above example, the input file `testdata/gophercolor.png` yields a function named
-`testdata_gophercolor_png`. If we want the `testdata` component to be left out, we invoke
-the program as follows:
-
- $ go-bindata -prefix "testdata/" testdata/gophercolor.png
-
+TODO
### Lower memory footprint
@@ -108,25 +73,6 @@ even increase the size of the data.
The default behaviour of the program is to use compression.
-### Table of Contents
-
-With the `-toc` flag, we can have `go-bindata` create a table of contents for all the files
-which have been generated by the tool. It does this by first generating a new file named
-`bindata-toc.go`. This contains a global map of type `map[string] func() []byte`. It uses the
-input filename as the key and the data function as the value. We can use this
-to fetch all data for our files, matching a given pattern.
-
-It then appands an `init` function to each generated file, which simply makes the data
-function append itself to the global `bindata` map.
-
-Once you have compiled your program with all these new files and run it, the map will
-be populated by all generated data files.
-
-**Note**: The `bindata-toc.go` file will not be created when we run in `pipe` mode.
-The reason being, that the tool does not write any files at all, as it has no idea
-where to save them. The data file is written to `stdout` instead after all.
-
-
#### Table of Contents keys
The keys used in the `go_bindata` map, are the same as the input file name passed to `go-bindata`.
@@ -148,20 +94,6 @@ Running with the `-prefix` flag, we get:
go_bindata["templates/foo.html"] = templates_foo_html
-#### bindata-toc.go
-
-The `bindata-toc.go` file is very simple and looks as follows:
-
-```go
-package $PACKAGENAME
-
-// Global Table of Contents map. Generated by go-bindata.
-// After startup of the program, all generated data files will
-// put themselves in this map. The key is the full filename, as
-// supplied to go-bindata.
-var go_bindata = make(map[string] func() []byte)
-```
-
#### Build tags
With the optional -tags flag, you can specify any go build tags that
diff --git a/config.go b/config.go
new file mode 100644
index 0000000..c9d7f96
--- /dev/null
+++ b/config.go
@@ -0,0 +1,92 @@
+// This work is subject to the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
+// license. Its contents can be found at:
+// http://creativecommons.org/publicdomain/zero/1.0/
+
+package bindata
+
+// Config defines a set of options for the asset conversion.
+type Config struct {
+ // Tags specify a set of optional build tags, which should be
+ // included in the generated output. The tags are appended to a
+ // `// +build` line in the beginning of the output file
+ // and must follow the build tags syntax specified by the go tool.
+ Tags []string
+
+ // Input defines the directory path, containing all asset files.
+ // This may contain sub directories, which will be included in the
+ // conversion.
+ Input string
+
+ // Output defines the output directory for the generated code.
+ Output string
+
+ /*
+ Prefix defines a path prefix which should be stripped from all
+ file names when generating the keys in the table of contents.
+ For example, running without the `-prefix` flag, we get:
+
+ $ go-bindata /path/to/templates
+ go_bindata["/path/to/templates/foo.html"] = _path_to_templates_foo_html
+
+ Running with the `-prefix` flag, we get:
+
+ $ go-bindata -prefix "/path/to/" /path/to/templates/foo.html
+ go_bindata["templates/foo.html"] = templates_foo_html
+ */
+ Prefix string
+
+ /*
+ NoMemCopy will alter the way the output file is generated.
+
+ It will employ a hack that allows us to read the file data directly from
+ the compiled program's `.rodata` section. This ensures that when we call
+ call our generated function, we omit unnecessary mem copies.
+
+ The downside of this, is that it requires dependencies on the `reflect` and
+ `unsafe` packages. These may be restricted on platforms like AppEngine and
+ thus prevent you from using this mode.
+
+ Another disadvantage is that the byte slice we create, is strictly read-only.
+ For most use-cases this is not a problem, but if you ever try to alter the
+ returned byte slice, a runtime panic is thrown. Use this mode only on target
+ platforms where memory constraints are an issue.
+
+ The default behaviour is to use the old code generation method. This
+ prevents the two previously mentioned issues, but will employ at least one
+ extra memcopy and thus increase memory requirements.
+
+ For instance, consider the following two examples:
+
+ This would be the default mode, using an extra memcopy but gives a safe
+ implementation without dependencies on `reflect` and `unsafe`:
+
+ func myfile() []byte {
+ return []byte{0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a}
+ }
+
+ Here is the same functionality, but uses the `.rodata` hack.
+ The byte slice returned from this example can not be written to without
+ generating a runtime error.
+
+ var _myfile = "\x89\x50\x4e\x47\x0d\x0a\x1a"
+
+ func myfile() []byte {
+ var empty [0]byte
+ sx := (*reflect.StringHeader)(unsafe.Pointer(&_myfile))
+ b := empty[:]
+ bx := (*reflect.SliceHeader)(unsafe.Pointer(&b))
+ bx.Data = sx.Data
+ bx.Len = len(_myfile)
+ bx.Cap = bx.Len
+ return b
+ }
+ */
+ NoMemCopy bool
+
+ /*
+ Compress means the assets are GZIP compressed before being turned
+ into Go code. The generated function will automatically unzip
+ the file data when called.
+ */
+ Compress bool
+}
diff --git a/convert.go b/convert.go
new file mode 100644
index 0000000..757add6
--- /dev/null
+++ b/convert.go
@@ -0,0 +1,120 @@
+// This work is subject to the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
+// license. Its contents can be found at:
+// http://creativecommons.org/publicdomain/zero/1.0/
+
+package bindata
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "regexp"
+ "strings"
+ "unicode"
+)
+
+// ProgressFunc is a callback handler which is fired whenever
+// bindata begins translating a new file.
+//
+// It takes the file path and the current and total file counts.
+// This can be used to indicate progress of the conversion.
+//
+// If this handler returns true, the processing is stopped and
+// Translate() returns immediately.
+type ProgressFunc func(file string, current, total int) bool
+
+// Translate reads assets from an input directory, converts them
+// to Go code and writes new files to the output directory specified
+// in the given configuration.
+func Translate(c *Config, pf ProgressFunc) error {
+ toc := make(map[string]string)
+ err := findFiles(c.Input, c.Prefix, toc)
+
+ if err != nil {
+ return err
+ }
+
+ var current int
+ for key, value := range toc {
+ if pf != nil {
+ current++
+ if pf(key, current, len(toc)) {
+ return nil
+ }
+ }
+
+ _ = value
+ }
+
+ return nil
+}
+
+// fillTOC recursively finds all the file paths in the given directory tree.
+// They are added to the given map as keys. Values will be safe function names
+// for each file, which will be used when generating the output code.
+func findFiles(dir, prefix string, toc map[string]string) error {
+ if len(prefix) > 0 {
+ dir, _ = filepath.Abs(dir)
+ prefix, _ = filepath.Abs(prefix)
+ }
+
+ fd, err := os.Open(dir)
+ if err != nil {
+ return err
+ }
+
+ defer fd.Close()
+
+ list, err := fd.Readdir(0)
+ if err != nil {
+ return err
+ }
+
+ for _, file := range list {
+ key := filepath.Join(dir, file.Name())
+
+ if file.IsDir() {
+ findFiles(key, prefix, toc)
+ } else {
+ if strings.HasPrefix(key, prefix) {
+ key = key[len(prefix):]
+ }
+
+ // If we have a leading slash, get rid of it.
+ if len(key) > 0 && key[0] == '/' {
+ key = key[1:]
+ }
+
+ // This shouldn't happen.
+ if len(key) == 0 {
+ return fmt.Errorf("Invalid file: %v", filepath.Join(dir, file.Name()))
+ }
+
+ value := safeFunctionName(key)
+ toc[key] = value
+ }
+ }
+
+ return nil
+}
+
+var regFuncName = regexp.MustCompile(`[^a-zA-Z0-9_]`)
+
+// safeFunctionName converts the given name into a name
+// which qualifies as a valid function identifier.
+func safeFunctionName(name string) string {
+ name = strings.ToLower(name)
+ name = regFuncName.ReplaceAllString(name, "_")
+
+ // Identifier can't start with a digit.
+ if unicode.IsDigit(rune(name[0])) {
+ name = "_" + name
+ }
+
+ // Get rid of "__" instances for niceness.
+ for strings.Index(name, "__") > -1 {
+ name = strings.Replace(name, "__", "_", -1)
+ }
+
+ return name
+}
diff --git a/go-bindata/config.go b/go-bindata/config.go
deleted file mode 100644
index d5cdaf5..0000000
--- a/go-bindata/config.go
+++ /dev/null
@@ -1,106 +0,0 @@
-// This work is subject to the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
-// license. Its contents can be found at:
-// http://creativecommons.org/publicdomain/zero/1.0/
-
-package main
-
-import (
- "flag"
- "fmt"
- "os"
- "path/filepath"
- "strings"
-)
-
-// Config defines command line options.
-type Config struct {
- Input string // Input directory with assets.
- Output string // Output directory for generated code.
- Tags []string // Build tags to include in output files.
-}
-
-// NewConfig create s anew, filled configuration instance
-// by reading and parsing command line options.
-//
-// This function exits the program with an error, if
-// any of the command line options are incorrect.
-func NewConfig() *Config {
- var version bool
- var tagstr string
-
- c := new(Config)
-
- flag.Usage = func() {
- fmt.Printf("Usage: %s [options] [