Add initial lsb file reading code

This commit is contained in:
lordwelch 2020-11-25 06:57:22 -08:00
parent ce5c1e45b2
commit 1c7c8e5055
3 changed files with 212 additions and 5 deletions

View File

@ -33,10 +33,6 @@ func (ts TranslatedString) MarshalXML(e *xml.Encoder, start *xml.StartElement) e
Name: xml.Name{Local: "version"},
Value: strconv.Itoa(int(ts.Version)),
},
// xml.Attr{
// Name: xml.Name{Local: "value"},
// Value: ts.Value,
// },
)
return nil
}

View File

@ -49,5 +49,7 @@ const (
)
var (
ErrVectorTooBig = errors.New("the vector is too big cannot marshal to an xml element")
ErrVectorTooBig = errors.New("the vector is too big cannot marshal to an xml element")
ErrInvalidNameKey = errors.New("invalid name key")
ErrKeyDoesNotMatch = errors.New("key for this node does not match")
)

209
lsb.go Normal file
View File

@ -0,0 +1,209 @@
package lslib
import (
"encoding/binary"
"io"
"github.com/go-kit/kit/log"
)
type LSBHeader struct {
Signature [4]byte
Size uint32
Endianness uint32
Unknown uint32
Version struct {
Major uint32
Minor uint32
Build uint32
Revision uint32
}
}
type LSBRegion struct {
name string
offset
}
type IdentifierDictionary map[int]string
func ReadLSBDictionary(r io.Reader, endianness binary.ByteOrder) (IdentifierDictionary, error) {
var (
dict IdentifierDictionary
size uint32
err error
)
err = binary.Read(r, endianness, &size)
if err != nil {
return nil, err
}
dict = make(IdentifierDictionary, size)
for i := 0; i < int(size); i++ {
var (
stringlength uint32
key uint32
str string
)
err = binary.Read(r, endianness, &stringlength)
if err != nil {
return dict, err
}
str, err = ReadCString(r, int(stringlength))
if err != nil {
return dict, err
}
err = binary.Read(r, endianness, &key)
if err != nil {
return dict, err
}
dict[key] = str
}
}
func ReadLSBRegions(r io.Reader, d IdentifierDictionary, endianness binary.ByteOrder) (Resource, error) {
var (
nodes []struct {
node *Node
offset uint32
}
nodeCount uint32
err error
)
err = binary.Read(r, endianness, &nodeCount)
if err != nil {
return dict, err
}
nodes = make([]struct{ Node, offset uint32 }, nodeCount)
for _, n := range nodes {
var (
key uint32
ok bool
)
err = binary.Read(r, endianness, &key)
if err != nil {
return dict, err
}
n.node = new(Node)
if n.node.Name, ok = d[int(key)]; !ok {
return Resource{}, ErrInvalidNameKey
}
err = binary.Read(r, endianness, &n.offset)
if err != nil {
return dict, err
}
}
// TODO: Sort
for _, n := range nodes {
var (
key uint32
attrCount uint32
childCount uint32
)
// TODO: Check offset
err = binary.Read(r, endianness, &key)
if err != nil {
return dict, err
}
// if keyV, ok := d[int(key)]; !ok {
// return Resource{}, ErrKeyDoesNotMatch
// }
err = binary.Read(r, endianness, &attrCount)
if err != nil {
return dict, err
}
n.node.Attributes = make([]NodeAttribute, int(attrCount))
err = binary.Read(r, endianness, &nodeCount)
if err != nil {
return dict, err
}
}
}
func readLSBAttribute(r io.Reader) (NodeAttribute, err) {
var (
key uint32
name string
attrType uint32
attr NodeAttribute
)
err = binary.Read(r, endianness, &key)
if err != nil {
return dict, err
}
if name, ok = d[int(key)]; !ok {
return Resource{}, ErrInvalidNameKey
}
err = binary.Read(r, endianness, &attrType)
if err != nil {
return dict, err
}
ReadLSBAttribute(r, name, DataType(attrType))
}
func ReadLSBAttr(r io.ReadSeeker, name string, DT DataType) (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{
Type: DT,
Name: name,
}
err error
l log.Logger
pos int64
)
l = log.With(Logger, "component", "LS converter", "file type", "lsb", "part", "attribute")
pos, err = r.Seek(0, io.SeekCurrent)
switch DT {
case DT_String, DT_Path, DT_FixedString, DT_LSString, DT_WString, DT_LSWString:
var v string
v, err = ReadCString(r, int(length))
attr.Value = v
l.Log("member", name, "read", length, "start position", pos, "value", attr.Value)
pos += int64(length)
return attr, err
case DT_TranslatedString:
var v TranslatedString
v, err = ReadTranslatedString(r, Version, EngineVersion)
attr.Value = v
l.Log("member", name, "read", length, "start position", pos, "value", attr.Value)
pos += int64(length)
return attr, err
case DT_TranslatedFSString:
var v TranslatedFSString
v, err = ReadTranslatedFSString(r, Version)
attr.Value = v
l.Log("member", name, "read", length, "start position", pos, "value", attr.Value)
pos += int64(length)
return attr, err
case DT_ScratchBuffer:
v := make([]byte, length)
_, err = r.Read(v)
attr.Value = v
l.Log("member", name, "read", length, "start position", pos, "value", attr.Value)
pos += int64(length)
return attr, err
default:
return ReadAttribute(r, name, DT, length, l)
}
}