Code:
package main
import (
"encoding/binary"
"strings"
"math"
"path"
"fmt"
"os"
)
type Header struct {
Magic [4]byte
_ [4]byte
_ [4]byte
EOFOff uint32
EntryTableOff uint32
EntryTableSize uint32
FileSize uint32
EntryCount uint32
_ [80]byte
}
type Entry struct{
_ uint32
FileOff uint32
FileSize uint32
}
var orzFileName string
var orzFilePath string
func main() {
var header Header
//Check for correct command line usage.
if len(os.Args) < 2{
fmt.Printf("Usage: %s [inputfile.orz]\n", os.Args[0])
fmt.Println("Closing")
os.Exit(2)
}
orzFileName = os.Args[1]
orzFilePath = "unpacked\\"
f, err := os.Open(orzFileName)
if err != nil{
panic(err)
}
defer f.Close()
//Read sizeof(Header) into header
err = binary.Read(f, binary.LittleEndian, &header)
if err != nil {
panic(err)
}
//Seek EntryTableOff + 0x1000
//EntryTableOff + 0x0000 ~ 0x1000 are file attributes/permissions I think.
_, err = f.Seek(int64(header.EntryTableOff+0x1000), 0)
if err != nil {
panic(err)
}
//Read Info Entries
for i := 0; i < int(header.EntryCount); i++{
var entry Entry
//Read sizeof(Entry) into entry
err = binary.Read(f, binary.LittleEndian, &entry)
if err != nil {
panic(err)
}
//Read in filename
//probably a better way to do this, but im new to Go.
var entryfilename string
var entrynamelen int
tmp := make([]byte, 1)
tmp[0] = 255
for {
_, err = f.Read(tmp)
if err != nil{
panic(err)
}
entrynamelen++
//If end of string, break from loop
if tmp[0] == 0{
break
}
entryfilename += string(tmp[0])
}
//4 byte alignment padding after filename string
eb := int((math.Ceil(float64(entrynamelen) / 4.0) * 4.0)) - entrynamelen
_, err = f.Seek(int64(eb), 1)
if err != nil{
panic(err)
}
//make folders for extracted data
err = os.MkdirAll(orzFilePath + path.Dir(strings.Replace(entryfilename, "\\", "/", -1)), os.ModeDir)
if err != nil{
panic("Error creating folders!")
}
//Create file for entry
extractfile, err := os.Create(orzFilePath + entryfilename)
if err != nil{
panic(err)
}
//Read entry data into buffer
buf := make([]byte, entry.FileSize)
_, err = f.ReadAt(buf, int64(entry.FileOff))
if err != nil{
panic(err)
}
//Write entry data to file
_, err = extractfile.Write(buf)
if err != nil{
panic(err)
}
//Output filename and size
fmt.Printf("%v\t\t\t:%vkb\n", entryfilename, entry.FileSize / 1024.0)
}
}