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)
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -385,9 +385,7 @@ func (na *NodeAttribute) FromString(str string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var err error
|
||||||
err error
|
|
||||||
)
|
|
||||||
|
|
||||||
switch na.Type {
|
switch na.Type {
|
||||||
case DTNone:
|
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
|
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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"git.narnian.us/lordwelch/lsgo"
|
"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/go-kit/kit/log"
|
||||||
"github.com/kr/pretty"
|
"github.com/kr/pretty"
|
||||||
@ -75,6 +80,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func openLSF(filename string) error {
|
func openLSF(filename string) error {
|
||||||
var (
|
var (
|
||||||
l *lsgo.Resource
|
l *lsgo.Resource
|
||||||
@ -119,16 +125,64 @@ func openLSF(filename string) error {
|
|||||||
func readLSF(filename string) (*lsgo.Resource, error) {
|
func readLSF(filename string) (*lsgo.Resource, error) {
|
||||||
var (
|
var (
|
||||||
l lsgo.Resource
|
l lsgo.Resource
|
||||||
f *os.File
|
r io.ReadSeeker
|
||||||
|
file *os.File
|
||||||
|
fi os.FileInfo
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
f, err = os.Open(filename)
|
switch filepath.Ext(filename) {
|
||||||
|
|
||||||
|
case ".lsf", ".lsb":
|
||||||
|
var b []byte
|
||||||
|
fi, err = os.Stat(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
// 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()
|
||||||
|
|
||||||
l, err = lsgo.ReadLSF(f)
|
_, 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -159,9 +213,7 @@ func marshalXML(l *lsgo.Resource) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func writeXML(f io.StringWriter, n string) error {
|
func writeXML(f io.StringWriter, n string) error {
|
||||||
var (
|
var err error
|
||||||
err error
|
|
||||||
)
|
|
||||||
_, err = f.WriteString(strings.ToLower(xml.Header))
|
_, err = f.WriteString(strings.ToLower(xml.Header))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
14
const.go
14
const.go
@ -1,6 +1,9 @@
|
|||||||
package lsgo
|
package lsgo
|
||||||
|
|
||||||
import "errors"
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
type FileVersion uint32
|
type FileVersion uint32
|
||||||
|
|
||||||
@ -43,3 +46,12 @@ var (
|
|||||||
ErrInvalidNameKey = errors.New("invalid name key")
|
ErrInvalidNameKey = errors.New("invalid name key")
|
||||||
ErrKeyDoesNotMatch = errors.New("key for this node does not match")
|
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
|
go 1.15
|
||||||
|
|
||||||
replace github.com/pierrec/lz4/v4 v4.1.1 => ./lz4
|
replace github.com/pierrec/lz4/v4 v4.1.3 => ./lz4
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/go-kit/kit v0.10.0
|
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/kr/pretty v0.2.1
|
||||||
github.com/pierrec/lz4/v4 v4.1.1
|
github.com/pierrec/lz4/v4 v4.1.3
|
||||||
gonum.org/v1/gonum v0.8.1
|
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/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
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.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.4 h1:0ecGp3skIrHWPNGPJDaBIghfA6Sp7Ruo2Io8eLKzWm0=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
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/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/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
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-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/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.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.2 h1:CCXrcPKiGGotvnN6jfUsKk4rRqm7q09/YbKb5xCEvtM=
|
||||||
gonum.org/v1/gonum v0.8.1/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
|
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 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc=
|
||||||
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
|
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=
|
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 (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
@ -7,6 +7,8 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
|
"git.narnian.us/lordwelch/lsgo"
|
||||||
|
|
||||||
"github.com/go-kit/kit/log"
|
"github.com/go-kit/kit/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -15,7 +17,7 @@ type LSBHeader struct {
|
|||||||
Size uint32
|
Size uint32
|
||||||
Endianness uint32
|
Endianness uint32
|
||||||
Unknown uint32
|
Unknown uint32
|
||||||
Version LSMetadata
|
Version lsgo.LSMetadata
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lsbh *LSBHeader) Read(r io.ReadSeeker) error {
|
func (lsbh *LSBHeader) Read(r io.ReadSeeker) error {
|
||||||
@ -25,7 +27,7 @@ func (lsbh *LSBHeader) Read(r io.ReadSeeker) error {
|
|||||||
n int
|
n int
|
||||||
err error
|
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)
|
pos, err = r.Seek(0, io.SeekCurrent)
|
||||||
|
|
||||||
n, err = r.Read(lsbh.Signature[:])
|
n, err = r.Read(lsbh.Signature[:])
|
||||||
@ -102,27 +104,27 @@ func (lsbh *LSBHeader) Read(r io.ReadSeeker) error {
|
|||||||
|
|
||||||
type IdentifierDictionary map[int]string
|
type IdentifierDictionary map[int]string
|
||||||
|
|
||||||
func ReadLSB(r io.ReadSeeker) (Resource, error) {
|
func ReadLSB(r io.ReadSeeker) (lsgo.Resource, error) {
|
||||||
var (
|
var (
|
||||||
hdr = &LSBHeader{}
|
hdr = &LSBHeader{}
|
||||||
h = [4]byte{0x00, 0x00, 0x00, 0x40}
|
h = [4]byte{0x00, 0x00, 0x00, 0x40}
|
||||||
err error
|
err error
|
||||||
d IdentifierDictionary
|
d IdentifierDictionary
|
||||||
res Resource
|
res lsgo.Resource
|
||||||
|
|
||||||
l log.Logger
|
l log.Logger
|
||||||
pos int64
|
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)
|
pos, err = r.Seek(0, io.SeekCurrent)
|
||||||
l.Log("member", "header", "start position", pos)
|
l.Log("member", "header", "start position", pos)
|
||||||
|
|
||||||
err = hdr.Read(r)
|
err = hdr.Read(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Resource{}, err
|
return lsgo.Resource{}, err
|
||||||
}
|
}
|
||||||
if !(hdr.Signature == [4]byte{'L', 'S', 'F', 'M'} || hdr.Signature == h) {
|
if !(hdr.Signature == [4]byte{'L', 'S', 'F', 'M'} || hdr.Signature == h) {
|
||||||
return Resource{}, HeaderError{
|
return lsgo.Resource{}, lsgo.HeaderError{
|
||||||
Expected: []byte("LSFM"),
|
Expected: []byte("LSFM"),
|
||||||
Got: hdr.Signature[:],
|
Got: hdr.Signature[:],
|
||||||
}
|
}
|
||||||
@ -132,13 +134,13 @@ func ReadLSB(r io.ReadSeeker) (Resource, error) {
|
|||||||
l.Log("member", "string dictionary", "start position", pos)
|
l.Log("member", "string dictionary", "start position", pos)
|
||||||
d, err = ReadLSBDictionary(r, binary.LittleEndian)
|
d, err = ReadLSBDictionary(r, binary.LittleEndian)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Resource{}, err
|
return lsgo.Resource{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
pos, err = r.Seek(0, io.SeekCurrent)
|
pos, err = r.Seek(0, io.SeekCurrent)
|
||||||
l.Log("member", "Regions", "start position", pos)
|
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
|
res.Metadata = hdr.Version
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
@ -153,7 +155,7 @@ func ReadLSBDictionary(r io.ReadSeeker, endianness binary.ByteOrder) (Identifier
|
|||||||
pos int64
|
pos int64
|
||||||
n int
|
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)
|
pos, err = r.Seek(0, io.SeekCurrent)
|
||||||
|
|
||||||
err = binary.Read(r, endianness, &length)
|
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)
|
l.Log("member", "stringLength", "read", n, "start position", pos, "value", stringLength)
|
||||||
pos += int64(n)
|
pos += int64(n)
|
||||||
|
|
||||||
str, err = ReadCString(r, int(stringLength))
|
str, err = lsgo.ReadCString(r, int(stringLength))
|
||||||
n += int(stringLength)
|
n += int(stringLength)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return dict, err
|
return dict, err
|
||||||
@ -199,7 +201,7 @@ func ReadLSBDictionary(r io.ReadSeeker, endianness binary.ByteOrder) (Identifier
|
|||||||
return dict, nil
|
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 (
|
var (
|
||||||
regions []struct {
|
regions []struct {
|
||||||
name string
|
name string
|
||||||
@ -212,13 +214,13 @@ func ReadLSBRegions(r io.ReadSeeker, d IdentifierDictionary, endianness binary.B
|
|||||||
pos int64
|
pos int64
|
||||||
n int
|
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)
|
pos, err = r.Seek(0, io.SeekCurrent)
|
||||||
|
|
||||||
err = binary.Read(r, endianness, ®ionCount)
|
err = binary.Read(r, endianness, ®ionCount)
|
||||||
n = 4
|
n = 4
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Resource{}, err
|
return lsgo.Resource{}, err
|
||||||
}
|
}
|
||||||
l.Log("member", "regionCount", "read", n, "start position", pos, "value", regionCount)
|
l.Log("member", "regionCount", "read", n, "start position", pos, "value", regionCount)
|
||||||
pos += int64(n)
|
pos += int64(n)
|
||||||
@ -235,17 +237,17 @@ func ReadLSBRegions(r io.ReadSeeker, d IdentifierDictionary, endianness binary.B
|
|||||||
err = binary.Read(r, endianness, &key)
|
err = binary.Read(r, endianness, &key)
|
||||||
n = 4
|
n = 4
|
||||||
if err != nil {
|
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)
|
l.Log("member", "key", "read", n, "start position", pos, "value", d[int(key)], "key", key)
|
||||||
pos += int64(n)
|
pos += int64(n)
|
||||||
if regions[i].name, ok = d[int(key)]; !ok {
|
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)
|
err = binary.Read(r, endianness, ®ions[i].offset)
|
||||||
n = 4
|
n = 4
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Resource{}, err
|
return lsgo.Resource{}, err
|
||||||
}
|
}
|
||||||
l.Log("member", "offset", "read", n, "start position", pos, "value", regions[i].offset)
|
l.Log("member", "offset", "read", n, "start position", pos, "value", regions[i].offset)
|
||||||
pos += int64(n)
|
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 {
|
sort.Slice(regions, func(i, j int) bool {
|
||||||
return regions[i].offset < regions[j].offset
|
return regions[i].offset < regions[j].offset
|
||||||
})
|
})
|
||||||
res := Resource{
|
res := lsgo.Resource{
|
||||||
Regions: make([]*Node, 0, regionCount),
|
Regions: make([]*lsgo.Node, 0, regionCount),
|
||||||
}
|
}
|
||||||
for _, re := range regions {
|
for _, re := range regions {
|
||||||
var node *Node
|
var node *lsgo.Node
|
||||||
node, err = readLSBNode(r, d, endianness, version, re.offset)
|
node, err = readLSBNode(r, d, endianness, version, re.offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
@ -268,12 +270,12 @@ func ReadLSBRegions(r io.ReadSeeker, d IdentifierDictionary, endianness binary.B
|
|||||||
return res, nil
|
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 (
|
var (
|
||||||
key uint32
|
key uint32
|
||||||
attrCount uint32
|
attrCount uint32
|
||||||
childCount uint32
|
childCount uint32
|
||||||
node = new(Node)
|
node = new(lsgo.Node)
|
||||||
err error
|
err error
|
||||||
ok bool
|
ok bool
|
||||||
|
|
||||||
@ -281,7 +283,7 @@ func readLSBNode(r io.ReadSeeker, d IdentifierDictionary, endianness binary.Byte
|
|||||||
pos int64
|
pos int64
|
||||||
n int
|
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)
|
pos, err = r.Seek(0, io.SeekCurrent)
|
||||||
|
|
||||||
if pos != int64(offset) && offset != 0 {
|
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)
|
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 {
|
for i := range node.Attributes {
|
||||||
node.Attributes[i], err = readLSBAttribute(r, d, endianness, version)
|
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 {
|
for i := range node.Children {
|
||||||
node.Children[i], err = readLSBNode(r, d, endianness, version, 0)
|
node.Children[i], err = readLSBNode(r, d, endianness, version, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -334,12 +336,12 @@ func readLSBNode(r io.ReadSeeker, d IdentifierDictionary, endianness binary.Byte
|
|||||||
return node, nil
|
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 (
|
var (
|
||||||
key uint32
|
key uint32
|
||||||
name string
|
name string
|
||||||
attrType uint32
|
attrType uint32
|
||||||
attr NodeAttribute
|
attr lsgo.NodeAttribute
|
||||||
err error
|
err error
|
||||||
ok bool
|
ok bool
|
||||||
)
|
)
|
||||||
@ -348,21 +350,21 @@ func readLSBAttribute(r io.ReadSeeker, d IdentifierDictionary, endianness binary
|
|||||||
return attr, err
|
return attr, err
|
||||||
}
|
}
|
||||||
if name, ok = d[int(key)]; !ok {
|
if name, ok = d[int(key)]; !ok {
|
||||||
return attr, ErrInvalidNameKey
|
return attr, lsgo.ErrInvalidNameKey
|
||||||
}
|
}
|
||||||
err = binary.Read(r, endianness, &attrType)
|
err = binary.Read(r, endianness, &attrType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return attr, err
|
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
|
// LSF and LSB serialize the buffer types differently, so specialized
|
||||||
// code is added to the LSB and LSf serializers, and the common code is
|
// code is added to the LSB and LSf serializers, and the common code is
|
||||||
// available in BinUtils.ReadAttribute()
|
// available in BinUtils.ReadAttribute()
|
||||||
var (
|
var (
|
||||||
attr = NodeAttribute{
|
attr = lsgo.NodeAttribute{
|
||||||
Type: dt,
|
Type: dt,
|
||||||
Name: name,
|
Name: name,
|
||||||
}
|
}
|
||||||
@ -372,38 +374,38 @@ func ReadLSBAttr(r io.ReadSeeker, name string, dt DataType, endianness binary.By
|
|||||||
l log.Logger
|
l log.Logger
|
||||||
pos int64
|
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)
|
pos, err = r.Seek(0, io.SeekCurrent)
|
||||||
|
|
||||||
switch dt {
|
switch dt {
|
||||||
case DTString, DTPath, DTFixedString, DTLSString: //, DTLSWString:
|
case lsgo.DTString, lsgo.DTPath, lsgo.DTFixedString, lsgo.DTLSString: //, DTLSWString:
|
||||||
var v string
|
var v string
|
||||||
err = binary.Read(r, endianness, &length)
|
err = binary.Read(r, endianness, &length)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return attr, err
|
return attr, err
|
||||||
}
|
}
|
||||||
v, err = ReadCString(r, int(length))
|
v, err = lsgo.ReadCString(r, int(length))
|
||||||
attr.Value = v
|
attr.Value = v
|
||||||
|
|
||||||
l.Log("member", name, "read", length, "start position", pos, "value", attr.Value)
|
l.Log("member", name, "read", length, "start position", pos, "value", attr.Value)
|
||||||
|
|
||||||
return attr, err
|
return attr, err
|
||||||
|
|
||||||
case DTWString:
|
case lsgo.DTWString:
|
||||||
panic("Not implemented")
|
panic("Not implemented")
|
||||||
|
|
||||||
case DTTranslatedString:
|
case lsgo.DTTranslatedString:
|
||||||
var v TranslatedString
|
var v lsgo.TranslatedString
|
||||||
v, err = ReadTranslatedString(r, version, 0)
|
v, err = lsgo.ReadTranslatedString(r, version, 0)
|
||||||
attr.Value = v
|
attr.Value = v
|
||||||
|
|
||||||
l.Log("member", name, "read", length, "start position", pos, "value", attr.Value)
|
l.Log("member", name, "read", length, "start position", pos, "value", attr.Value)
|
||||||
|
|
||||||
return attr, err
|
return attr, err
|
||||||
|
|
||||||
case DTTranslatedFSString:
|
case lsgo.DTTranslatedFSString:
|
||||||
panic("Not implemented")
|
panic("Not implemented")
|
||||||
var v TranslatedFSString
|
var v lsgo.TranslatedFSString
|
||||||
// v, err = ReadTranslatedFSString(r, Version)
|
// v, err = ReadTranslatedFSString(r, Version)
|
||||||
attr.Value = v
|
attr.Value = v
|
||||||
|
|
||||||
@ -411,7 +413,7 @@ func ReadLSBAttr(r io.ReadSeeker, name string, dt DataType, endianness binary.By
|
|||||||
|
|
||||||
return attr, err
|
return attr, err
|
||||||
|
|
||||||
case DTScratchBuffer:
|
case lsgo.DTScratchBuffer:
|
||||||
panic("Not implemented")
|
panic("Not implemented")
|
||||||
|
|
||||||
v := make([]byte, length)
|
v := make([]byte, length)
|
||||||
@ -423,6 +425,11 @@ func ReadLSBAttr(r io.ReadSeeker, name string, dt DataType, endianness binary.By
|
|||||||
return attr, err
|
return attr, err
|
||||||
|
|
||||||
default:
|
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 (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
|
"git.narnian.us/lordwelch/lsgo"
|
||||||
|
|
||||||
"github.com/go-kit/kit/log"
|
"github.com/go-kit/kit/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var LSFSignature = [4]byte{0x4C, 0x53, 0x4F, 0x46}
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
type LSFHeader struct {
|
type LSFHeader struct {
|
||||||
// LSOF file signature
|
// LSOF file signature
|
||||||
Signature [4]byte
|
Signature [4]byte
|
||||||
|
|
||||||
// Version of the LSOF file D:OS EE is version 1/2, D:OS 2 is version 3
|
// 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)
|
// Possibly version number? (major, minor, rev, build)
|
||||||
EngineVersion uint32
|
EngineVersion uint32
|
||||||
@ -103,7 +66,7 @@ func (lsfh *LSFHeader) Read(r io.ReadSeeker) error {
|
|||||||
n int
|
n int
|
||||||
err error
|
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)
|
pos, err = r.Seek(0, io.SeekCurrent)
|
||||||
n, err = r.Read(lsfh.Signature[:])
|
n, err = r.Read(lsfh.Signature[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -233,7 +196,7 @@ func (lsfh *LSFHeader) Read(r io.ReadSeeker) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (lsfh LSFHeader) IsCompressed() bool {
|
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 {
|
type NodeEntry struct {
|
||||||
@ -274,7 +237,7 @@ func (ne *NodeEntry) readShort(r io.ReadSeeker) error {
|
|||||||
err error
|
err error
|
||||||
n int
|
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)
|
pos, err = r.Seek(0, io.SeekCurrent)
|
||||||
err = binary.Read(r, binary.LittleEndian, &ne.NameHashTableIndex)
|
err = binary.Read(r, binary.LittleEndian, &ne.NameHashTableIndex)
|
||||||
n = 4
|
n = 4
|
||||||
@ -312,7 +275,7 @@ func (ne *NodeEntry) readLong(r io.ReadSeeker) error {
|
|||||||
err error
|
err error
|
||||||
n int
|
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)
|
pos, err = r.Seek(0, io.SeekCurrent)
|
||||||
err = binary.Read(r, binary.LittleEndian, &ne.NameHashTableIndex)
|
err = binary.Read(r, binary.LittleEndian, &ne.NameHashTableIndex)
|
||||||
n = 4
|
n = 4
|
||||||
@ -417,7 +380,7 @@ func (ae *AttributeEntry) readShort(r io.ReadSeeker) error {
|
|||||||
err error
|
err error
|
||||||
n int
|
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)
|
pos, err = r.Seek(0, io.SeekCurrent)
|
||||||
|
|
||||||
err = binary.Read(r, binary.LittleEndian, &ae.NameHashTableIndex)
|
err = binary.Read(r, binary.LittleEndian, &ae.NameHashTableIndex)
|
||||||
@ -454,7 +417,7 @@ func (ae *AttributeEntry) readLong(r io.ReadSeeker) error {
|
|||||||
err error
|
err error
|
||||||
n int
|
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)
|
pos, err = r.Seek(0, io.SeekCurrent)
|
||||||
|
|
||||||
err = binary.Read(r, binary.LittleEndian, &ae.NameHashTableIndex)
|
err = binary.Read(r, binary.LittleEndian, &ae.NameHashTableIndex)
|
||||||
@ -503,8 +466,8 @@ func (ae AttributeEntry) NameOffset() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Type of this attribute (see NodeAttribute.DataType)
|
// Type of this attribute (see NodeAttribute.DataType)
|
||||||
func (ae AttributeEntry) TypeID() DataType {
|
func (ae AttributeEntry) TypeID() lsgo.DataType {
|
||||||
return DataType(ae.TypeAndLength & 0x3f)
|
return lsgo.DataType(ae.TypeAndLength & 0x3f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Length of this attribute
|
// Length of this attribute
|
||||||
@ -522,7 +485,7 @@ type AttributeInfo struct {
|
|||||||
NameOffset int
|
NameOffset int
|
||||||
|
|
||||||
// Type of this attribute (see NodeAttribute.DataType)
|
// Type of this attribute (see NodeAttribute.DataType)
|
||||||
TypeID DataType
|
TypeID lsgo.DataType
|
||||||
|
|
||||||
// Length of this attribute
|
// Length of this attribute
|
||||||
Length uint
|
Length uint
|
||||||
@ -546,7 +509,7 @@ func ReadNames(r io.ReadSeeker) ([][]string, error) {
|
|||||||
pos int64
|
pos int64
|
||||||
n int
|
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)
|
pos, err = r.Seek(0, io.SeekCurrent)
|
||||||
|
|
||||||
err = binary.Read(r, binary.LittleEndian, &numHashEntries)
|
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)
|
l.Log("member", "numStrings", "read", n, "start position", pos, "value", numStrings)
|
||||||
pos += int64(n)
|
pos += int64(n)
|
||||||
|
|
||||||
var hash = make([]string, int(numStrings))
|
hash := make([]string, int(numStrings))
|
||||||
for x := range hash {
|
for x := range hash {
|
||||||
var (
|
var (
|
||||||
nameLen uint16
|
nameLen uint16
|
||||||
@ -702,19 +665,9 @@ func readAttributeInfo(r io.ReadSeeker, long bool) []AttributeInfo {
|
|||||||
// );
|
// );
|
||||||
// Console.WriteLine(debug);
|
// Console.WriteLine(debug);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type HeaderError struct {
|
func ReadLSF(r io.ReadSeeker) (lsgo.Resource, error) {
|
||||||
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) {
|
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
|
|
||||||
@ -728,38 +681,36 @@ func ReadLSF(r io.ReadSeeker) (Resource, error) {
|
|||||||
attributeInfo []AttributeInfo
|
attributeInfo []AttributeInfo
|
||||||
|
|
||||||
// Node instances
|
// Node instances
|
||||||
nodeInstances []*Node
|
nodeInstances []*lsgo.Node
|
||||||
)
|
)
|
||||||
var (
|
var (
|
||||||
l log.Logger
|
l log.Logger
|
||||||
pos, npos int64
|
pos, npos int64
|
||||||
// n int
|
// 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)
|
pos, err = r.Seek(0, io.SeekCurrent)
|
||||||
l.Log("member", "header", "start position", pos)
|
l.Log("member", "header", "start position", pos)
|
||||||
|
|
||||||
hdr := &LSFHeader{}
|
hdr := &LSFHeader{}
|
||||||
err = hdr.Read(r)
|
err = hdr.Read(r)
|
||||||
if err != nil || (hdr.Signature != LSFSignature) {
|
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 {
|
if hdr.Version < lsgo.VerInitial || hdr.Version > lsgo.MaxVersion {
|
||||||
return Resource{}, fmt.Errorf("LSF version %v is not supported", hdr.Version)
|
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)
|
pos, err = r.Seek(0, io.SeekCurrent)
|
||||||
l.Log("member", "LSF names", "start position", pos)
|
l.Log("member", "LSF names", "start position", pos)
|
||||||
if hdr.StringsSizeOnDisk > 0 || hdr.StringsUncompressedSize > 0 {
|
if hdr.StringsSizeOnDisk > 0 || hdr.StringsUncompressedSize > 0 {
|
||||||
var (
|
uncompressed := lsgo.LimitReadSeeker(r, int64(hdr.StringsSizeOnDisk))
|
||||||
uncompressed = LimitReadSeeker(r, int64(hdr.StringsSizeOnDisk))
|
|
||||||
)
|
|
||||||
|
|
||||||
if isCompressed {
|
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))
|
// 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)
|
names, err = ReadNames(uncompressed)
|
||||||
// pretty.Log(len(names), names)
|
// pretty.Log(len(names), names)
|
||||||
if err != nil && err != io.EOF {
|
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
|
pos = npos
|
||||||
}
|
}
|
||||||
if hdr.NodesSizeOnDisk > 0 || hdr.NodesUncompressedSize > 0 {
|
if hdr.NodesSizeOnDisk > 0 || hdr.NodesUncompressedSize > 0 {
|
||||||
var (
|
uncompressed := lsgo.LimitReadSeeker(r, int64(hdr.NodesSizeOnDisk))
|
||||||
uncompressed = LimitReadSeeker(r, int64(hdr.NodesSizeOnDisk))
|
|
||||||
)
|
|
||||||
if isCompressed {
|
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))
|
// 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);
|
// 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)
|
nodeInfo, err = readNodeInfo(uncompressed, longNodes)
|
||||||
// pretty.Log(err, nodeInfo)
|
// pretty.Log(err, nodeInfo)
|
||||||
// logger.Printf("region 1 name: %v", names[nodeInfo[0].NameIndex])
|
// logger.Printf("region 1 name: %v", names[nodeInfo[0].NameIndex])
|
||||||
if err != nil && err != io.EOF {
|
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
|
pos = npos
|
||||||
}
|
}
|
||||||
if hdr.AttributesSizeOnDisk > 0 || hdr.AttributesUncompressedSize > 0 {
|
if hdr.AttributesSizeOnDisk > 0 || hdr.AttributesUncompressedSize > 0 {
|
||||||
var (
|
var uncompressed io.ReadSeeker = lsgo.LimitReadSeeker(r, int64(hdr.AttributesSizeOnDisk))
|
||||||
uncompressed io.ReadSeeker = LimitReadSeeker(r, int64(hdr.AttributesSizeOnDisk))
|
|
||||||
)
|
|
||||||
if isCompressed {
|
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))
|
// 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);
|
// 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)
|
attributeInfo = readAttributeInfo(uncompressed, longAttributes)
|
||||||
// logger.Printf("attribute 1 name: %v", names[attributeInfo[0].NameIndex])
|
// logger.Printf("attribute 1 name: %v", names[attributeInfo[0].NameIndex])
|
||||||
// pretty.Log(attributeInfo)
|
// pretty.Log(attributeInfo)
|
||||||
@ -839,18 +786,16 @@ func ReadLSF(r io.ReadSeeker) (Resource, error) {
|
|||||||
} else {
|
} else {
|
||||||
pos = npos
|
pos = npos
|
||||||
}
|
}
|
||||||
var (
|
var uncompressed io.ReadSeeker = lsgo.LimitReadSeeker(r, int64(hdr.ValuesSizeOnDisk))
|
||||||
uncompressed io.ReadSeeker = LimitReadSeeker(r, int64(hdr.ValuesSizeOnDisk))
|
|
||||||
)
|
|
||||||
if hdr.ValuesSizeOnDisk > 0 || hdr.ValuesUncompressedSize > 0 {
|
if hdr.ValuesSizeOnDisk > 0 || hdr.ValuesUncompressedSize > 0 {
|
||||||
if isCompressed {
|
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{}
|
res := lsgo.Resource{}
|
||||||
valueStart, _ = uncompressed.Seek(0, io.SeekCurrent)
|
valueStart, _ := uncompressed.Seek(0, io.SeekCurrent)
|
||||||
nodeInstances, err = ReadRegions(uncompressed, names, nodeInfo, attributeInfo, hdr.Version, hdr.EngineVersion)
|
nodeInstances, err = ReadRegions(uncompressed, valueStart, names, nodeInfo, attributeInfo, hdr.Version, hdr.EngineVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
@ -867,16 +812,13 @@ func ReadLSF(r io.ReadSeeker) (Resource, error) {
|
|||||||
|
|
||||||
// pretty.Log(res)
|
// pretty.Log(res)
|
||||||
return res, nil
|
return res, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var valueStart int64
|
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))
|
||||||
func ReadRegions(r io.ReadSeeker, names [][]string, nodeInfo []NodeInfo, attributeInfo []AttributeInfo, version FileVersion, engineVersion uint32) ([]*Node, error) {
|
|
||||||
NodeInstances := make([]*Node, 0, len(nodeInfo))
|
|
||||||
for _, nodeInfo := range nodeInfo {
|
for _, nodeInfo := range nodeInfo {
|
||||||
if nodeInfo.ParentIndex == -1 {
|
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)
|
// pretty.Log(err, region)
|
||||||
|
|
||||||
@ -887,7 +829,7 @@ func ReadRegions(r io.ReadSeeker, names [][]string, nodeInfo []NodeInfo, attribu
|
|||||||
return NodeInstances, err
|
return NodeInstances, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
node, err := ReadNode(r, nodeInfo, names, attributeInfo, version, engineVersion)
|
node, err := ReadNode(r, valueStart, nodeInfo, names, attributeInfo, version, engineVersion)
|
||||||
|
|
||||||
// pretty.Log(err, node)
|
// pretty.Log(err, node)
|
||||||
|
|
||||||
@ -903,16 +845,16 @@ func ReadRegions(r io.ReadSeeker, names [][]string, nodeInfo []NodeInfo, attribu
|
|||||||
return NodeInstances, nil
|
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 (
|
var (
|
||||||
node = Node{}
|
node = lsgo.Node{}
|
||||||
index = ni.FirstAttributeIndex
|
index = ni.FirstAttributeIndex
|
||||||
err error
|
err error
|
||||||
|
|
||||||
l log.Logger
|
l log.Logger
|
||||||
pos int64
|
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)
|
pos, err = r.Seek(0, io.SeekCurrent)
|
||||||
|
|
||||||
node.Name = names[ni.NameIndex][ni.NameOffset]
|
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 {
|
for index != -1 {
|
||||||
var (
|
var (
|
||||||
attribute = attributeInfo[index]
|
attribute = attributeInfo[index]
|
||||||
v NodeAttribute
|
v lsgo.NodeAttribute
|
||||||
)
|
)
|
||||||
|
|
||||||
if valueStart+int64(attribute.DataOffset) != pos {
|
if valueStart+int64(attribute.DataOffset) != pos {
|
||||||
@ -943,12 +885,12 @@ func ReadNode(r io.ReadSeeker, ni NodeInfo, names [][]string, attributeInfo []At
|
|||||||
return node, nil
|
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
|
// LSF and LSB serialize the buffer types differently, so specialized
|
||||||
// code is added to the LSB and LSf serializers, and the common code is
|
// code is added to the LSB and LSf serializers, and the common code is
|
||||||
// available in BinUtils.ReadAttribute()
|
// available in BinUtils.ReadAttribute()
|
||||||
var (
|
var (
|
||||||
attr = NodeAttribute{
|
attr = lsgo.NodeAttribute{
|
||||||
Type: dt,
|
Type: dt,
|
||||||
Name: name,
|
Name: name,
|
||||||
}
|
}
|
||||||
@ -957,13 +899,13 @@ func ReadLSFAttribute(r io.ReadSeeker, name string, dt DataType, length uint, ve
|
|||||||
l log.Logger
|
l log.Logger
|
||||||
pos int64
|
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)
|
pos, err = r.Seek(0, io.SeekCurrent)
|
||||||
|
|
||||||
switch dt {
|
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
|
var v string
|
||||||
v, err = ReadCString(r, int(length))
|
v, err = lsgo.ReadCString(r, int(length))
|
||||||
attr.Value = v
|
attr.Value = v
|
||||||
|
|
||||||
l.Log("member", name, "read", length, "start position", pos, "value", attr.Value)
|
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
|
return attr, err
|
||||||
|
|
||||||
case DTTranslatedString:
|
case lsgo.DTTranslatedString:
|
||||||
var v TranslatedString
|
var v lsgo.TranslatedString
|
||||||
v, err = ReadTranslatedString(r, version, engineVersion)
|
v, err = lsgo.ReadTranslatedString(r, version, engineVersion)
|
||||||
attr.Value = v
|
attr.Value = v
|
||||||
|
|
||||||
l.Log("member", name, "read", length, "start position", pos, "value", attr.Value)
|
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
|
return attr, err
|
||||||
|
|
||||||
case DTTranslatedFSString:
|
case lsgo.DTTranslatedFSString:
|
||||||
var v TranslatedFSString
|
var v lsgo.TranslatedFSString
|
||||||
v, err = ReadTranslatedFSString(r, version)
|
v, err = lsgo.ReadTranslatedFSString(r, version)
|
||||||
attr.Value = v
|
attr.Value = v
|
||||||
|
|
||||||
l.Log("member", name, "read", length, "start position", pos, "value", attr.Value)
|
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
|
return attr, err
|
||||||
|
|
||||||
case DTScratchBuffer:
|
case lsgo.DTScratchBuffer:
|
||||||
|
|
||||||
v := make([]byte, length)
|
v := make([]byte, length)
|
||||||
_, err = r.Read(v)
|
_, err = r.Read(v)
|
||||||
@ -1003,147 +945,10 @@ func ReadLSFAttribute(r io.ReadSeeker, name string, dt DataType, length uint, ve
|
|||||||
return attr, err
|
return attr, err
|
||||||
|
|
||||||
default:
|
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) {
|
func init() {
|
||||||
var (
|
lsgo.RegisterFormat("lsf", "LSOF", ReadLSF)
|
||||||
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
|
|
||||||
}
|
}
|
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 {
|
type LSMetadata struct {
|
||||||
//public const uint CurrentMajorVersion = 33;
|
// public const uint CurrentMajorVersion = 33;
|
||||||
|
|
||||||
Timestamp uint64 `xml:"-"`
|
Timestamp uint64 `xml:"-"`
|
||||||
Major uint32 `xml:"major,attr"`
|
Major uint32 `xml:"major,attr"`
|
||||||
@ -15,18 +15,12 @@ type LSMetadata struct {
|
|||||||
Build uint32 `xml:"build,attr"`
|
Build uint32 `xml:"build,attr"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type format struct {
|
|
||||||
name, magic string
|
|
||||||
read func(io.Reader) (Resource, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Resource struct {
|
type Resource struct {
|
||||||
Metadata LSMetadata `xml:"version"`
|
Metadata LSMetadata `xml:"version"`
|
||||||
Regions []*Node `xml:"region"`
|
Regions []*Node `xml:"region"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resource) Read(io.Reader) {
|
func (r *Resource) Read(io.Reader) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// public Resource()
|
// public Resource()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user