translate.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. // This work is subject to the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
  2. // license. Its contents can be found at:
  3. // http://creativecommons.org/publicdomain/zero/1.0/
  4. package bindata
  5. import (
  6. "compress/gzip"
  7. "fmt"
  8. "io"
  9. "regexp"
  10. "strings"
  11. "unicode"
  12. )
  13. var regFuncName = regexp.MustCompile(`[^a-zA-Z0-9_]`)
  14. // translate translates the input file to go source code.
  15. func Translate(input io.Reader, output io.Writer, pkgname, funcname string, uncompressed, nomemcpy bool) {
  16. if nomemcpy {
  17. if uncompressed {
  18. translate_nomemcpy_uncomp(input, output, pkgname, funcname)
  19. } else {
  20. translate_nomemcpy_comp(input, output, pkgname, funcname)
  21. }
  22. } else {
  23. if uncompressed {
  24. translate_memcpy_uncomp(input, output, pkgname, funcname)
  25. } else {
  26. translate_memcpy_comp(input, output, pkgname, funcname)
  27. }
  28. }
  29. }
  30. // input -> gzip -> gowriter -> output.
  31. func translate_memcpy_comp(input io.Reader, output io.Writer, pkgname, funcname string) {
  32. fmt.Fprintf(output, `package %s
  33. import (
  34. "bytes"
  35. "compress/gzip"
  36. "io"
  37. )
  38. // %s returns raw, uncompressed file data.
  39. func %s() []byte {
  40. gz, err := gzip.NewReader(bytes.NewBuffer([]byte{`, pkgname, funcname, funcname)
  41. gz := gzip.NewWriter(&ByteWriter{Writer: output})
  42. io.Copy(gz, input)
  43. gz.Close()
  44. fmt.Fprint(output, `
  45. }))
  46. if err != nil {
  47. panic("Decompression failed: " + err.Error())
  48. }
  49. var b bytes.Buffer
  50. io.Copy(&b, gz)
  51. gz.Close()
  52. return b.Bytes()
  53. }`)
  54. }
  55. // input -> gzip -> gowriter -> output.
  56. func translate_memcpy_uncomp(input io.Reader, output io.Writer, pkgname, funcname string) {
  57. fmt.Fprintf(output, `package %s
  58. // %s returns raw file data.
  59. func %s() []byte {
  60. return []byte{`, pkgname, funcname, funcname)
  61. io.Copy(&ByteWriter{Writer: output}, input)
  62. fmt.Fprint(output, `
  63. }
  64. }`)
  65. }
  66. // input -> gzip -> gowriter -> output.
  67. func translate_nomemcpy_comp(input io.Reader, output io.Writer, pkgname, funcname string) {
  68. fmt.Fprintf(output, `package %s
  69. import (
  70. "bytes"
  71. "compress/gzip"
  72. "io"
  73. "reflect"
  74. "unsafe"
  75. )
  76. var _%s = "`, pkgname, funcname)
  77. gz := gzip.NewWriter(&StringWriter{Writer: output})
  78. io.Copy(gz, input)
  79. gz.Close()
  80. fmt.Fprintf(output, `"
  81. // %s returns raw, uncompressed file data.
  82. func %s() []byte {
  83. var empty [0]byte
  84. sx := (*reflect.StringHeader)(unsafe.Pointer(&_%s))
  85. b := empty[:]
  86. bx := (*reflect.SliceHeader)(unsafe.Pointer(&b))
  87. bx.Data = sx.Data
  88. bx.Len = len(_%s)
  89. bx.Cap = bx.Len
  90. gz, err := gzip.NewReader(bytes.NewBuffer(b))
  91. if err != nil {
  92. panic("Decompression failed: " + err.Error())
  93. }
  94. var buf bytes.Buffer
  95. io.Copy(&buf, gz)
  96. gz.Close()
  97. return buf.Bytes()
  98. }
  99. `, funcname, funcname, funcname, funcname)
  100. }
  101. // input -> gowriter -> output.
  102. func translate_nomemcpy_uncomp(input io.Reader, output io.Writer, pkgname, funcname string) {
  103. fmt.Fprintf(output, `package %s
  104. import (
  105. "reflect"
  106. "unsafe"
  107. )
  108. var _%s = "`, pkgname, funcname)
  109. io.Copy(&StringWriter{Writer: output}, input)
  110. fmt.Fprintf(output, `"
  111. // %s returns raw file data.
  112. //
  113. // WARNING: The returned byte slice is READ-ONLY.
  114. // Attempting to alter the slice contents will yield a runtime panic.
  115. func %s() []byte {
  116. var empty [0]byte
  117. sx := (*reflect.StringHeader)(unsafe.Pointer(&_%s))
  118. b := empty[:]
  119. bx := (*reflect.SliceHeader)(unsafe.Pointer(&b))
  120. bx.Data = sx.Data
  121. bx.Len = len(_%s)
  122. bx.Cap = bx.Len
  123. return b
  124. }
  125. `, funcname, funcname, funcname, funcname)
  126. }
  127. // safeFuncname creates a safe function name from the input path.
  128. func SafeFuncname(in, prefix string) string {
  129. name := strings.Replace(in, prefix, "", 1)
  130. if len(name) == 0 {
  131. name = in
  132. }
  133. name = strings.ToLower(name)
  134. name = regFuncName.ReplaceAllString(name, "_")
  135. if unicode.IsDigit(rune(name[0])) {
  136. // Identifier can't start with a digit.
  137. name = "_" + name
  138. }
  139. // Get rid of "__" instances for niceness.
  140. for strings.Index(name, "__") > -1 {
  141. name = strings.Replace(name, "__", "_", -1)
  142. }
  143. // Leading underscore is silly.
  144. if name[0] == '_' {
  145. name = name[1:]
  146. }
  147. return name
  148. }