From 1eff8711d376e9b74991c21564dc32c0c3912824 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20S=C3=B6lver?= Date: Mon, 28 Dec 2020 23:11:21 +0100 Subject: [PATCH] Add integer attribute type. Merges some common code between integer and enum. Enum can now bw a set. Add valuer must take a interface{} in addValue since it can be different types. --- packages/ipp/enum.go | 40 +++++++-------------- packages/ipp/integer.go | 67 +++++++++++++++++++++++++++++++++++ packages/ipp/integer_test.go | 38 ++++++++++++++++++++ packages/ipp/keyword.go | 4 +-- packages/ipp/messages.go | 35 +++++++++++++++++- packages/ipp/mimemediatype.go | 4 +-- packages/ipp/request.go | 2 +- 7 files changed, 156 insertions(+), 34 deletions(-) create mode 100644 packages/ipp/integer.go create mode 100644 packages/ipp/integer_test.go diff --git a/packages/ipp/enum.go b/packages/ipp/enum.go index 334d95c..00e3831 100644 --- a/packages/ipp/enum.go +++ b/packages/ipp/enum.go @@ -1,23 +1,18 @@ package ipp import ( - "bytes" - "encoding/binary" "fmt" - "io" - - log "github.com/sirupsen/logrus" ) type enum struct { - name string - value int32 + name string + values []int32 } -func NewEnum(name string, value int32) *enum { +func NewEnum(name string, values ...int32) *enum { e := new(enum) e.name = name - e.value = value + e.values = values return e } @@ -26,32 +21,21 @@ func (e enum) Name() string { } func (e enum) String() string { - return e.name + ":" + fmt.Sprint(e.value) + return e.name + ":" + fmt.Sprint(e.values) } func (e *enum) valueTag() tag { return enumValueTag } -func (e *enum) unmarshal(byteStream io.Reader) { - log.Warn("Unmarshal of enum is not implemented yet") +func (e *enum) size() int { + return 9 + len(e.name) +} + +func (i *enum) addValue(v interface{}) { + i.values = append(i.values, v.(int32)) } func (e *enum) marshal() []byte { - l := 3 + len(e.name) + 6 - b := make([]byte, 0, l) - buf := bytes.NewBuffer(b) - buf.WriteByte(byte(enumValueTag)) - binary.Write(buf, binary.BigEndian, uint16(len(e.name))) - buf.WriteString(e.name) - binary.Write(buf, binary.BigEndian, uint16(4)) - binary.Write(buf, binary.BigEndian, e.value) - return buf.Bytes() -} - -func (e *enum) size() int { - l := 1 + 4 // The attribute tag + 2 lengths - l += len(e.name) - l += 4 - return l + return marshalInteger(enumValueTag, e.name, e.values) } diff --git a/packages/ipp/integer.go b/packages/ipp/integer.go new file mode 100644 index 0000000..b75df60 --- /dev/null +++ b/packages/ipp/integer.go @@ -0,0 +1,67 @@ +package ipp + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" +) + +type integer struct { + name string + values []int32 +} + +func NewInteger(name string, values ...int32) *integer { + e := new(integer) + e.name = name + e.values = values + return e +} + +func (i integer) Name() string { + return i.name +} + +func (i integer) String() string { + return i.name + ":" + fmt.Sprint(i.values) +} + +func (i *integer) valueTag() tag { + return integerValueTag +} + +func (i *integer) size() int { + return 9 + len(i.name) // The attribute tag + 2 lengths +} + +func (i *integer) addValue(v interface{}) { + i.values = append(i.values, v.(int32)) +} + +func (i *integer) marshal() []byte { + return marshalInteger(integerValueTag, i.name, i.values) +} + +func marshalInteger(t tag, name string, values []int32) []byte { + l := 9 + len(name) + b := make([]byte, 0, l) + buf := bytes.NewBuffer(b) + buf.WriteByte(byte(integerValueTag)) + binary.Write(buf, binary.BigEndian, uint16(len(name))) + buf.WriteString(name) + binary.Write(buf, binary.BigEndian, uint16(4)) + binary.Write(buf, binary.BigEndian, values[0]) + for _, v := range values[1:] { + buf.WriteByte(byte(integerValueTag)) + binary.Write(buf, binary.BigEndian, uint16(0)) + binary.Write(buf, binary.BigEndian, uint16(4)) + binary.Write(buf, binary.BigEndian, v) + } + return buf.Bytes() +} + +func unmarshalSingleInteger(byteStream io.Reader) (string, int32) { + name, data := unmarshalSingleAttribute(byteStream) + return name, int32(binary.BigEndian.Uint32(data)) +} diff --git a/packages/ipp/integer_test.go b/packages/ipp/integer_test.go new file mode 100644 index 0000000..142d1a6 --- /dev/null +++ b/packages/ipp/integer_test.go @@ -0,0 +1,38 @@ +package ipp + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestUnMarshalSinglePositiveInteger(T *testing.T) { + testdata := []byte{ + 0x00, 0x04, + 0x66, 0x6c, 0x6f, 0x70, //flop + 0x00, 0x04, + 0x00, 0x0, 0x0, 0x4, + } + + buf := bytes.NewBuffer(testdata) + + n, v := unmarshalSingleInteger(buf) + assert.Equal(T, "flop", n, "Should be equal") + assert.Equal(T, int32(4), v, "Should be equal") +} + +func TestUnMarshalSingleNegativeInteger(T *testing.T) { + testdata := []byte{ + 0x00, 0x04, + 0x66, 0x6c, 0x6f, 0x70, //flop + 0x00, 0x04, + 0xff, 0xff, 0xff, 0xfc, + } + + buf := bytes.NewBuffer(testdata) + + n, v := unmarshalSingleInteger(buf) + assert.Equal(T, "flop", n, "Should be equal") + assert.Equal(T, int32(-4), v, "Should be equal") +} diff --git a/packages/ipp/keyword.go b/packages/ipp/keyword.go index 0de6b25..b5c0057 100644 --- a/packages/ipp/keyword.go +++ b/packages/ipp/keyword.go @@ -31,7 +31,7 @@ func (k *keyWord) marshal() []byte { return k.sos.marshal() } -func (k *keyWord) addValue(v string) { - k.sos.AddValue(v) +func (k *keyWord) addValue(v interface{}) { + k.sos.AddValue(v.(string)) } diff --git a/packages/ipp/messages.go b/packages/ipp/messages.go index 8d4b929..93133ef 100644 --- a/packages/ipp/messages.go +++ b/packages/ipp/messages.go @@ -100,6 +100,19 @@ func (v versionNumber) String() string { return fmt.Sprintf("%x.%x", vn&0xff00>>8, vn&0x00ff) } +func unmarshalSingleAttribute(byteStream io.Reader) (string, []byte) { + var length uint16 + binary.Read(byteStream, binary.BigEndian, &length) + attributeName := make([]byte, length) + if length > 0 { + binary.Read(byteStream, binary.BigEndian, attributeName) + } + binary.Read(byteStream, binary.BigEndian, &length) + attributeValue := make([]byte, length) + binary.Read(byteStream, binary.BigEndian, attributeValue) + return string(attributeName), attributeValue +} + func unmarshalSingleValue(byteStream io.Reader) (string, string) { var length uint16 binary.Read(byteStream, binary.BigEndian, &length) @@ -137,7 +150,7 @@ type attributes struct { job []Attribute } -func (a *attributes) String() string{ +func (a *attributes) String() string { s := " OperationAttributes" + "\n" for _, a := range a.operation { s = s + fmt.Sprintf(" %v (%v)\n", a, a.valueTag()) @@ -231,6 +244,26 @@ func UnMarshalAttributues(body io.Reader) *attributes { lastAddValuer = m } log.Debugf("%v : %v", name, value) + case integerValueTag: + name, value := unmarshalSingleInteger(body) + if name == "" { + lastAddValuer.addValue(value) + } else { + i := NewInteger(name, value) + a.addAttribute(currentAttributeGroup, i) + lastAddValuer = i + } + log.Debugf("%v : %v", name, value) + case enumValueTag: + name, value := unmarshalSingleInteger(body) + if name == "" { + lastAddValuer.addValue(value) + } else { + e := NewEnum(name, value) + a.addAttribute(currentAttributeGroup, e) + lastAddValuer = e + } + log.Debugf("%v : %v", name, value) case jobAttributes: log.Debug("Start job attributes") currentAttributeGroup = jobAttributes diff --git a/packages/ipp/mimemediatype.go b/packages/ipp/mimemediatype.go index 7043224..6788489 100644 --- a/packages/ipp/mimemediatype.go +++ b/packages/ipp/mimemediatype.go @@ -31,6 +31,6 @@ func (m *mimeMediaType) marshal() []byte { return m.sos.marshal() } -func (m *mimeMediaType) addValue(v string) { - m.sos.AddValue(v) +func (m *mimeMediaType) addValue(v interface{}) { + m.sos.AddValue(v.(string)) } diff --git a/packages/ipp/request.go b/packages/ipp/request.go index 3363bbc..3adc75f 100644 --- a/packages/ipp/request.go +++ b/packages/ipp/request.go @@ -33,7 +33,7 @@ func (h ippMessageHeader) String() string { } type AddValuer interface { - addValue(string) + addValue(interface{}) } type Request struct {