Move LSF and LSB decoding into their own packages
Adapt format.go from the image package Change the only package level state variable to a function parameter Load entire files into memory for performance
This commit is contained in:
parent
e8c7e22293
commit
2f87df40d6
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Norbyte
|
||||
Copyright (c) 2020 lordwelch
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -385,9 +385,7 @@ func (na *NodeAttribute) FromString(str string) error {
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
)
|
||||
var err error
|
||||
|
||||
switch na.Type {
|
||||
case DTNone:
|
||||
|
139
binutils.go
139
binutils.go
@ -406,3 +406,142 @@ func (l *LimitedReadSeeker) Seek(offset int64, whence int) (int64, error) {
|
||||
return -1, io.ErrNoProgress
|
||||
}
|
||||
}
|
||||
|
||||
func ReadTranslatedString(r io.ReadSeeker, version FileVersion, engineVersion uint32) (TranslatedString, error) {
|
||||
var (
|
||||
str TranslatedString
|
||||
err error
|
||||
)
|
||||
|
||||
if version >= VerBG3 || engineVersion == 0x4000001d {
|
||||
// logger.Println("decoding bg3 data")
|
||||
var version uint16
|
||||
err = binary.Read(r, binary.LittleEndian, &version)
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
str.Version = version
|
||||
err = binary.Read(r, binary.LittleEndian, &version)
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
if version == 0 {
|
||||
str.Value, err = ReadCString(r, int(str.Version))
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
str.Version = 0
|
||||
} else {
|
||||
_, err = r.Seek(-2, io.SeekCurrent)
|
||||
}
|
||||
} else {
|
||||
str.Version = 0
|
||||
|
||||
var (
|
||||
vlength int32
|
||||
v []byte
|
||||
// n int
|
||||
)
|
||||
|
||||
err = binary.Read(r, binary.LittleEndian, &vlength)
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
v = make([]byte, vlength)
|
||||
_, err = r.Read(v)
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
str.Value = string(v)
|
||||
}
|
||||
|
||||
var handleLength int32
|
||||
err = binary.Read(r, binary.LittleEndian, &handleLength)
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
str.Handle, err = ReadCString(r, int(handleLength))
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
// logger.Printf("handle %s; %v", str.Handle, err)
|
||||
return str, nil
|
||||
}
|
||||
|
||||
func ReadTranslatedFSString(r io.ReadSeeker, version FileVersion) (TranslatedFSString, error) {
|
||||
var (
|
||||
str = TranslatedFSString{}
|
||||
err error
|
||||
)
|
||||
|
||||
if version >= VerBG3 {
|
||||
var version uint16
|
||||
err = binary.Read(r, binary.LittleEndian, &version)
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
str.Version = version
|
||||
} else {
|
||||
str.Version = 0
|
||||
|
||||
var length int32
|
||||
|
||||
err = binary.Read(r, binary.LittleEndian, &length)
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
str.Value, err = ReadCString(r, int(length))
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
}
|
||||
|
||||
var handleLength int32
|
||||
err = binary.Read(r, binary.LittleEndian, &handleLength)
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
str.Handle, err = ReadCString(r, int(handleLength))
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
|
||||
var arguments int32
|
||||
err = binary.Read(r, binary.LittleEndian, &arguments)
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
str.Arguments = make([]TranslatedFSStringArgument, 0, arguments)
|
||||
for i := 0; i < int(arguments); i++ {
|
||||
arg := TranslatedFSStringArgument{}
|
||||
|
||||
var argKeyLength int32
|
||||
err = binary.Read(r, binary.LittleEndian, &argKeyLength)
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
arg.Key, err = ReadCString(r, int(argKeyLength))
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
|
||||
arg.String, err = ReadTranslatedFSString(r, version)
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
|
||||
var argValueLength int32
|
||||
err = binary.Read(r, binary.LittleEndian, &argValueLength)
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
arg.Value, err = ReadCString(r, int(argValueLength))
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
|
||||
str.Arguments = append(str.Arguments, arg)
|
||||
}
|
||||
|
||||
return str, nil
|
||||
}
|
||||
|
@ -1,16 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"git.narnian.us/lordwelch/lsgo"
|
||||
_ "git.narnian.us/lordwelch/lsgo/lsb"
|
||||
_ "git.narnian.us/lordwelch/lsgo/lsf"
|
||||
|
||||
"github.com/go-kit/kit/log"
|
||||
"github.com/kr/pretty"
|
||||
@ -75,6 +80,7 @@ func main() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func openLSF(filename string) error {
|
||||
var (
|
||||
l *lsgo.Resource
|
||||
@ -118,17 +124,65 @@ func openLSF(filename string) error {
|
||||
|
||||
func readLSF(filename string) (*lsgo.Resource, error) {
|
||||
var (
|
||||
l lsgo.Resource
|
||||
f *os.File
|
||||
err error
|
||||
l lsgo.Resource
|
||||
r io.ReadSeeker
|
||||
file *os.File
|
||||
fi os.FileInfo
|
||||
err error
|
||||
)
|
||||
f, err = os.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
switch filepath.Ext(filename) {
|
||||
|
||||
l, err = lsgo.ReadLSF(f)
|
||||
case ".lsf", ".lsb":
|
||||
var b []byte
|
||||
fi, err = os.Stat(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Arbitrary size, no lsf file should reach 100 MB (I haven't found one over 90 KB) and if you don't have 100 MB of ram free you shouldn't be using this
|
||||
if fi.Size() <= 100*1024*1024 {
|
||||
b, err = ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r = bytes.NewReader(b)
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
b := make([]byte, 4)
|
||||
file, err = os.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
_, err = file.Read(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !lsgo.SupportedFormat(b) {
|
||||
return nil, lsgo.ErrFormat
|
||||
}
|
||||
|
||||
_, err = file.Seek(0, io.SeekStart)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fi, _ = os.Stat(filename)
|
||||
|
||||
// I have never seen a valid "ls*" file over 90 KB
|
||||
if fi.Size() < 1*1024*1024 {
|
||||
b, err = ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r = bytes.NewReader(b)
|
||||
} else {
|
||||
r = file
|
||||
}
|
||||
}
|
||||
|
||||
l, _, err = lsgo.Decode(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -159,9 +213,7 @@ func marshalXML(l *lsgo.Resource) (string, error) {
|
||||
}
|
||||
|
||||
func writeXML(f io.StringWriter, n string) error {
|
||||
var (
|
||||
err error
|
||||
)
|
||||
var err error
|
||||
_, err = f.WriteString(strings.ToLower(xml.Header))
|
||||
if err != nil {
|
||||
return err
|
||||
|
14
const.go
14
const.go
@ -1,6 +1,9 @@
|
||||
package lsgo
|
||||
|
||||
import "errors"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type FileVersion uint32
|
||||
|
||||
@ -43,3 +46,12 @@ var (
|
||||
ErrInvalidNameKey = errors.New("invalid name key")
|
||||
ErrKeyDoesNotMatch = errors.New("key for this node does not match")
|
||||
)
|
||||
|
||||
type HeaderError struct {
|
||||
Expected []byte
|
||||
Got []byte
|
||||
}
|
||||
|
||||
func (he HeaderError) Error() string {
|
||||
return fmt.Sprintf("Invalid LSF signature; expected %v, got %v", he.Expected, he.Got)
|
||||
}
|
||||
|
92
format.go
Normal file
92
format.go
Normal file
@ -0,0 +1,92 @@
|
||||
// Adapted from the image package
|
||||
package lsgo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// ErrFormat indicates that decoding encountered an unknown format.
|
||||
var ErrFormat = errors.New("lsgo: unknown format")
|
||||
|
||||
// A format holds an image format's name, magic header and how to decode it.
|
||||
type format struct {
|
||||
name, magic string
|
||||
decode func(io.ReadSeeker) (Resource, error)
|
||||
}
|
||||
|
||||
// Formats is the list of registered formats.
|
||||
var (
|
||||
formatsMu sync.Mutex
|
||||
atomicFormats atomic.Value
|
||||
)
|
||||
|
||||
// RegisterFormat registers an image format for use by Decode.
|
||||
// Name is the name of the format, like "jpeg" or "png".
|
||||
// Magic is the magic prefix that identifies the format's encoding. The magic
|
||||
// string can contain "?" wildcards that each match any one byte.
|
||||
// Decode is the function that decodes the encoded image.
|
||||
// DecodeConfig is the function that decodes just its configuration.
|
||||
func RegisterFormat(name, magic string, decode func(io.ReadSeeker) (Resource, error)) {
|
||||
formatsMu.Lock()
|
||||
formats, _ := atomicFormats.Load().([]format)
|
||||
atomicFormats.Store(append(formats, format{name, magic, decode}))
|
||||
formatsMu.Unlock()
|
||||
}
|
||||
|
||||
// Match reports whether magic matches b. Magic may contain "?" wildcards.
|
||||
func match(magic string, b []byte) bool {
|
||||
if len(magic) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i, c := range b {
|
||||
if magic[i] != c && magic[i] != '?' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Sniff determines the format of r's data.
|
||||
func sniff(r io.ReadSeeker) format {
|
||||
var (
|
||||
b []byte = make([]byte, 4)
|
||||
err error
|
||||
)
|
||||
formats, _ := atomicFormats.Load().([]format)
|
||||
for _, f := range formats {
|
||||
if len(b) < len(f.magic) {
|
||||
fmt.Fprintln(os.Stderr, f.magic)
|
||||
b = make([]byte, len(f.magic))
|
||||
}
|
||||
_, err = r.Read(b)
|
||||
r.Seek(0, io.SeekStart)
|
||||
if err == nil && match(f.magic, b) {
|
||||
return f
|
||||
}
|
||||
}
|
||||
return format{}
|
||||
}
|
||||
|
||||
func Decode(r io.ReadSeeker) (Resource, string, error) {
|
||||
f := sniff(r)
|
||||
if f.decode == nil {
|
||||
return Resource{}, "", ErrFormat
|
||||
}
|
||||
m, err := f.decode(r)
|
||||
return m, f.name, err
|
||||
}
|
||||
|
||||
func SupportedFormat(signature []byte) bool {
|
||||
formats, _ := atomicFormats.Load().([]format)
|
||||
for _, f := range formats {
|
||||
if match(f.magic, signature) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
8
go.mod
8
go.mod
@ -2,12 +2,12 @@ module git.narnian.us/lordwelch/lsgo
|
||||
|
||||
go 1.15
|
||||
|
||||
replace github.com/pierrec/lz4/v4 v4.1.1 => ./lz4
|
||||
replace github.com/pierrec/lz4/v4 v4.1.3 => ./lz4
|
||||
|
||||
require (
|
||||
github.com/go-kit/kit v0.10.0
|
||||
github.com/google/uuid v1.1.2
|
||||
github.com/google/uuid v1.1.4
|
||||
github.com/kr/pretty v0.2.1
|
||||
github.com/pierrec/lz4/v4 v4.1.1
|
||||
gonum.org/v1/gonum v0.8.1
|
||||
github.com/pierrec/lz4/v4 v4.1.3
|
||||
gonum.org/v1/gonum v0.8.2
|
||||
)
|
||||
|
8
go.sum
8
go.sum
@ -86,8 +86,8 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.4 h1:0ecGp3skIrHWPNGPJDaBIghfA6Sp7Ruo2Io8eLKzWm0=
|
||||
github.com/google/uuid v1.1.4/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
@ -329,8 +329,8 @@ golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapK
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
||||
gonum.org/v1/gonum v0.8.1 h1:wGtP3yGpc5mCLOLeTeBdjeui9oZSz5De0eOjMLC/QuQ=
|
||||
gonum.org/v1/gonum v0.8.1/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
|
||||
gonum.org/v1/gonum v0.8.2 h1:CCXrcPKiGGotvnN6jfUsKk4rRqm7q09/YbKb5xCEvtM=
|
||||
gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
|
||||
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc=
|
||||
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
|
||||
gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
|
||||
|
@ -1,4 +1,4 @@
|
||||
package lsgo
|
||||
package lsb
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
@ -7,6 +7,8 @@ import (
|
||||
"io"
|
||||
"sort"
|
||||
|
||||
"git.narnian.us/lordwelch/lsgo"
|
||||
|
||||
"github.com/go-kit/kit/log"
|
||||
)
|
||||
|
||||
@ -15,7 +17,7 @@ type LSBHeader struct {
|
||||
Size uint32
|
||||
Endianness uint32
|
||||
Unknown uint32
|
||||
Version LSMetadata
|
||||
Version lsgo.LSMetadata
|
||||
}
|
||||
|
||||
func (lsbh *LSBHeader) Read(r io.ReadSeeker) error {
|
||||
@ -25,7 +27,7 @@ func (lsbh *LSBHeader) Read(r io.ReadSeeker) error {
|
||||
n int
|
||||
err error
|
||||
)
|
||||
l = log.With(Logger, "component", "LS converter", "file type", "lsb", "part", "header")
|
||||
l = log.With(lsgo.Logger, "component", "LS converter", "file type", "lsb", "part", "header")
|
||||
pos, err = r.Seek(0, io.SeekCurrent)
|
||||
|
||||
n, err = r.Read(lsbh.Signature[:])
|
||||
@ -102,27 +104,27 @@ func (lsbh *LSBHeader) Read(r io.ReadSeeker) error {
|
||||
|
||||
type IdentifierDictionary map[int]string
|
||||
|
||||
func ReadLSB(r io.ReadSeeker) (Resource, error) {
|
||||
func ReadLSB(r io.ReadSeeker) (lsgo.Resource, error) {
|
||||
var (
|
||||
hdr = &LSBHeader{}
|
||||
h = [4]byte{0x00, 0x00, 0x00, 0x40}
|
||||
err error
|
||||
d IdentifierDictionary
|
||||
res Resource
|
||||
res lsgo.Resource
|
||||
|
||||
l log.Logger
|
||||
pos int64
|
||||
)
|
||||
l = log.With(Logger, "component", "LS converter", "file type", "lsb", "part", "file")
|
||||
l = log.With(lsgo.Logger, "component", "LS converter", "file type", "lsb", "part", "file")
|
||||
pos, err = r.Seek(0, io.SeekCurrent)
|
||||
l.Log("member", "header", "start position", pos)
|
||||
|
||||
err = hdr.Read(r)
|
||||
if err != nil {
|
||||
return Resource{}, err
|
||||
return lsgo.Resource{}, err
|
||||
}
|
||||
if !(hdr.Signature == [4]byte{'L', 'S', 'F', 'M'} || hdr.Signature == h) {
|
||||
return Resource{}, HeaderError{
|
||||
return lsgo.Resource{}, lsgo.HeaderError{
|
||||
Expected: []byte("LSFM"),
|
||||
Got: hdr.Signature[:],
|
||||
}
|
||||
@ -132,13 +134,13 @@ func ReadLSB(r io.ReadSeeker) (Resource, error) {
|
||||
l.Log("member", "string dictionary", "start position", pos)
|
||||
d, err = ReadLSBDictionary(r, binary.LittleEndian)
|
||||
if err != nil {
|
||||
return Resource{}, err
|
||||
return lsgo.Resource{}, err
|
||||
}
|
||||
|
||||
pos, err = r.Seek(0, io.SeekCurrent)
|
||||
l.Log("member", "Regions", "start position", pos)
|
||||
|
||||
res, err = ReadLSBRegions(r, d, binary.LittleEndian, FileVersion(hdr.Version.Major))
|
||||
res, err = ReadLSBRegions(r, d, binary.LittleEndian, lsgo.FileVersion(hdr.Version.Major))
|
||||
res.Metadata = hdr.Version
|
||||
return res, err
|
||||
}
|
||||
@ -153,7 +155,7 @@ func ReadLSBDictionary(r io.ReadSeeker, endianness binary.ByteOrder) (Identifier
|
||||
pos int64
|
||||
n int
|
||||
)
|
||||
l = log.With(Logger, "component", "LS converter", "file type", "lsb", "part", "dictionary")
|
||||
l = log.With(lsgo.Logger, "component", "LS converter", "file type", "lsb", "part", "dictionary")
|
||||
pos, err = r.Seek(0, io.SeekCurrent)
|
||||
|
||||
err = binary.Read(r, endianness, &length)
|
||||
@ -179,7 +181,7 @@ func ReadLSBDictionary(r io.ReadSeeker, endianness binary.ByteOrder) (Identifier
|
||||
l.Log("member", "stringLength", "read", n, "start position", pos, "value", stringLength)
|
||||
pos += int64(n)
|
||||
|
||||
str, err = ReadCString(r, int(stringLength))
|
||||
str, err = lsgo.ReadCString(r, int(stringLength))
|
||||
n += int(stringLength)
|
||||
if err != nil {
|
||||
return dict, err
|
||||
@ -199,7 +201,7 @@ func ReadLSBDictionary(r io.ReadSeeker, endianness binary.ByteOrder) (Identifier
|
||||
return dict, nil
|
||||
}
|
||||
|
||||
func ReadLSBRegions(r io.ReadSeeker, d IdentifierDictionary, endianness binary.ByteOrder, version FileVersion) (Resource, error) {
|
||||
func ReadLSBRegions(r io.ReadSeeker, d IdentifierDictionary, endianness binary.ByteOrder, version lsgo.FileVersion) (lsgo.Resource, error) {
|
||||
var (
|
||||
regions []struct {
|
||||
name string
|
||||
@ -212,13 +214,13 @@ func ReadLSBRegions(r io.ReadSeeker, d IdentifierDictionary, endianness binary.B
|
||||
pos int64
|
||||
n int
|
||||
)
|
||||
l = log.With(Logger, "component", "LS converter", "file type", "lsb", "part", "region")
|
||||
l = log.With(lsgo.Logger, "component", "LS converter", "file type", "lsb", "part", "region")
|
||||
pos, err = r.Seek(0, io.SeekCurrent)
|
||||
|
||||
err = binary.Read(r, endianness, ®ionCount)
|
||||
n = 4
|
||||
if err != nil {
|
||||
return Resource{}, err
|
||||
return lsgo.Resource{}, err
|
||||
}
|
||||
l.Log("member", "regionCount", "read", n, "start position", pos, "value", regionCount)
|
||||
pos += int64(n)
|
||||
@ -235,17 +237,17 @@ func ReadLSBRegions(r io.ReadSeeker, d IdentifierDictionary, endianness binary.B
|
||||
err = binary.Read(r, endianness, &key)
|
||||
n = 4
|
||||
if err != nil {
|
||||
return Resource{}, err
|
||||
return lsgo.Resource{}, err
|
||||
}
|
||||
l.Log("member", "key", "read", n, "start position", pos, "value", d[int(key)], "key", key)
|
||||
pos += int64(n)
|
||||
if regions[i].name, ok = d[int(key)]; !ok {
|
||||
return Resource{}, ErrInvalidNameKey
|
||||
return lsgo.Resource{}, lsgo.ErrInvalidNameKey
|
||||
}
|
||||
err = binary.Read(r, endianness, ®ions[i].offset)
|
||||
n = 4
|
||||
if err != nil {
|
||||
return Resource{}, err
|
||||
return lsgo.Resource{}, err
|
||||
}
|
||||
l.Log("member", "offset", "read", n, "start position", pos, "value", regions[i].offset)
|
||||
pos += int64(n)
|
||||
@ -253,11 +255,11 @@ func ReadLSBRegions(r io.ReadSeeker, d IdentifierDictionary, endianness binary.B
|
||||
sort.Slice(regions, func(i, j int) bool {
|
||||
return regions[i].offset < regions[j].offset
|
||||
})
|
||||
res := Resource{
|
||||
Regions: make([]*Node, 0, regionCount),
|
||||
res := lsgo.Resource{
|
||||
Regions: make([]*lsgo.Node, 0, regionCount),
|
||||
}
|
||||
for _, re := range regions {
|
||||
var node *Node
|
||||
var node *lsgo.Node
|
||||
node, err = readLSBNode(r, d, endianness, version, re.offset)
|
||||
if err != nil {
|
||||
return res, err
|
||||
@ -268,12 +270,12 @@ func ReadLSBRegions(r io.ReadSeeker, d IdentifierDictionary, endianness binary.B
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func readLSBNode(r io.ReadSeeker, d IdentifierDictionary, endianness binary.ByteOrder, version FileVersion, offset uint32) (*Node, error) {
|
||||
func readLSBNode(r io.ReadSeeker, d IdentifierDictionary, endianness binary.ByteOrder, version lsgo.FileVersion, offset uint32) (*lsgo.Node, error) {
|
||||
var (
|
||||
key uint32
|
||||
attrCount uint32
|
||||
childCount uint32
|
||||
node = new(Node)
|
||||
node = new(lsgo.Node)
|
||||
err error
|
||||
ok bool
|
||||
|
||||
@ -281,7 +283,7 @@ func readLSBNode(r io.ReadSeeker, d IdentifierDictionary, endianness binary.Byte
|
||||
pos int64
|
||||
n int
|
||||
)
|
||||
l = log.With(Logger, "component", "LS converter", "file type", "lsb", "part", "node")
|
||||
l = log.With(lsgo.Logger, "component", "LS converter", "file type", "lsb", "part", "node")
|
||||
pos, err = r.Seek(0, io.SeekCurrent)
|
||||
|
||||
if pos != int64(offset) && offset != 0 {
|
||||
@ -315,7 +317,7 @@ func readLSBNode(r io.ReadSeeker, d IdentifierDictionary, endianness binary.Byte
|
||||
}
|
||||
l.Log("member", "childCount", "read", n, "start position", pos, "value", childCount)
|
||||
|
||||
node.Attributes = make([]NodeAttribute, int(attrCount))
|
||||
node.Attributes = make([]lsgo.NodeAttribute, int(attrCount))
|
||||
|
||||
for i := range node.Attributes {
|
||||
node.Attributes[i], err = readLSBAttribute(r, d, endianness, version)
|
||||
@ -324,7 +326,7 @@ func readLSBNode(r io.ReadSeeker, d IdentifierDictionary, endianness binary.Byte
|
||||
}
|
||||
}
|
||||
|
||||
node.Children = make([]*Node, int(childCount))
|
||||
node.Children = make([]*lsgo.Node, int(childCount))
|
||||
for i := range node.Children {
|
||||
node.Children[i], err = readLSBNode(r, d, endianness, version, 0)
|
||||
if err != nil {
|
||||
@ -334,12 +336,12 @@ func readLSBNode(r io.ReadSeeker, d IdentifierDictionary, endianness binary.Byte
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func readLSBAttribute(r io.ReadSeeker, d IdentifierDictionary, endianness binary.ByteOrder, version FileVersion) (NodeAttribute, error) {
|
||||
func readLSBAttribute(r io.ReadSeeker, d IdentifierDictionary, endianness binary.ByteOrder, version lsgo.FileVersion) (lsgo.NodeAttribute, error) {
|
||||
var (
|
||||
key uint32
|
||||
name string
|
||||
attrType uint32
|
||||
attr NodeAttribute
|
||||
attr lsgo.NodeAttribute
|
||||
err error
|
||||
ok bool
|
||||
)
|
||||
@ -348,21 +350,21 @@ func readLSBAttribute(r io.ReadSeeker, d IdentifierDictionary, endianness binary
|
||||
return attr, err
|
||||
}
|
||||
if name, ok = d[int(key)]; !ok {
|
||||
return attr, ErrInvalidNameKey
|
||||
return attr, lsgo.ErrInvalidNameKey
|
||||
}
|
||||
err = binary.Read(r, endianness, &attrType)
|
||||
if err != nil {
|
||||
return attr, err
|
||||
}
|
||||
return ReadLSBAttr(r, name, DataType(attrType), endianness, version)
|
||||
return ReadLSBAttr(r, name, lsgo.DataType(attrType), endianness, version)
|
||||
}
|
||||
|
||||
func ReadLSBAttr(r io.ReadSeeker, name string, dt DataType, endianness binary.ByteOrder, version FileVersion) (NodeAttribute, error) {
|
||||
func ReadLSBAttr(r io.ReadSeeker, name string, dt lsgo.DataType, endianness binary.ByteOrder, version lsgo.FileVersion) (lsgo.NodeAttribute, error) {
|
||||
// LSF and LSB serialize the buffer types differently, so specialized
|
||||
// code is added to the LSB and LSf serializers, and the common code is
|
||||
// available in BinUtils.ReadAttribute()
|
||||
var (
|
||||
attr = NodeAttribute{
|
||||
attr = lsgo.NodeAttribute{
|
||||
Type: dt,
|
||||
Name: name,
|
||||
}
|
||||
@ -372,38 +374,38 @@ func ReadLSBAttr(r io.ReadSeeker, name string, dt DataType, endianness binary.By
|
||||
l log.Logger
|
||||
pos int64
|
||||
)
|
||||
l = log.With(Logger, "component", "LS converter", "file type", "lsb", "part", "attribute")
|
||||
l = log.With(lsgo.Logger, "component", "LS converter", "file type", "lsb", "part", "attribute")
|
||||
pos, err = r.Seek(0, io.SeekCurrent)
|
||||
|
||||
switch dt {
|
||||
case DTString, DTPath, DTFixedString, DTLSString: //, DTLSWString:
|
||||
case lsgo.DTString, lsgo.DTPath, lsgo.DTFixedString, lsgo.DTLSString: //, DTLSWString:
|
||||
var v string
|
||||
err = binary.Read(r, endianness, &length)
|
||||
if err != nil {
|
||||
return attr, err
|
||||
}
|
||||
v, err = ReadCString(r, int(length))
|
||||
v, err = lsgo.ReadCString(r, int(length))
|
||||
attr.Value = v
|
||||
|
||||
l.Log("member", name, "read", length, "start position", pos, "value", attr.Value)
|
||||
|
||||
return attr, err
|
||||
|
||||
case DTWString:
|
||||
case lsgo.DTWString:
|
||||
panic("Not implemented")
|
||||
|
||||
case DTTranslatedString:
|
||||
var v TranslatedString
|
||||
v, err = ReadTranslatedString(r, version, 0)
|
||||
case lsgo.DTTranslatedString:
|
||||
var v lsgo.TranslatedString
|
||||
v, err = lsgo.ReadTranslatedString(r, version, 0)
|
||||
attr.Value = v
|
||||
|
||||
l.Log("member", name, "read", length, "start position", pos, "value", attr.Value)
|
||||
|
||||
return attr, err
|
||||
|
||||
case DTTranslatedFSString:
|
||||
case lsgo.DTTranslatedFSString:
|
||||
panic("Not implemented")
|
||||
var v TranslatedFSString
|
||||
var v lsgo.TranslatedFSString
|
||||
// v, err = ReadTranslatedFSString(r, Version)
|
||||
attr.Value = v
|
||||
|
||||
@ -411,7 +413,7 @@ func ReadLSBAttr(r io.ReadSeeker, name string, dt DataType, endianness binary.By
|
||||
|
||||
return attr, err
|
||||
|
||||
case DTScratchBuffer:
|
||||
case lsgo.DTScratchBuffer:
|
||||
panic("Not implemented")
|
||||
|
||||
v := make([]byte, length)
|
||||
@ -423,6 +425,11 @@ func ReadLSBAttr(r io.ReadSeeker, name string, dt DataType, endianness binary.By
|
||||
return attr, err
|
||||
|
||||
default:
|
||||
return ReadAttribute(r, name, dt, uint(length), l)
|
||||
return lsgo.ReadAttribute(r, name, dt, uint(length), l)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
lsgo.RegisterFormat("lsb", "LSFM", ReadLSB)
|
||||
lsgo.RegisterFormat("lsb", "\x00\x00\x00\x40", ReadLSB)
|
||||
}
|
@ -1,61 +1,24 @@
|
||||
package lsgo
|
||||
package lsf
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"git.narnian.us/lordwelch/lsgo"
|
||||
|
||||
"github.com/go-kit/kit/log"
|
||||
)
|
||||
|
||||
var (
|
||||
LSFSignature = [4]byte{0x4C, 0x53, 0x4F, 0x46}
|
||||
Logger log.Logger = log.NewNopLogger()
|
||||
)
|
||||
|
||||
// NewFilter allows filtering of l
|
||||
func NewFilter(f map[string][]string, l log.Logger) log.Logger {
|
||||
return filter{
|
||||
filter: f,
|
||||
next: l,
|
||||
}
|
||||
}
|
||||
|
||||
type filter struct {
|
||||
next log.Logger
|
||||
filter map[string][]string
|
||||
}
|
||||
|
||||
func (f filter) Log(keyvals ...interface{}) error {
|
||||
var allowed = true // allow everything
|
||||
for i := 0; i < len(keyvals)-1; i += 2 {
|
||||
if v, ok := keyvals[i].(string); ok { // key
|
||||
if fil, ok := f.filter[v]; ok { // key has a filter
|
||||
if v, ok = keyvals[i+1].(string); ok { // value is a string
|
||||
allowed = false // this key has a filter deny everything except what the filter allows
|
||||
for _, fi := range fil {
|
||||
if strings.Contains(v, fi) {
|
||||
allowed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if allowed {
|
||||
return f.next.Log(keyvals...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
var LSFSignature = [4]byte{0x4C, 0x53, 0x4F, 0x46}
|
||||
|
||||
type LSFHeader struct {
|
||||
// LSOF file signature
|
||||
Signature [4]byte
|
||||
|
||||
// Version of the LSOF file D:OS EE is version 1/2, D:OS 2 is version 3
|
||||
Version FileVersion
|
||||
Version lsgo.FileVersion
|
||||
|
||||
// Possibly version number? (major, minor, rev, build)
|
||||
EngineVersion uint32
|
||||
@ -103,7 +66,7 @@ func (lsfh *LSFHeader) Read(r io.ReadSeeker) error {
|
||||
n int
|
||||
err error
|
||||
)
|
||||
l = log.With(Logger, "component", "LS converter", "file type", "lsf", "part", "header")
|
||||
l = log.With(lsgo.Logger, "component", "LS converter", "file type", "lsf", "part", "header")
|
||||
pos, err = r.Seek(0, io.SeekCurrent)
|
||||
n, err = r.Read(lsfh.Signature[:])
|
||||
if err != nil {
|
||||
@ -233,7 +196,7 @@ func (lsfh *LSFHeader) Read(r io.ReadSeeker) error {
|
||||
}
|
||||
|
||||
func (lsfh LSFHeader) IsCompressed() bool {
|
||||
return CompressionFlagsToMethod(lsfh.CompressionFlags) != CMNone && CompressionFlagsToMethod(lsfh.CompressionFlags) != CMInvalid
|
||||
return lsgo.CompressionFlagsToMethod(lsfh.CompressionFlags) != lsgo.CMNone && lsgo.CompressionFlagsToMethod(lsfh.CompressionFlags) != lsgo.CMInvalid
|
||||
}
|
||||
|
||||
type NodeEntry struct {
|
||||
@ -274,7 +237,7 @@ func (ne *NodeEntry) readShort(r io.ReadSeeker) error {
|
||||
err error
|
||||
n int
|
||||
)
|
||||
l = log.With(Logger, "component", "LS converter", "file type", "lsf", "part", "short node")
|
||||
l = log.With(lsgo.Logger, "component", "LS converter", "file type", "lsf", "part", "short node")
|
||||
pos, err = r.Seek(0, io.SeekCurrent)
|
||||
err = binary.Read(r, binary.LittleEndian, &ne.NameHashTableIndex)
|
||||
n = 4
|
||||
@ -312,7 +275,7 @@ func (ne *NodeEntry) readLong(r io.ReadSeeker) error {
|
||||
err error
|
||||
n int
|
||||
)
|
||||
l = log.With(Logger, "component", "LS converter", "file type", "lsf", "part", "long node")
|
||||
l = log.With(lsgo.Logger, "component", "LS converter", "file type", "lsf", "part", "long node")
|
||||
pos, err = r.Seek(0, io.SeekCurrent)
|
||||
err = binary.Read(r, binary.LittleEndian, &ne.NameHashTableIndex)
|
||||
n = 4
|
||||
@ -417,7 +380,7 @@ func (ae *AttributeEntry) readShort(r io.ReadSeeker) error {
|
||||
err error
|
||||
n int
|
||||
)
|
||||
l = log.With(Logger, "component", "LS converter", "file type", "lsf", "part", "short attribute")
|
||||
l = log.With(lsgo.Logger, "component", "LS converter", "file type", "lsf", "part", "short attribute")
|
||||
pos, err = r.Seek(0, io.SeekCurrent)
|
||||
|
||||
err = binary.Read(r, binary.LittleEndian, &ae.NameHashTableIndex)
|
||||
@ -454,7 +417,7 @@ func (ae *AttributeEntry) readLong(r io.ReadSeeker) error {
|
||||
err error
|
||||
n int
|
||||
)
|
||||
l = log.With(Logger, "component", "LS converter", "file type", "lsf", "part", "long attribute")
|
||||
l = log.With(lsgo.Logger, "component", "LS converter", "file type", "lsf", "part", "long attribute")
|
||||
pos, err = r.Seek(0, io.SeekCurrent)
|
||||
|
||||
err = binary.Read(r, binary.LittleEndian, &ae.NameHashTableIndex)
|
||||
@ -503,8 +466,8 @@ func (ae AttributeEntry) NameOffset() int {
|
||||
}
|
||||
|
||||
// Type of this attribute (see NodeAttribute.DataType)
|
||||
func (ae AttributeEntry) TypeID() DataType {
|
||||
return DataType(ae.TypeAndLength & 0x3f)
|
||||
func (ae AttributeEntry) TypeID() lsgo.DataType {
|
||||
return lsgo.DataType(ae.TypeAndLength & 0x3f)
|
||||
}
|
||||
|
||||
// Length of this attribute
|
||||
@ -522,7 +485,7 @@ type AttributeInfo struct {
|
||||
NameOffset int
|
||||
|
||||
// Type of this attribute (see NodeAttribute.DataType)
|
||||
TypeID DataType
|
||||
TypeID lsgo.DataType
|
||||
|
||||
// Length of this attribute
|
||||
Length uint
|
||||
@ -546,7 +509,7 @@ func ReadNames(r io.ReadSeeker) ([][]string, error) {
|
||||
pos int64
|
||||
n int
|
||||
)
|
||||
l = log.With(Logger, "component", "LS converter", "file type", "lsf", "part", "names")
|
||||
l = log.With(lsgo.Logger, "component", "LS converter", "file type", "lsf", "part", "names")
|
||||
pos, err = r.Seek(0, io.SeekCurrent)
|
||||
|
||||
err = binary.Read(r, binary.LittleEndian, &numHashEntries)
|
||||
@ -567,7 +530,7 @@ func ReadNames(r io.ReadSeeker) ([][]string, error) {
|
||||
l.Log("member", "numStrings", "read", n, "start position", pos, "value", numStrings)
|
||||
pos += int64(n)
|
||||
|
||||
var hash = make([]string, int(numStrings))
|
||||
hash := make([]string, int(numStrings))
|
||||
for x := range hash {
|
||||
var (
|
||||
nameLen uint16
|
||||
@ -702,19 +665,9 @@ func readAttributeInfo(r io.ReadSeeker, long bool) []AttributeInfo {
|
||||
// );
|
||||
// Console.WriteLine(debug);
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
type HeaderError struct {
|
||||
Expected []byte
|
||||
Got []byte
|
||||
}
|
||||
|
||||
func (he HeaderError) Error() string {
|
||||
return fmt.Sprintf("Invalid LSF signature; expected %v, got %v", he.Expected, he.Got)
|
||||
}
|
||||
|
||||
func ReadLSF(r io.ReadSeeker) (Resource, error) {
|
||||
func ReadLSF(r io.ReadSeeker) (lsgo.Resource, error) {
|
||||
var (
|
||||
err error
|
||||
|
||||
@ -728,38 +681,36 @@ func ReadLSF(r io.ReadSeeker) (Resource, error) {
|
||||
attributeInfo []AttributeInfo
|
||||
|
||||
// Node instances
|
||||
nodeInstances []*Node
|
||||
nodeInstances []*lsgo.Node
|
||||
)
|
||||
var (
|
||||
l log.Logger
|
||||
pos, npos int64
|
||||
// n int
|
||||
)
|
||||
l = log.With(Logger, "component", "LS converter", "file type", "lsf", "part", "file")
|
||||
l = log.With(lsgo.Logger, "component", "LS converter", "file type", "lsf", "part", "file")
|
||||
pos, err = r.Seek(0, io.SeekCurrent)
|
||||
l.Log("member", "header", "start position", pos)
|
||||
|
||||
hdr := &LSFHeader{}
|
||||
err = hdr.Read(r)
|
||||
if err != nil || (hdr.Signature != LSFSignature) {
|
||||
return Resource{}, HeaderError{LSFSignature[:], hdr.Signature[:]}
|
||||
return lsgo.Resource{}, lsgo.HeaderError{Expected: LSFSignature[:], Got: hdr.Signature[:]}
|
||||
}
|
||||
|
||||
if hdr.Version < VerInitial || hdr.Version > MaxVersion {
|
||||
return Resource{}, fmt.Errorf("LSF version %v is not supported", hdr.Version)
|
||||
if hdr.Version < lsgo.VerInitial || hdr.Version > lsgo.MaxVersion {
|
||||
return lsgo.Resource{}, fmt.Errorf("LSF version %v is not supported", hdr.Version)
|
||||
}
|
||||
|
||||
isCompressed := CompressionFlagsToMethod(hdr.CompressionFlags) != CMNone && CompressionFlagsToMethod(hdr.CompressionFlags) != CMInvalid
|
||||
isCompressed := lsgo.CompressionFlagsToMethod(hdr.CompressionFlags) != lsgo.CMNone && lsgo.CompressionFlagsToMethod(hdr.CompressionFlags) != lsgo.CMInvalid
|
||||
|
||||
pos, err = r.Seek(0, io.SeekCurrent)
|
||||
l.Log("member", "LSF names", "start position", pos)
|
||||
if hdr.StringsSizeOnDisk > 0 || hdr.StringsUncompressedSize > 0 {
|
||||
var (
|
||||
uncompressed = LimitReadSeeker(r, int64(hdr.StringsSizeOnDisk))
|
||||
)
|
||||
uncompressed := lsgo.LimitReadSeeker(r, int64(hdr.StringsSizeOnDisk))
|
||||
|
||||
if isCompressed {
|
||||
uncompressed = Decompress(uncompressed, int(hdr.StringsUncompressedSize), hdr.CompressionFlags, false)
|
||||
uncompressed = lsgo.Decompress(uncompressed, int(hdr.StringsUncompressedSize), hdr.CompressionFlags, false)
|
||||
}
|
||||
|
||||
// using (var nodesFile = new FileStream("names.bin", FileMode.Create, FileAccess.Write))
|
||||
@ -770,7 +721,7 @@ func ReadLSF(r io.ReadSeeker) (Resource, error) {
|
||||
names, err = ReadNames(uncompressed)
|
||||
// pretty.Log(len(names), names)
|
||||
if err != nil && err != io.EOF {
|
||||
return Resource{}, err
|
||||
return lsgo.Resource{}, err
|
||||
}
|
||||
}
|
||||
|
||||
@ -783,11 +734,9 @@ func ReadLSF(r io.ReadSeeker) (Resource, error) {
|
||||
pos = npos
|
||||
}
|
||||
if hdr.NodesSizeOnDisk > 0 || hdr.NodesUncompressedSize > 0 {
|
||||
var (
|
||||
uncompressed = LimitReadSeeker(r, int64(hdr.NodesSizeOnDisk))
|
||||
)
|
||||
uncompressed := lsgo.LimitReadSeeker(r, int64(hdr.NodesSizeOnDisk))
|
||||
if isCompressed {
|
||||
uncompressed = Decompress(uncompressed, int(hdr.NodesUncompressedSize), hdr.CompressionFlags, hdr.Version >= VerChunkedCompress)
|
||||
uncompressed = lsgo.Decompress(uncompressed, int(hdr.NodesUncompressedSize), hdr.CompressionFlags, hdr.Version >= lsgo.VerChunkedCompress)
|
||||
}
|
||||
|
||||
// using (var nodesFile = new FileStream("nodes.bin", FileMode.Create, FileAccess.Write))
|
||||
@ -795,12 +744,12 @@ func ReadLSF(r io.ReadSeeker) (Resource, error) {
|
||||
// nodesFile.Write(uncompressed, 0, uncompressed.Length);
|
||||
// }
|
||||
|
||||
longNodes := hdr.Version >= VerExtendedNodes && hdr.Extended == 1
|
||||
longNodes := hdr.Version >= lsgo.VerExtendedNodes && hdr.Extended == 1
|
||||
nodeInfo, err = readNodeInfo(uncompressed, longNodes)
|
||||
// pretty.Log(err, nodeInfo)
|
||||
// logger.Printf("region 1 name: %v", names[nodeInfo[0].NameIndex])
|
||||
if err != nil && err != io.EOF {
|
||||
return Resource{}, err
|
||||
return lsgo.Resource{}, err
|
||||
}
|
||||
}
|
||||
|
||||
@ -813,11 +762,9 @@ func ReadLSF(r io.ReadSeeker) (Resource, error) {
|
||||
pos = npos
|
||||
}
|
||||
if hdr.AttributesSizeOnDisk > 0 || hdr.AttributesUncompressedSize > 0 {
|
||||
var (
|
||||
uncompressed io.ReadSeeker = LimitReadSeeker(r, int64(hdr.AttributesSizeOnDisk))
|
||||
)
|
||||
var uncompressed io.ReadSeeker = lsgo.LimitReadSeeker(r, int64(hdr.AttributesSizeOnDisk))
|
||||
if isCompressed {
|
||||
uncompressed = Decompress(uncompressed, int(hdr.AttributesUncompressedSize), hdr.CompressionFlags, hdr.Version >= VerChunkedCompress)
|
||||
uncompressed = lsgo.Decompress(uncompressed, int(hdr.AttributesUncompressedSize), hdr.CompressionFlags, hdr.Version >= lsgo.VerChunkedCompress)
|
||||
}
|
||||
|
||||
// using (var attributesFile = new FileStream("attributes.bin", FileMode.Create, FileAccess.Write))
|
||||
@ -825,7 +772,7 @@ func ReadLSF(r io.ReadSeeker) (Resource, error) {
|
||||
// attributesFile.Write(uncompressed, 0, uncompressed.Length);
|
||||
// }
|
||||
|
||||
longAttributes := hdr.Version >= VerExtendedNodes && hdr.Extended == 1
|
||||
longAttributes := hdr.Version >= lsgo.VerExtendedNodes && hdr.Extended == 1
|
||||
attributeInfo = readAttributeInfo(uncompressed, longAttributes)
|
||||
// logger.Printf("attribute 1 name: %v", names[attributeInfo[0].NameIndex])
|
||||
// pretty.Log(attributeInfo)
|
||||
@ -839,18 +786,16 @@ func ReadLSF(r io.ReadSeeker) (Resource, error) {
|
||||
} else {
|
||||
pos = npos
|
||||
}
|
||||
var (
|
||||
uncompressed io.ReadSeeker = LimitReadSeeker(r, int64(hdr.ValuesSizeOnDisk))
|
||||
)
|
||||
var uncompressed io.ReadSeeker = lsgo.LimitReadSeeker(r, int64(hdr.ValuesSizeOnDisk))
|
||||
if hdr.ValuesSizeOnDisk > 0 || hdr.ValuesUncompressedSize > 0 {
|
||||
if isCompressed {
|
||||
uncompressed = Decompress(r, int(hdr.ValuesUncompressedSize), hdr.CompressionFlags, hdr.Version >= VerChunkedCompress)
|
||||
uncompressed = lsgo.Decompress(r, int(hdr.ValuesUncompressedSize), hdr.CompressionFlags, hdr.Version >= lsgo.VerChunkedCompress)
|
||||
}
|
||||
}
|
||||
|
||||
res := Resource{}
|
||||
valueStart, _ = uncompressed.Seek(0, io.SeekCurrent)
|
||||
nodeInstances, err = ReadRegions(uncompressed, names, nodeInfo, attributeInfo, hdr.Version, hdr.EngineVersion)
|
||||
res := lsgo.Resource{}
|
||||
valueStart, _ := uncompressed.Seek(0, io.SeekCurrent)
|
||||
nodeInstances, err = ReadRegions(uncompressed, valueStart, names, nodeInfo, attributeInfo, hdr.Version, hdr.EngineVersion)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
@ -867,16 +812,13 @@ func ReadLSF(r io.ReadSeeker) (Resource, error) {
|
||||
|
||||
// pretty.Log(res)
|
||||
return res, nil
|
||||
|
||||
}
|
||||
|
||||
var valueStart int64
|
||||
|
||||
func ReadRegions(r io.ReadSeeker, names [][]string, nodeInfo []NodeInfo, attributeInfo []AttributeInfo, version FileVersion, engineVersion uint32) ([]*Node, error) {
|
||||
NodeInstances := make([]*Node, 0, len(nodeInfo))
|
||||
func ReadRegions(r io.ReadSeeker, valueStart int64, names [][]string, nodeInfo []NodeInfo, attributeInfo []AttributeInfo, version lsgo.FileVersion, engineVersion uint32) ([]*lsgo.Node, error) {
|
||||
NodeInstances := make([]*lsgo.Node, 0, len(nodeInfo))
|
||||
for _, nodeInfo := range nodeInfo {
|
||||
if nodeInfo.ParentIndex == -1 {
|
||||
region, err := ReadNode(r, nodeInfo, names, attributeInfo, version, engineVersion)
|
||||
region, err := ReadNode(r, valueStart, nodeInfo, names, attributeInfo, version, engineVersion)
|
||||
|
||||
// pretty.Log(err, region)
|
||||
|
||||
@ -887,7 +829,7 @@ func ReadRegions(r io.ReadSeeker, names [][]string, nodeInfo []NodeInfo, attribu
|
||||
return NodeInstances, err
|
||||
}
|
||||
} else {
|
||||
node, err := ReadNode(r, nodeInfo, names, attributeInfo, version, engineVersion)
|
||||
node, err := ReadNode(r, valueStart, nodeInfo, names, attributeInfo, version, engineVersion)
|
||||
|
||||
// pretty.Log(err, node)
|
||||
|
||||
@ -903,16 +845,16 @@ func ReadRegions(r io.ReadSeeker, names [][]string, nodeInfo []NodeInfo, attribu
|
||||
return NodeInstances, nil
|
||||
}
|
||||
|
||||
func ReadNode(r io.ReadSeeker, ni NodeInfo, names [][]string, attributeInfo []AttributeInfo, version FileVersion, engineVersion uint32) (Node, error) {
|
||||
func ReadNode(r io.ReadSeeker, valueStart int64, ni NodeInfo, names [][]string, attributeInfo []AttributeInfo, version lsgo.FileVersion, engineVersion uint32) (lsgo.Node, error) {
|
||||
var (
|
||||
node = Node{}
|
||||
node = lsgo.Node{}
|
||||
index = ni.FirstAttributeIndex
|
||||
err error
|
||||
|
||||
l log.Logger
|
||||
pos int64
|
||||
)
|
||||
l = log.With(Logger, "component", "LS converter", "file type", "lsf", "part", "node")
|
||||
l = log.With(lsgo.Logger, "component", "LS converter", "file type", "lsf", "part", "node")
|
||||
pos, err = r.Seek(0, io.SeekCurrent)
|
||||
|
||||
node.Name = names[ni.NameIndex][ni.NameOffset]
|
||||
@ -922,7 +864,7 @@ func ReadNode(r io.ReadSeeker, ni NodeInfo, names [][]string, attributeInfo []At
|
||||
for index != -1 {
|
||||
var (
|
||||
attribute = attributeInfo[index]
|
||||
v NodeAttribute
|
||||
v lsgo.NodeAttribute
|
||||
)
|
||||
|
||||
if valueStart+int64(attribute.DataOffset) != pos {
|
||||
@ -943,12 +885,12 @@ func ReadNode(r io.ReadSeeker, ni NodeInfo, names [][]string, attributeInfo []At
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func ReadLSFAttribute(r io.ReadSeeker, name string, dt DataType, length uint, version FileVersion, engineVersion uint32) (NodeAttribute, error) {
|
||||
func ReadLSFAttribute(r io.ReadSeeker, name string, dt lsgo.DataType, length uint, version lsgo.FileVersion, engineVersion uint32) (lsgo.NodeAttribute, error) {
|
||||
// LSF and LSB serialize the buffer types differently, so specialized
|
||||
// code is added to the LSB and LSf serializers, and the common code is
|
||||
// available in BinUtils.ReadAttribute()
|
||||
var (
|
||||
attr = NodeAttribute{
|
||||
attr = lsgo.NodeAttribute{
|
||||
Type: dt,
|
||||
Name: name,
|
||||
}
|
||||
@ -957,13 +899,13 @@ func ReadLSFAttribute(r io.ReadSeeker, name string, dt DataType, length uint, ve
|
||||
l log.Logger
|
||||
pos int64
|
||||
)
|
||||
l = log.With(Logger, "component", "LS converter", "file type", "lsf", "part", "attribute")
|
||||
l = log.With(lsgo.Logger, "component", "LS converter", "file type", "lsf", "part", "attribute")
|
||||
pos, err = r.Seek(0, io.SeekCurrent)
|
||||
|
||||
switch dt {
|
||||
case DTString, DTPath, DTFixedString, DTLSString, DTWString, DTLSWString:
|
||||
case lsgo.DTString, lsgo.DTPath, lsgo.DTFixedString, lsgo.DTLSString, lsgo.DTWString, lsgo.DTLSWString:
|
||||
var v string
|
||||
v, err = ReadCString(r, int(length))
|
||||
v, err = lsgo.ReadCString(r, int(length))
|
||||
attr.Value = v
|
||||
|
||||
l.Log("member", name, "read", length, "start position", pos, "value", attr.Value)
|
||||
@ -971,9 +913,9 @@ func ReadLSFAttribute(r io.ReadSeeker, name string, dt DataType, length uint, ve
|
||||
|
||||
return attr, err
|
||||
|
||||
case DTTranslatedString:
|
||||
var v TranslatedString
|
||||
v, err = ReadTranslatedString(r, version, engineVersion)
|
||||
case lsgo.DTTranslatedString:
|
||||
var v lsgo.TranslatedString
|
||||
v, err = lsgo.ReadTranslatedString(r, version, engineVersion)
|
||||
attr.Value = v
|
||||
|
||||
l.Log("member", name, "read", length, "start position", pos, "value", attr.Value)
|
||||
@ -981,9 +923,9 @@ func ReadLSFAttribute(r io.ReadSeeker, name string, dt DataType, length uint, ve
|
||||
|
||||
return attr, err
|
||||
|
||||
case DTTranslatedFSString:
|
||||
var v TranslatedFSString
|
||||
v, err = ReadTranslatedFSString(r, version)
|
||||
case lsgo.DTTranslatedFSString:
|
||||
var v lsgo.TranslatedFSString
|
||||
v, err = lsgo.ReadTranslatedFSString(r, version)
|
||||
attr.Value = v
|
||||
|
||||
l.Log("member", name, "read", length, "start position", pos, "value", attr.Value)
|
||||
@ -991,7 +933,7 @@ func ReadLSFAttribute(r io.ReadSeeker, name string, dt DataType, length uint, ve
|
||||
|
||||
return attr, err
|
||||
|
||||
case DTScratchBuffer:
|
||||
case lsgo.DTScratchBuffer:
|
||||
|
||||
v := make([]byte, length)
|
||||
_, err = r.Read(v)
|
||||
@ -1003,147 +945,10 @@ func ReadLSFAttribute(r io.ReadSeeker, name string, dt DataType, length uint, ve
|
||||
return attr, err
|
||||
|
||||
default:
|
||||
return ReadAttribute(r, name, dt, length, l)
|
||||
return lsgo.ReadAttribute(r, name, dt, length, l)
|
||||
}
|
||||
}
|
||||
|
||||
func ReadTranslatedString(r io.ReadSeeker, version FileVersion, engineVersion uint32) (TranslatedString, error) {
|
||||
var (
|
||||
str TranslatedString
|
||||
err error
|
||||
)
|
||||
|
||||
if version >= VerBG3 || engineVersion == 0x4000001d {
|
||||
// logger.Println("decoding bg3 data")
|
||||
var version uint16
|
||||
err = binary.Read(r, binary.LittleEndian, &version)
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
str.Version = version
|
||||
err = binary.Read(r, binary.LittleEndian, &version)
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
if version == 0 {
|
||||
str.Value, err = ReadCString(r, int(str.Version))
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
str.Version = 0
|
||||
} else {
|
||||
_, err = r.Seek(-2, io.SeekCurrent)
|
||||
}
|
||||
} else {
|
||||
str.Version = 0
|
||||
|
||||
var (
|
||||
vlength int32
|
||||
v []byte
|
||||
// n int
|
||||
)
|
||||
|
||||
err = binary.Read(r, binary.LittleEndian, &vlength)
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
v = make([]byte, vlength)
|
||||
_, err = r.Read(v)
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
str.Value = string(v)
|
||||
}
|
||||
|
||||
var handleLength int32
|
||||
err = binary.Read(r, binary.LittleEndian, &handleLength)
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
str.Handle, err = ReadCString(r, int(handleLength))
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
// logger.Printf("handle %s; %v", str.Handle, err)
|
||||
return str, nil
|
||||
}
|
||||
|
||||
func ReadTranslatedFSString(r io.ReadSeeker, version FileVersion) (TranslatedFSString, error) {
|
||||
var (
|
||||
str = TranslatedFSString{}
|
||||
err error
|
||||
)
|
||||
|
||||
if version >= VerBG3 {
|
||||
var version uint16
|
||||
err = binary.Read(r, binary.LittleEndian, &version)
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
str.Version = version
|
||||
} else {
|
||||
str.Version = 0
|
||||
|
||||
var (
|
||||
length int32
|
||||
)
|
||||
|
||||
err = binary.Read(r, binary.LittleEndian, &length)
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
str.Value, err = ReadCString(r, int(length))
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
}
|
||||
|
||||
var handleLength int32
|
||||
err = binary.Read(r, binary.LittleEndian, &handleLength)
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
str.Handle, err = ReadCString(r, int(handleLength))
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
|
||||
var arguments int32
|
||||
err = binary.Read(r, binary.LittleEndian, &arguments)
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
str.Arguments = make([]TranslatedFSStringArgument, 0, arguments)
|
||||
for i := 0; i < int(arguments); i++ {
|
||||
arg := TranslatedFSStringArgument{}
|
||||
|
||||
var argKeyLength int32
|
||||
err = binary.Read(r, binary.LittleEndian, &argKeyLength)
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
arg.Key, err = ReadCString(r, int(argKeyLength))
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
|
||||
arg.String, err = ReadTranslatedFSString(r, version)
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
|
||||
var argValueLength int32
|
||||
err = binary.Read(r, binary.LittleEndian, &argValueLength)
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
arg.Value, err = ReadCString(r, int(argValueLength))
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
|
||||
str.Arguments = append(str.Arguments, arg)
|
||||
}
|
||||
|
||||
return str, nil
|
||||
func init() {
|
||||
lsgo.RegisterFormat("lsf", "LSOF", ReadLSF)
|
||||
}
|
44
lsgo.go
Normal file
44
lsgo.go
Normal file
@ -0,0 +1,44 @@
|
||||
package lsgo
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/go-kit/kit/log"
|
||||
)
|
||||
|
||||
var Logger log.Logger = log.NewNopLogger()
|
||||
|
||||
// NewFilter allows filtering of l
|
||||
func NewFilter(f map[string][]string, l log.Logger) log.Logger {
|
||||
return filter{
|
||||
filter: f,
|
||||
next: l,
|
||||
}
|
||||
}
|
||||
|
||||
type filter struct {
|
||||
next log.Logger
|
||||
filter map[string][]string
|
||||
}
|
||||
|
||||
func (f filter) Log(keyvals ...interface{}) error {
|
||||
allowed := true // allow everything
|
||||
for i := 0; i < len(keyvals)-1; i += 2 {
|
||||
if v, ok := keyvals[i].(string); ok { // key
|
||||
if fil, ok := f.filter[v]; ok { // key has a filter
|
||||
if v, ok = keyvals[i+1].(string); ok { // value is a string
|
||||
allowed = false // this key has a filter deny everything except what the filter allows
|
||||
for _, fi := range fil {
|
||||
if strings.Contains(v, fi) {
|
||||
allowed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if allowed {
|
||||
return f.next.Log(keyvals...)
|
||||
}
|
||||
return nil
|
||||
}
|
@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
type LSMetadata struct {
|
||||
//public const uint CurrentMajorVersion = 33;
|
||||
// public const uint CurrentMajorVersion = 33;
|
||||
|
||||
Timestamp uint64 `xml:"-"`
|
||||
Major uint32 `xml:"major,attr"`
|
||||
@ -15,18 +15,12 @@ type LSMetadata struct {
|
||||
Build uint32 `xml:"build,attr"`
|
||||
}
|
||||
|
||||
type format struct {
|
||||
name, magic string
|
||||
read func(io.Reader) (Resource, error)
|
||||
}
|
||||
|
||||
type Resource struct {
|
||||
Metadata LSMetadata `xml:"version"`
|
||||
Regions []*Node `xml:"region"`
|
||||
}
|
||||
|
||||
func (r *Resource) Read(io.Reader) {
|
||||
|
||||
}
|
||||
|
||||
// public Resource()
|
||||
|
Loading…
x
Reference in New Issue
Block a user