-
Notifications
You must be signed in to change notification settings - Fork 200
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Go language support #146
Comments
Thanks for the suggestion! Let's go with our checklist. I presume you're acquainted with KS, so going to section 2. What would be Go equivalents of the following:
What are the basic Go coding standards / universally accepted practices that we'll follow (also as per checklist, section 2.4)? |
just taking a stab at this -- KS
also take a look at https://github.com/virtao/GoTypeBytes/blob/master/typeBytes.go for conversion from and to these types directly from bytes. KS 'stream': I believe these are the packages required but I have not experimented with this yet :)
A slice is a dynamically sized array of type. https://golang.org/ref/spec#Slice_types fields := []int{1,2,3}
Not sure what you want here. There is a key value hash map in Go. So if key is 'field' then: fields := make(map[string]interface{}) this would create a kv map with a string as the key and illustration of slice and map: https://play.golang.org/p/K1gaQ1zhHg
is this structs? https://golang.org/ref/spec#Struct_types
https://github.com/virtao/GoTypeBytes/blob/master/typeBytes.go const (
INT_SIZE int = int(unsafe.Sizeof(0))
UINT_SIZE int = int(unsafe.Sizeof(uint(0)))
FLOAT32_SIZE int = 4
FLOAT64_SIZE int = 8
DEFAULT_ENDIAN int = 0
BIG_ENDIAN int = 1
LITTLE_ENDIAN int = 2
) |
This list is also useful, but the primary question was how to present KS concept of "type". In the majority of target languages, it corresponds to a class. Reading a How all that maps to Go concepts and practices?
Um, please don't take offense, but may be you'd want to get slightly more familiar with KS concepts, such as seq, instances, enums, nested types, etc? |
KS type seems to follow: https://golang.org/ref/spec#Types There are usually no getter setter methods. They are treated as a variable but can also be given methods: https://gobyexample.com/methods gives an example of this but with a more complex type, a struct. Yet it is still a 'type' you can see in it's declaration. Give me a bit longer, I am new to KS and I need to read more. Thanks. |
Yeah, that should be useful as well. We could use that for "parse instances" (which define some out-of-sequence data located at some arbitrary offset in the stream) and "value instances" (which are basically values, calculated using other available attributes).
No rush, take your time :) Also, you might be interested in announcing this work on support of Go in KS in some Go communities. I've heard that they are very friendly and open to new things — so, chances are, we'll get more people interested in this support contributing ideas. N heads is better than one, anyway :) |
I'll post something up on the reddit :) Thanks! |
I saw this on Reddit and am suddenly interested in Kaitai. I am familiar with Go, but not with Kaitai or scala. I have read through the documentation about adding support for a new language and believe it should be pretty straightforward to get started with a prototype for Go. Here are my thoughts on how the representation should be in Go (also a basic introduction to some Go concepts):
I tried prototyping the interface with an The API for the protobuf encoding and decoding might be interesting (it's also a little bit confusing when you first look at it because of the way the decoding references autogenerated metadata fields): https://godoc.org/github.com/golang/protobuf/proto Here is an example of how I might generate code: What are the next steps? Explicitly following the "new language" document? @GreyCat Are you available to write the scala code generation if a reasonable template can be provided? I can work more on the Streaming API. |
Here is what the streaming API might look like in Go: https://play.golang.org/p/O1vKDZroZ1 The io.ReadSeeker could be either a an os.File or a bytes.Reader |
@tarm Thanks for your interest!
Judging by the examples, probably you mean that type names, sequence attribute names and enums-as-consts should be UpperCamelCase. What about instances?
Ok, not a problem.
I believe that goes well with
Thanks, it makes much more sense now! I believe that stuff like that: nn, err := e.TrackTitle.Unmarshal(b[n:])
n += nn
if err != nil {
return n, err
} can be incapsulated into some sort of KaitaiStream-like library?
We need:
Then I add new target
Sure, I'm totally up to it ;) |
Cool! I'd like to start a Go runtime repository, but we need to choose name that Go will be referred to everywhere in KS. I guess there are two alternatives - shall we use
By the way, what about reading performance when using |
Instances could also be represented as methods on the top level type. (I'm not familiar with how common they are and what their uses are). For naming, I think Is the generated code typically standalone (like the Unmarshal example I gave) or does it typically use metadata/reflection and runtime assistance from the Stream object? Obviously either is possible, but one is probably easier from the existing code generation structure. If reflection is typical, then it might be possible to make something pretty clean looking by putting all the metadata into field attributes that Go calls
OK let me work more on hello world. |
BTW, could you point me to what example generated code looks like? Hello world python for example. I see the unit test in the spec directory, but haven't seen generated code. |
I've created https://github.com/kaitai-io/kaitai_struct_go_runtime — feel free to start runtime project there. Would you be ok with MIT license, as most our other runtimes use?
If I understand properly, generally, there is no metadata/reflection usage inside generated code to maximize performance / efficiency. There is no "parsing state" (except for the state that Stream object provides), we try to minimize various conditions / checks.
That's an interesting feature, but that looks more like "an interpreter of provided metadata, encoded in tags", not "compiler". Generally, "compiler" approach is more efficient.
You can use # This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
import array
import struct
import zlib
from enum import Enum
from pkg_resources import parse_version
from kaitaistruct import __version__ as ks_version, KaitaiStruct, KaitaiStream, BytesIO
if parse_version(ks_version) < parse_version('0.7'):
raise Exception("Incompatible Kaitai Struct Python API: 0.7 or later is required, but you have %s" % (ks_version))
class HelloWorld(KaitaiStruct):
def __init__(self, _io, _parent=None, _root=None):
self._io = _io
self._parent = _parent
self._root = _root if _root else self
self.one = self._io.read_u1() |
@tarm The following issues contain answers on some questions: |
Thanks for the pointers! I've made a little progress and would like to share and get feedback: Runtime stream library: https://github.com/tarm/kaitai_struct_go_runtime/blob/master/kaitai/stream.go
Hello world manual compile and a unit test for it: I do not know what the "Kaitai Struct" base type/interface would need to be and would like to explore some examples to get a feeling. I think next steps for me would be to manually convert a few more .ksy files that have more features. Any suggested progression from Hello World? Perhaps something with a parent reference and something with instances? Are there plans to have an interface to write files from structures? Naively it seems like all the operations could just be done in reverse. |
Ok, first I'm gonna answer questions on runtime API:
Generally, there are two approaches to EOF handling in this world:
Given that we inevitably deal with languages that have both schemes, we had to choose a single common pattern here, and we've chosen the first one. Languages like C++ and Python, that rely on the second pattern, will thus have slightly more complex implementations - like this one in C++ or this one in Python. Probably we'll have to implement this with Go as well.
What's the difference between a
Generally, it is supposed to read a bitset / bit array data type with given number of bits. See #112 for more details, it's right now in planning stage. Probably we'll use BitSet for Java, BitArray for .NET, std::bitset for C++, etc.
I see that you've implemented older v0.6 API here — probably because I've referred you to some outdated documentation, and I'm truly sorry for that. Modern 0.7 API does not have distinct string reading methods, instead it uses byte array reading methods (
Generally, it is supposed to split given byte array into groups of
Using default
|
Generally,
Normally, they operate at copies and return them, but it might be customized for particular target language.
It's clearly a terminology question ;) I see that Go's understand of "stream" term implies that it's something that is not seekable and you may be able only to rewind it with some extra pain (doing that buffering). In other languages (and more or less in KS), "stream" is used as a term that just describes an abstraction over generic reading / writing API that deals with files and in-memory byte arrays. Thus it's perfectly fine to have a "seekable stream": for example, Ruby's IO or Python's io work in that paradigm.
Yes, it's more or less so.
Sure, here's probably the minimal one: https://github.com/kaitai-io/kaitai_struct_tests/blob/master/formats/instance_std.ksy For example, in Python it generates: @property
def header(self):
if hasattr(self, '_m_header'):
return self._m_header if hasattr(self, '_m_header') else None
_pos = self._io.pos()
self._io.seek(2)
self._m_header = (self._io.read_bytes(5)).decode(u"ASCII")
self._io.seek(_pos)
return self._m_header if hasattr(self, '_m_header') else None
That's up to you to decide as Go expert ;) The general requirement is that parsing many real-life file formats (and even some network packets, like DNS) requires seeking. If you feel like providing several implementations (one that to be used when seeking is required and one that can be used for simpler types with no seeking) — sure, why not :) The only language that might have benefited from such approach so far was probably Java (it has unseekable stuff like |
Happy to read along :) 👍 |
@tarm I've started GoCompiler, and went over your rendition of hello_world.go. I have a few questions:
seq:
- id: foo1
type: u1
instances:
foo2:
pos: 1234
type: u1 You can access both So, shall we add some field (traditionally we call it
Normally, we allow to supply |
Is this anything you would want some help with? I stumbled across this project on a whim after having implemented decoders for a bunch of legacy game file formats in Go. I would be very interested in avoiding future tedium by defining future data spec in Kaitai, and letting a code generated codex do the rest of my work. Is it possible to author a per-language emitter as a plugin from IDL in a native language à la Protocol Buffers? |
@matttproud Please follow the discussion in this issue. I've asked some questions and I'm still waiting for Go expert opinions on them. It's not like I can move this whole thing alone. Unfortunately, it looks like that we've lost original proposers and experts @5k3105 and @tarm :(
If I understood you correctly, this is already like that. All we need to write to support a certain target language is |
Usually Unmarshal should be something like:
The streaming api could be something like:
Similar in json That way the decoder handles the stream and the relations (parent, root) etc. This Go way pretty much contradicts the Kaitai way of storing the stream and relations in every object. |
To just add relations (IO, parent, root) to @tarm 's hello world see https://github.com/cugu/kaitai_struct_go/blob/master/hello_world.go and https://github.com/cugu/kaitai_struct_go/blob/master/struct.go |
@cugu My main question is whether The problem is that KS generally is not that simple, and you don't have a luxury of parsing anything in one function and just going in with approach "I'll call this one can and after that I'm guaranteed to have all the fields of structure X filles in". There is lazy parsing, and it is especially important for "parse instances": it is used to parse multi-terabyte file systems without loading everything into memory at once. Normally, you just generate something like that in languages like Java: public IndexEntry index() {
if (this.index != null)
return this.index;
long _pos = this._io.pos();
this._io.seek(indexOffset());
this.index = new IndexEntry(this._io, this, _root);
this._io.seek(_pos);
return this.index;
} Note that it makes heavy use of I see that you've proposed to add |
@GreyCat Thanks for all the background and suggestions. It's very helpful. Sorry for being MIA, $DAYJOB has kept me busy. I have been thinking about it though! Sorry, I have not yet updated the stream api with your comments, but the comments and changes to the stream API seem straightforward. Go does not have python's As @cugu mentioned, there is definitely a preference in Go to have data types be flat and add functionality using methods. That is different than the standard KS way. Obviously that does not work for terabyte filesystem parsing. However, if you have to parse a terabyte filesystem, you could still use the auto generated code but only call the "inner" unmarshal functions and manually write code to jump or iterate through as needed for your business logic. As a Go user, my preference would be to have the Unmarshal() method and not embed the KS struct into each object. I've been thinking more about the parent and root references as well. (This suggestions presumes unmarshal). You could pass in the needed leaf fields into Unmarshal() as extra arguments. That means more bookkeeping for the code generator because all the intermediate Unmarshal functions would also need those arguments, but would be easy to understand and satisfy the type checker. I just pushed an example for nav_parent: Obviously that is also different from the standard KS way as well. Go is statically typed enough to make the parent references a little painful otherwise. Doing it the more typically KS way would be easy with root, but trickier with parent references if a type could have parents of different types. How is that handled in the generated code for other statically typed languages? Is the .ksy format statically typed enough for that to not be a problem? Finally, in nav_parent, I had to add an |
Ok, I start to understand that Go is a pretty low-level language, as I go ;) It's not terribly hard to do these distinctions automatically for generated code (i.e.
It is possible, but it would basically require end-user to keep references to root, parent and io somewhere, and pass it along to every instance attribute call, i.e.
Parent type is inferred in pre-compile-time in ksc, and is known since then. For example, in Java, nav_parent.ksy is compiled to: public class NavParent extends KaitaiStruct {
public NavParent(KaitaiStream _io, KaitaiStruct _parent, NavParent _root) { /* ... */ }
public static class HeaderObj extends KaitaiStruct {
public HeaderObj(KaitaiStream _io, NavParent _parent, NavParent _root) { /* ... */ }
}
public static class IndexObj extends KaitaiStruct {
public IndexObj(KaitaiStream _io, NavParent _parent, NavParent _root) { /* ... */ }
}
public static class Entry extends KaitaiStruct {
public Entry(KaitaiStream _io, IndexObj _parent, NavParent _root) { /* ... */ }
}
} Note that both
By design decision, KS expression language assumes that there's only a single one-size-fits-all integer type in a language (which is not that far from being true in many cases) and doesn't track complex integer type implicit casts, which are very different in various languages. Implementation of stuff like
There's no overflow checking everywhere, and this is almost mostly by design. Current approachin vast majority of existing situations and we don't really aim to implement 100% compliant exact emulator of some particular language in all other languages. We just say that it's "undefined behavior" (which is pretty much the standard excuse in C/C++ standard, so we're not alone here either). |
I guess we can leave the remaining ones, as they are used as numbers, not as data bytes. If this makes sense to you. |
Currently, GoCompiler generates But, generally, I don't have a strong opinion on this one, this is obviously more of a taste thing. |
I would personally keep it as it is. Another reference: https://golang.org/pkg/builtin/#byte A suggestions for switches: https://gist.github.com/cugu/8a724fbd91f4a23d6189be7c75c9d4a3 |
|
Basical enum support is in, CI completion rating is up to 32%. Note that I had to add namespacing prefixes to both "enum" type names and to individual constants, resulting in something like this enum_0.go. |
Applied some more assorted fixes, CI rating is up to 39%. @cugu I think that bit-level reading generation is now correct and ready to be tested, but it turned out that runtime implementation is very strange and it just does an infinite loop. Could you take a look? |
@GreyCat Nice! And here is a patch for the bit read: kaitai-io/kaitai_struct_go_runtime#8 |
@cugu JFYI, latest changes in runtime broke it. Namely, here func (k *Stream) ReadBytesTerm(term byte, includeTerm, consumeTerm, eosError bool) ([]byte, error) {
r := bufio.NewReader(k)
- pos, err := k.Pos()
- if err != nil {
- return nil, err
- }
slice, err := r.ReadBytes(term) However, if I'll just delete it, it still causes panic during the tests:
|
Ok, but it still results in panic, and thus produces no test report. |
Done a few more passes, Go rating is up to 41%. Major things to do/fix left:
Anyone wants to take on any of this list? |
kaitai-io/kaitai_struct_tests#47 This allows panicking tests. |
Just a little update: thanks to @jchv contributions, Go support rating is 41% => 53%. |
Can Go be added to https://kaitai.io/repl/index.html ? (perhaps with a warning that it is not 100% yet) |
@tomberek Please take a look https://ide.kaitai.io/devel/. It's the development version of the awesome Kaitai Web IDE. which is currently IMHO the best way to write and debug the KSY files. It has a number of useful features which really simplify the development. And it is the development version, which means that it gets updated every time someone pushes a commit to the https://github.com/kaitai-io/kaitai_struct_compiler repo, so you can be sure that you're always using the latest version without making any effort. The Web IDE supports generating the parser to an arbitrary target language, but I see there isn't Go option as well. But I can add it if you want, it should be relatively easy. The REPL tool is no longer actively supported at the moment. It has compiler of version 0.7, but the latest is 0.9 (it isn't yet released, but hopefully will be soon), so it's not supporting a number of useful features introduced since then (and I think most formats from the format gallery use some of them, so you can't compile it here). And the plain The best would be to delete the REPL completely, because it's just confusing the new users, when they get there via the call-to-action link |
And if you want to track the development progress in Go, you can watch our CI (Continuous Integration) dashboard. There are the results of all tests which were created over the time. Each test consists of a test KSY format (in this folder), which uses a special feature or tests a known bug. All formats are compiled to all target languages using the latest compiler. The generated parsers are used on some prepared binary file and the parsed data structure is checked with unit test assertions (in each language separately). In case you are interested, here is the detailed description of the CI infrastructure. |
@GreyCat really wonderful work on starting to implement Go support in Kaitai Struct! How far along is it currently? I had a look at the CI dashboard that @generalmimon posted (thanks @generalmimon!) and it seems Go it not yet listed here. Cheers, |
Sorry for the confusion. That's my fault, yesterday I ported test For testing we have partial builders in some languages, which are able to recover even if one test is invalid. Some efforts to restore the build in case of failure can be seen also in the builder for Go, but it didn't work in this case for some reason. I'll revert the change so you can look at the results, until this issue is resolved. |
I can say that the Go generator works well enough for simple cases. My use case is a binary format of simple graph structure. Thanks for the great work! |
@generalmimon, thanks for the explanation and on working on the builders! Now Go seems to be up and running again, with a rating of Great job! |
This comment has been minimized.
This comment has been minimized.
ImportsDoes the Go version of Kaitai support imports yet? It seem partially supported. However, it is possible to run into issue with an incorrect root type, which causes build failures. Details provided below. I found an issue when using imports with the generated Go parser when using imports in Example taken from the Kaitai Struct User Guide (https://doc.kaitai.io/user_guide.html#meta-imports): Contents of meta:
id: date
seq:
- id: year
type: u2le
- id: month
type: u2le
- id: day
type: u2le Contents of meta:
id: filelist
# this will import "date.ksy"
imports:
- date
seq:
- id: entries
type: entry
repeat: eos
types:
entry:
seq:
- id: filename
type: strz
encoding: ASCII
# just use "date" type from date.ksy as if it was declared in
# current file
- id: timestamp
type: date
# you can access its members too!
- id: historical_data
size: 160
if: timestamp.year < 1970 Commands used to compile:
If we now try to compile the generated Go package, we get the following error:
The contents of the generated Go source files are as follows. Contents of // This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
package foo
import "github.com/kaitai-io/kaitai_struct_go_runtime/kaitai"
type Date struct {
Year uint16
Month uint16
Day uint16
_io *kaitai.Stream
_root *Date
_parent interface{}
}
func (this *Date) Read(io *kaitai.Stream, parent interface{}, root *Date) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp1, err := this._io.ReadU2le()
if err != nil {
return err
}
this.Year = uint16(tmp1)
tmp2, err := this._io.ReadU2le()
if err != nil {
return err
}
this.Month = uint16(tmp2)
tmp3, err := this._io.ReadU2le()
if err != nil {
return err
}
this.Day = uint16(tmp3)
return err
} Contents of // This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
package foo
import "github.com/kaitai-io/kaitai_struct_go_runtime/kaitai"
type Filelist struct {
Entries []*Filelist_Entry
_io *kaitai.Stream
_root *Filelist
_parent interface{}
}
func (this *Filelist) Read(io *kaitai.Stream, parent interface{}, root *Filelist) (err error) {
this._io = io
this._parent = parent
this._root = root
for {
tmp1, err := this._io.EOF()
if err != nil {
return err
}
if tmp1 {
break
}
tmp2 := new(Filelist_Entry)
err = tmp2.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Entries = append(this.Entries, tmp2)
}
return err
}
type Filelist_Entry struct {
Filename string
Timestamp *Date
HistoricalData []byte
_io *kaitai.Stream
_root *Filelist
_parent *Filelist
}
func (this *Filelist_Entry) Read(io *kaitai.Stream, parent *Filelist, root *Filelist) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp3, err := this._io.ReadBytesTerm(0, false, true, true)
if err != nil {
return err
}
this.Filename = string(tmp3)
tmp4 := new(Date)
err = tmp4.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Timestamp = tmp4
if (this.Timestamp.Year < 1970) {
tmp5, err := this._io.ReadBytes(int(160))
if err != nil {
return err
}
tmp5 = tmp5
this.HistoricalData = tmp5
}
return err
} Change to fix buildu@x220 ~/D/g/s/g/s/d/f/foo> git diff
diff --git a/foo/date.go b/foo/date.go
index 8ab7edc..66c0b28 100644
--- a/foo/date.go
+++ b/foo/date.go
@@ -9,11 +9,11 @@ type Date struct {
Month uint16
Day uint16
_io *kaitai.Stream
- _root *Date
+ _root interface{}
_parent interface{}
}
-func (this *Date) Read(io *kaitai.Stream, parent interface{}, root *Date) (err error) {
+func (this *Date) Read(io *kaitai.Stream, parent interface{}, root interface{}) (err error) {
this._io = io
this._parent = parent
this._root = root
diff --git a/foo/filelist.go b/foo/filelist.go
index d510127..453d44f 100644
--- a/foo/filelist.go
+++ b/foo/filelist.go
@@ -7,11 +7,11 @@ import "github.com/kaitai-io/kaitai_struct_go_runtime/kaitai"
type Filelist struct {
Entries []*Filelist_Entry
_io *kaitai.Stream
- _root *Filelist
+ _root interface{}
_parent interface{}
}
-func (this *Filelist) Read(io *kaitai.Stream, parent interface{}, root *Filelist) (err error) {
+func (this *Filelist) Read(io *kaitai.Stream, parent interface{}, root interface{}) (err error) {
this._io = io
this._parent = parent
this._root = root
@@ -39,11 +39,11 @@ type Filelist_Entry struct {
Timestamp *Date
HistoricalData []byte
_io *kaitai.Stream
- _root *Filelist
+ _root interface{}
_parent *Filelist
}
-func (this *Filelist_Entry) Read(io *kaitai.Stream, parent *Filelist, root *Filelist) (err error) {
+func (this *Filelist_Entry) Read(io *kaitai.Stream, parent *Filelist, root interface{}) (err error) {
this._io = io
this._parent = parent
this._root = root Perhaps there is a better solution than using |
Parametric typesI tried to use parametric types today, but it seems that at least part of the Go implementation is not yet complete. The parameter uses are generated properly, but the instantiation and definition of the type parameters are now. An example taken from the Kaitai Struct User Guide follows below (https://doc.kaitai.io/user_guide.html#param-types): Contents of meta:
id: params
endian: le
types:
kv_pair:
params:
- id: len_key
type: u2
seq:
- id: key
size: len_key
type: str
encoding: ASCII
- id: value
type: strz
encoding: ASCII
seq:
- id: short_pairs
type: kv_pair(3)
repeat: expr
repeat-expr: 0x100
- id: long_pairs
type: kv_pair(8)
repeat: expr
repeat-expr: 0x100 Commands used to compile:
If we now try to compile the generated Go package, we get the following error:
The contents of the generated Go source files are as follows. Contents of // This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
package p
import "github.com/kaitai-io/kaitai_struct_go_runtime/kaitai"
type Params struct {
ShortPairs []*Params_KvPair
LongPairs []*Params_KvPair
_io *kaitai.Stream
_root *Params
_parent interface{}
}
func (this *Params) Read(io *kaitai.Stream, parent interface{}, root *Params) (err error) {
this._io = io
this._parent = parent
this._root = root
this.ShortPairs = make([]*Params_KvPair, 256)
for i := range this.ShortPairs {
tmp1 := new(Params_KvPair)
err = tmp1.Read(this._io, this, this._root)
if err != nil {
return err
}
this.ShortPairs[i] = tmp1
}
this.LongPairs = make([]*Params_KvPair, 256)
for i := range this.LongPairs {
tmp2 := new(Params_KvPair)
err = tmp2.Read(this._io, this, this._root)
if err != nil {
return err
}
this.LongPairs[i] = tmp2
}
return err
}
type Params_KvPair struct {
Key string
Value string
_io *kaitai.Stream
_root *Params
_parent *Params
}
func (this *Params_KvPair) Read(io *kaitai.Stream, parent *Params, root *Params) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp3, err := this._io.ReadBytes(int(this.LenKey))
if err != nil {
return err
}
tmp3 = tmp3
this.Key = string(tmp3)
tmp4, err := this._io.ReadBytesTerm(0, false, true, true)
if err != nil {
return err
}
this.Value = string(tmp4)
return err
} Suggested solutionWhen generating parametric types, also generate a constructor function taking said parameters. E.g. for the example above. u@x220 ~/D/g/s/g/s/d/f/p> diff -u params.go.orig params.go
--- params.go.orig 2020-02-21 15:23:40.420027468 +0100
+++ params.go 2020-02-21 15:25:44.633361203 +0100
@@ -38,6 +38,7 @@
return err
}
type Params_KvPair struct {
+ LenKey int // added parameter type.
Key string
Value string
_io *kaitai.Stream
@@ -45,6 +46,12 @@
_parent *Params
}
+func NewParams_KVPair(lenKey int) *Params_KvPair {
+ return &Params_KvPair{
+ LenKey: lenKey, // parameter type set when invoking constructor function.
+ }
+}
+
func (this *Params_KvPair) Read(io *kaitai.Stream, parent *Params, root *Params) (err error) {
this._io = io
this._parent = parent |
I believe the appropriate lower level libraries to use will be:
https://golang.org/pkg/bytes/
https://golang.org/pkg/os/
general outline of a go program. Taken from a sprite editor I was making for it's 'low levelness'.
github.com/virtao/GoTypeBytes has a lot of functions on bytes that seem applicable for this library.
The text was updated successfully, but these errors were encountered: