writer.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. package tools
  2. import (
  3. "fmt"
  4. "go-common/library/log"
  5. "os"
  6. "path/filepath"
  7. "time"
  8. )
  9. type zipSections struct {
  10. beforeSigningBlock []byte
  11. signingBlock []byte
  12. signingBlockOffset int64
  13. centraDir []byte
  14. centralDirOffset int64
  15. eocd []byte
  16. eocdOffset int64
  17. }
  18. type transform func(*zipSections) (*zipSections, error)
  19. func (z *zipSections) writeTo(output string, transform transform) (err error) {
  20. f, err := os.Create(output)
  21. if err != nil {
  22. return
  23. }
  24. defer f.Close()
  25. newZip, err := transform(z)
  26. if err != nil {
  27. return
  28. }
  29. for _, s := range [][]byte{
  30. newZip.beforeSigningBlock,
  31. newZip.signingBlock,
  32. newZip.centraDir,
  33. newZip.eocd} {
  34. _, err := f.Write(s)
  35. if err != nil {
  36. return err
  37. }
  38. }
  39. return
  40. }
  41. var _debug bool
  42. // GenerateChannelApk generate a specified channel apk
  43. func GenerateChannelApk(out string, channel string, extras map[string]string, input string, force bool, debug bool) (output string, err error) {
  44. _debug = debug
  45. if len(input) == 0 {
  46. err = fmt.Errorf("Error: no input file specified")
  47. log.Error("no input file specified, error(%v)", err)
  48. return
  49. }
  50. if _, err = os.Stat(input); os.IsNotExist(err) {
  51. return
  52. }
  53. if len(out) == 0 {
  54. out = filepath.Dir(input)
  55. } else {
  56. var fi os.FileInfo
  57. err = os.MkdirAll(out, 0755)
  58. if err != nil {
  59. log.Error("os.MkdirAll(%s) error(%v)", out, err)
  60. return
  61. }
  62. fi, err = os.Stat(out)
  63. println("error %v", err)
  64. if os.IsNotExist(err) || !fi.IsDir() {
  65. err = fmt.Errorf("Error: output %s is neither exist nor a dir", out)
  66. log.Error("output %s is neither exist nor a dir, error(%v)", out, err)
  67. return
  68. }
  69. }
  70. if channel == "" {
  71. err = fmt.Errorf("Error: no channel specified")
  72. log.Error("no channel specified, error(%v)", err)
  73. return
  74. }
  75. //TODO: add new option for generating new channel from channelled apk
  76. if c, _ := readChannelInfo(input); len(c.Channel) != 0 {
  77. err = fmt.Errorf("Error: file %s is registered a channel block %s", filepath.Base(input), c.String())
  78. log.Error("file %s is registered a channel block %s, error(%v)", filepath.Base(input), c.String(), err)
  79. return
  80. }
  81. var start time.Time
  82. if _debug {
  83. start = time.Now()
  84. }
  85. z, err := newZipSections(input)
  86. if err != nil {
  87. err = fmt.Errorf("Error occurred on parsing apk %s, %s", input, err)
  88. log.Error("Error occurred on parsing apk %s, error(%v)", input, err)
  89. return
  90. }
  91. name, ext := fileNameAndExt(input)
  92. output = filepath.Join(out, name+"-"+channel+ext)
  93. c := ChannelInfo{Channel: channel, Extras: extras}
  94. err = gen(c, z, output, force)
  95. if err != nil {
  96. err = fmt.Errorf("Error occurred on generating channel %s, %s", channel, err)
  97. log.Error("Error occurred on generating channel %s, error(%v)", input, err)
  98. return
  99. }
  100. if _debug {
  101. println("Consume", time.Since(start).String())
  102. } else {
  103. println("Done!")
  104. }
  105. return
  106. }
  107. func newZipSections(input string) (z zipSections, err error) {
  108. in, err := os.Open(input)
  109. if err != nil {
  110. return
  111. }
  112. defer in.Close()
  113. // read eocd
  114. eocd, eocdOffset, err := findEndOfCentralDirectoryRecord(in)
  115. if err != nil {
  116. return
  117. }
  118. centralDirOffset := getEocdCentralDirectoryOffset(eocd)
  119. centralDirSize := getEocdCentralDirectorySize(eocd)
  120. z.eocd = eocd
  121. z.eocdOffset = eocdOffset
  122. z.centralDirOffset = int64(centralDirOffset)
  123. // read signing block
  124. signingBlock, signingBlockOffset, err := findApkSigningBlock(in, centralDirOffset)
  125. if err != nil {
  126. return
  127. }
  128. z.signingBlock = signingBlock
  129. z.signingBlockOffset = signingBlockOffset
  130. // read bytes before signing block
  131. //TODO: waste too large memory
  132. if signingBlockOffset >= 64*1024*1024 {
  133. fmt.Print("Warning: maybe waste large memory on processing this apk! ")
  134. fmt.Println("Before APK Signing Block bytes size is", signingBlockOffset/1024/1024, "MB")
  135. }
  136. beforeSigningBlock := make([]byte, signingBlockOffset)
  137. n, err := in.ReadAt(beforeSigningBlock, 0)
  138. if err != nil {
  139. return
  140. }
  141. if int64(n) != signingBlockOffset {
  142. return z, fmt.Errorf("Read bytes count mismatched! Expect %d, but %d", signingBlockOffset, n)
  143. }
  144. z.beforeSigningBlock = beforeSigningBlock
  145. centralDir := make([]byte, centralDirSize)
  146. n, err = in.ReadAt(centralDir, int64(centralDirOffset))
  147. if uint32(n) != centralDirSize {
  148. return z, fmt.Errorf("Read bytes count mismatched! Expect %d, but %d", centralDirSize, n)
  149. }
  150. z.centraDir = centralDir
  151. if _debug {
  152. fmt.Printf("signingBlockOffset=%d, signingBlockLenth=%d\n"+
  153. "centralDirOffset=%d, centralDirSize=%d\n"+
  154. "eocdOffset=%d, eocdLenthe=%d\n",
  155. signingBlockOffset,
  156. len(signingBlock),
  157. centralDirOffset,
  158. centralDirSize,
  159. eocdOffset,
  160. len(eocd))
  161. }
  162. return
  163. }
  164. func gen(info ChannelInfo, sections zipSections, output string, force bool) (err error) {
  165. fi, err := os.Stat(output)
  166. if err != nil && !os.IsNotExist(err) {
  167. return err
  168. }
  169. if fi != nil {
  170. if !force {
  171. return fmt.Errorf("file already exists %s", output)
  172. }
  173. println("Force generating channel", info.Channel)
  174. }
  175. var s time.Time
  176. if _debug {
  177. s = time.Now()
  178. }
  179. err = sections.writeTo(output, newTransform(info))
  180. if _debug {
  181. fmt.Printf(" write %s consume %s", output, time.Since(s).String())
  182. fmt.Println()
  183. }
  184. return
  185. }
  186. func newTransform(info ChannelInfo) transform {
  187. return func(zip *zipSections) (*zipSections, error) {
  188. newBlock, diffSize, err := makeSigningBlockWithChannelInfo(info, zip.signingBlock)
  189. if err != nil {
  190. return nil, err
  191. }
  192. newzip := new(zipSections)
  193. newzip.beforeSigningBlock = zip.beforeSigningBlock
  194. newzip.signingBlock = newBlock
  195. newzip.signingBlockOffset = zip.signingBlockOffset
  196. newzip.centraDir = zip.centraDir
  197. newzip.centralDirOffset = zip.centralDirOffset
  198. newzip.eocdOffset = zip.eocdOffset
  199. newzip.eocd = makeEocd(zip.eocd, uint32(int64(diffSize)+zip.centralDirOffset))
  200. return newzip, nil
  201. }
  202. }