From 11c26e32114dabc6524ad9fb1f868440f5d3fff3 Mon Sep 17 00:00:00 2001
From: obscuren <geffobscura@gmail.com>
Date: Wed, 23 Apr 2014 11:50:17 +0200
Subject: Implemented ethereum package reader

---
 ethutil/package.go | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 123 insertions(+)
 create mode 100644 ethutil/package.go

diff --git a/ethutil/package.go b/ethutil/package.go
new file mode 100644
index 000000000..e5df989d2
--- /dev/null
+++ b/ethutil/package.go
@@ -0,0 +1,123 @@
+package ethutil
+
+import (
+	"archive/zip"
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"strings"
+)
+
+// Manifest object
+//
+// The manifest object holds all the relevant information supplied with the
+// the manifest specified in the package
+type Manifest struct {
+	Entry         string
+	Height, Width int
+}
+
+// External package
+//
+// External package contains the main html file and manifest
+type ExtPackage struct {
+	EntryHtml string
+	Manifest  *Manifest
+}
+
+// Read file
+//
+// Read a given compressed file and returns the read bytes.
+// Returns an error otherwise
+func ReadFile(f *zip.File) ([]byte, error) {
+	rc, err := f.Open()
+	if err != nil {
+		return nil, err
+	}
+	defer rc.Close()
+
+	content, err := ioutil.ReadAll(rc)
+	if err != nil {
+		return nil, err
+	}
+
+	return content, nil
+}
+
+// Reads manifest
+//
+// Reads and returns a manifest object. Returns error otherwise
+func ReadManifest(m []byte) (*Manifest, error) {
+	var manifest Manifest
+
+	dec := json.NewDecoder(strings.NewReader(string(m)))
+	if err := dec.Decode(&manifest); err == io.EOF {
+	} else if err != nil {
+		return nil, err
+	}
+
+	return &manifest, nil
+}
+
+// Find file in archive
+//
+// Returns the index of the given file name if it exists. -1 if file not found
+func FindFileInArchive(fn string, files []*zip.File) (index int) {
+	index = -1
+	// Find the manifest first
+	for i, f := range files {
+		if f.Name == fn {
+			index = i
+		}
+	}
+
+	return
+}
+
+// Open package
+//
+// Opens a prepared ethereum package
+// Reads the manifest file and determines file contents and returns and
+// the external package.
+func OpenPackage(fn string) (*ExtPackage, error) {
+	r, err := zip.OpenReader(fn)
+	if err != nil {
+		return nil, err
+	}
+	defer r.Close()
+
+	manifestIndex := FindFileInArchive("manifest.json", r.File)
+
+	if manifestIndex < 0 {
+		return nil, fmt.Errorf("No manifest file found in archive")
+	}
+
+	f, err := ReadFile(r.File[manifestIndex])
+	if err != nil {
+		return nil, err
+	}
+
+	manifest, err := ReadManifest(f)
+	if err != nil {
+		return nil, err
+	}
+
+	if manifest.Entry == "" {
+		return nil, fmt.Errorf("Entry file specified but appears to be empty: %s", manifest.Entry)
+	}
+
+	entryIndex := FindFileInArchive(manifest.Entry, r.File)
+	if entryIndex < 0 {
+		return nil, fmt.Errorf("Entry file not found: '%s'", manifest.Entry)
+	}
+
+	f, err = ReadFile(r.File[entryIndex])
+	if err != nil {
+		return nil, err
+	}
+
+	extPackage := &ExtPackage{string(f), manifest}
+
+	return extPackage, nil
+}
-- 
cgit v1.2.3