Skip to content

Commit

Permalink
Modify binxml's ZipReader to read all the files in a ZIP
Browse files Browse the repository at this point in the history
  • Loading branch information
Vojtech Bocek committed Feb 15, 2016
1 parent bd5247d commit 24497f4
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 40 deletions.
18 changes: 16 additions & 2 deletions axml2xml/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,27 @@ func main() {
if input == "-" {
r = os.Stdin
} else if *isApk {
zr, err := binxml.OpenFileInZip(input, "AndroidManifest.xml")
zr, err := binxml.OpenZip(input)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
defer zr.Close()
r = zr

zrf := zr.File["AndroidManifest.xml"]
if zrf == nil {
fmt.Fprintln(os.Stderr, "Failed to find manifest")
os.Exit(1)
}

if err := zrf.Open(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
defer zrf.Close()

zrf.Next()
r = zrf
} else {
f, err := os.Open(input)
if err != nil {
Expand Down
108 changes: 70 additions & 38 deletions zipreader.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,39 @@ import (
"compress/flate"
)

type zipReaderFileEntry struct {
type zipReaderFileSubEntry struct {
offset int64
method uint16
}

type ZipReader struct {
type ZipReaderFile struct {
Name string

zipFile *os.File
internalReader io.ReadCloser
entries []zipReaderFileEntry

zipEntry *carelesszip.File

entries []zipReaderFileSubEntry
curEntry int
}

func (zr *ZipReader) Read(p []byte) (int, error) {
type ZipReader struct {
File map[string]*ZipReaderFile

zipFile *os.File
}

func (zr *ZipReaderFile) Open() error {
if zr.zipEntry != nil {
var err error
zr.internalReader, err = zr.zipEntry.Open()
return err
}
return nil
}

func (zr *ZipReaderFile) Read(p []byte) (int, error) {
if zr.internalReader == nil {
if zr.curEntry >= len(zr.entries) {
return 0, io.ErrUnexpectedEOF
Expand All @@ -44,7 +64,7 @@ func (zr *ZipReader) Read(p []byte) (int, error) {
return zr.internalReader.Read(p)
}

func (zr *ZipReader) Next() bool {
func (zr *ZipReaderFile) Next() bool {
if len(zr.entries) == 0 && zr.internalReader != nil {
zr.curEntry++
return zr.curEntry == 1
Expand All @@ -62,22 +82,35 @@ func (zr *ZipReader) Next() bool {
return true
}

func (zr *ZipReaderFile) Close() error {
if zr.internalReader != nil {
if zr.internalReader != zr.zipFile {
zr.internalReader.Close()
}
zr.internalReader = nil

// prevent reopen
zr.curEntry = len(zr.entries)
}
return nil
}

func (zr *ZipReader) Close() error {
if zr.zipFile == nil {
return nil
}

if zr.internalReader != nil && zr.internalReader != zr.zipFile {
zr.internalReader.Close()
for _, zf := range zr.File {
zf.Close()
}

err := zr.zipFile.Close()
zr.zipFile = nil
return err
}

func OpenFileInZip(zippath, filename string) (zr *ZipReader, err error) {
f, err := os.Open(zippath)
func OpenZip(path string) (zr *ZipReader, err error) {
f, err := os.Open(path)
if err != nil {
return
}
Expand All @@ -88,33 +121,33 @@ func OpenFileInZip(zippath, filename string) (zr *ZipReader, err error) {
}
}()

zr = &ZipReader{
File: make(map[string]*ZipReaderFile),
zipFile: f,
}

var zipinfo *carelesszip.Reader
zipinfo, err = tryReadZip(f)
if err == nil {
for _, zf := range zipinfo.File {
if filepath.Clean(zf.Name) == filename {
var rc io.ReadCloser
rc, err = zf.Open()
if err == nil {
zr = &ZipReader { zipFile: f, internalReader: rc }
return
cl := filepath.Clean(zf.Name)
if zr.File[cl] == nil {
zr.File[cl] = &ZipReaderFile{
Name: cl,
zipFile: f,
zipEntry: zf,
}
}
}
return
}

f.Seek(0, 0)

var off int64
for {
off, err = findNextFileHeader(f)
if off == -1 {
if zr != nil && len(zr.entries) != 0 {
return
}
err = fmt.Errorf("Unable to find file %s!", filename)
}
if err != nil {
if off == -1 || err != nil {
return
}

Expand All @@ -130,11 +163,6 @@ func OpenFileInZip(zippath, filename string) (zr *ZipReader, err error) {
return
}

if int(nameLen) < len(filename) || int(nameLen) > len(filename)*2 {
f.Seek(off+4, 0)
continue
}

if err = binary.Read(f, binary.LittleEndian, &extraLen); err != nil {
return
}
Expand All @@ -144,20 +172,24 @@ func OpenFileInZip(zippath, filename string) (zr *ZipReader, err error) {
return
}

if filepath.Clean(string(buf)) == filename {
fileOffset := off+30+int64(nameLen)+int64(extraLen)
switch method {
case zip.Deflate, zip.Store:
if zr == nil {
zr = &ZipReader { zipFile: f, curEntry: -1 }
}
zr.entries = append(zr.entries, zipReaderFileEntry{
offset: fileOffset,
method: method,
})
fileName := filepath.Clean(string(buf))
fileOffset := off+30+int64(nameLen)+int64(extraLen)

zrf := zr.File[fileName]
if zrf == nil {
zrf = &ZipReaderFile{
Name: fileName,
zipFile: f,
curEntry: -1,
}
zr.File[fileName] = zrf
}

zrf.entries = append(zrf.entries, zipReaderFileSubEntry{
offset: fileOffset,
method: method,
})

f.Seek(off+4, 0)
}

Expand Down

0 comments on commit 24497f4

Please sign in to comment.