summaryrefslogtreecommitdiff
path: root/binstream.go
diff options
context:
space:
mode:
Diffstat (limited to 'binstream.go')
-rw-r--r--binstream.go114
1 files changed, 114 insertions, 0 deletions
diff --git a/binstream.go b/binstream.go
new file mode 100644
index 0000000..4240517
--- /dev/null
+++ b/binstream.go
@@ -0,0 +1,114 @@
+package binproto
+
+import (
+ "encoding/binary"
+ "errors"
+ "github.com/kch42/kagus"
+ "io"
+ "sync"
+)
+
+// BinstreamReader reads a binary stream from a binproto stream.
+type BinstreamReader struct {
+ r io.Reader
+ err error
+ toread int
+ surMu *sync.Mutex // The mutex of the parent SimpleUnitReader
+}
+
+// Read implements io.Reader.
+func (bsr *BinstreamReader) Read(p []byte) (int, error) {
+ if bsr.err != nil {
+ return 0, bsr.err
+ }
+
+ if bsr.toread == 0 {
+ var _toread int32
+ if err := binary.Read(bsr.r, binary.LittleEndian, &_toread); err != nil {
+ bsr.err = err
+ return 0, err
+ }
+
+ if _toread < 0 {
+ bsr.toread = -1
+ bsr.err = io.EOF
+ bsr.surMu.Unlock() // TODO: Unlock on other conditions?
+ return 0, io.EOF
+ }
+
+ bsr.toread = int(_toread)
+ }
+
+ want := len(p)
+ if bsr.toread < want {
+ want = bsr.toread
+ }
+ n, err := bsr.r.Read(p[:want])
+
+ switch err {
+ case nil:
+ bsr.toread -= n
+ return n, nil
+ case io.EOF:
+ // NOTE: Perhaps we should log this? IDK...
+ bsr.err = errors.New("binstream terminated abnormally")
+ return n, bsr.err
+ }
+
+ bsr.err = err
+ return n, err
+}
+
+// FastForward skips to the end of the stream. Use this, if the data is useless.
+func (bsr *BinstreamReader) FastForward() error {
+ nirvana := kagus.NewNirvanaWriter()
+ _, err := io.Copy(nirvana, bsr)
+ return err
+}
+
+// BinstreamReader writes a binary stream to a binproto stream.
+type BinstreamWriter struct {
+ w io.Writer
+ err error
+}
+
+// Write implements io.Writer.
+func (bsw *BinstreamWriter) Write(p []byte) (int, error) {
+ if bsw.err != nil {
+ return 0, bsw.err
+ }
+
+ l := len(p)
+ if l == 0 {
+ return 0, nil
+ }
+
+ if err := binary.Write(bsw.w, binary.LittleEndian, int32(l)); err != nil {
+ bsw.err = err
+ return 0, err
+ }
+
+ n, err := bsw.w.Write(p)
+ if err != nil {
+ bsw.err = err
+ }
+
+ return n, err
+}
+
+// Close implements io.Closer. You MUST close a stream, so it is terminated properly.
+func (bsw *BinstreamWriter) Close() error {
+ switch bsw.err {
+ case nil:
+ case io.EOF:
+ return nil
+ default:
+ return bsw.err
+ }
+ if err := binary.Write(bsw.w, binary.LittleEndian, int32(-1)); err != nil {
+ return err
+ }
+
+ bsw.err = io.EOF
+ return nil
+}