go-ipp/attribute.go

520 lines
10 KiB
Go
Raw Normal View History

2019-03-10 17:43:47 +00:00
package ipp
import (
"encoding/binary"
"fmt"
"io"
)
const (
sizeInteger = int16(4)
sizeBoolean = int16(1)
)
type AttributeEncoder struct {
writer io.Writer
}
func NewAttributeEncoder(w io.Writer) *AttributeEncoder {
return &AttributeEncoder{w}
}
func (e *AttributeEncoder) Encode(attribute string, value interface{}) error {
tag, ok := AttributeTagMapping[attribute]
if !ok {
return fmt.Errorf("cannot get tag of attribute %s", attribute)
}
switch value.(type) {
2019-03-13 21:54:08 +00:00
case int:
2019-05-29 02:03:47 +00:00
if tag != TagInteger && tag != TagEnum {
2019-05-29 02:08:57 +00:00
return fmt.Errorf("tag for attribute %s does not match with value type", attribute)
2019-03-10 17:43:47 +00:00
}
if err := e.encodeTag(tag); err != nil {
return err
}
if err := e.encodeString(attribute); err != nil {
return err
}
2019-03-13 21:54:08 +00:00
if err := e.encodeInteger(int32(value.(int))); err != nil {
2019-03-10 17:43:47 +00:00
return err
}
2019-03-13 21:54:08 +00:00
case int16:
2019-05-29 02:03:47 +00:00
if tag != TagInteger && tag != TagEnum {
2019-05-29 02:08:57 +00:00
return fmt.Errorf("tag for attribute %s does not match with value type", attribute)
2019-03-13 21:54:08 +00:00
}
if err := e.encodeTag(tag); err != nil {
return err
}
if err := e.encodeString(attribute); err != nil {
return err
}
if err := e.encodeInteger(int32(value.(int16))); err != nil {
return err
}
case int8:
2019-05-29 02:03:47 +00:00
if tag != TagInteger && tag != TagEnum {
2019-05-29 02:08:57 +00:00
return fmt.Errorf("tag for attribute %s does not match with value type", attribute)
2019-03-13 21:54:08 +00:00
}
if err := e.encodeTag(tag); err != nil {
return err
}
if err := e.encodeString(attribute); err != nil {
return err
}
if err := e.encodeInteger(int32(value.(int8))); err != nil {
return err
}
case int32:
2019-05-29 02:03:47 +00:00
if tag != TagInteger && tag != TagEnum {
2019-05-29 02:08:57 +00:00
return fmt.Errorf("tag for attribute %s does not match with value type", attribute)
2019-03-13 21:54:08 +00:00
}
if err := e.encodeTag(tag); err != nil {
return err
}
if err := e.encodeString(attribute); err != nil {
return err
}
if err := e.encodeInteger(value.(int32)); err != nil {
return err
}
case int64:
2019-05-29 02:03:47 +00:00
if tag != TagInteger && tag != TagEnum {
2019-05-29 02:08:57 +00:00
return fmt.Errorf("tag for attribute %s does not match with value type", attribute)
2019-03-13 21:54:08 +00:00
}
if err := e.encodeTag(tag); err != nil {
return err
}
if err := e.encodeString(attribute); err != nil {
return err
}
if err := e.encodeInteger(int32(value.(int64))); err != nil {
return err
}
case []int:
2019-05-29 02:03:47 +00:00
if tag != TagInteger && tag != TagEnum {
2019-05-29 02:08:57 +00:00
return fmt.Errorf("tag for attribute %s does not match with value type", attribute)
2019-03-10 17:43:47 +00:00
}
for index, val := range value.([]int) {
if err := e.encodeTag(tag); err != nil {
return err
}
if index == 0 {
if err := e.encodeString(attribute); err != nil {
return err
}
} else {
if err := e.writeNullByte(); err != nil {
return err
}
}
2019-03-13 21:54:08 +00:00
if err := e.encodeInteger(int32(val)); err != nil {
return err
}
}
case []int16:
2019-05-29 02:03:47 +00:00
if tag != TagInteger && tag != TagEnum {
2019-05-29 02:08:57 +00:00
return fmt.Errorf("tag for attribute %s does not match with value type", attribute)
2019-03-13 21:54:08 +00:00
}
for index, val := range value.([]int16) {
if err := e.encodeTag(tag); err != nil {
return err
}
if index == 0 {
if err := e.encodeString(attribute); err != nil {
return err
}
} else {
if err := e.writeNullByte(); err != nil {
return err
}
}
if err := e.encodeInteger(int32(val)); err != nil {
return err
}
}
case []int8:
2019-05-29 02:03:47 +00:00
if tag != TagInteger && tag != TagEnum {
2019-05-29 02:08:57 +00:00
return fmt.Errorf("tag for attribute %s does not match with value type", attribute)
2019-03-13 21:54:08 +00:00
}
for index, val := range value.([]int8) {
if err := e.encodeTag(tag); err != nil {
return err
}
if index == 0 {
if err := e.encodeString(attribute); err != nil {
return err
}
} else {
if err := e.writeNullByte(); err != nil {
return err
}
}
if err := e.encodeInteger(int32(val)); err != nil {
return err
}
}
case []int32:
2019-05-29 02:03:47 +00:00
if tag != TagInteger && tag != TagEnum {
2019-05-29 02:08:57 +00:00
return fmt.Errorf("tag for attribute %s does not match with value type", attribute)
2019-03-13 21:54:08 +00:00
}
for index, val := range value.([]int32) {
if err := e.encodeTag(tag); err != nil {
return err
}
if index == 0 {
if err := e.encodeString(attribute); err != nil {
return err
}
} else {
if err := e.writeNullByte(); err != nil {
return err
}
}
2019-03-10 17:43:47 +00:00
if err := e.encodeInteger(val); err != nil {
return err
}
}
2019-03-13 21:54:08 +00:00
case []int64:
2019-05-29 02:03:47 +00:00
if tag != TagInteger && tag != TagEnum {
2019-05-29 02:08:57 +00:00
return fmt.Errorf("tag for attribute %s does not match with value type", attribute)
2019-03-13 21:54:08 +00:00
}
for index, val := range value.([]int64) {
if err := e.encodeTag(tag); err != nil {
return err
}
if index == 0 {
if err := e.encodeString(attribute); err != nil {
return err
}
} else {
if err := e.writeNullByte(); err != nil {
return err
}
}
if err := e.encodeInteger(int32(val)); err != nil {
return err
}
}
2019-03-10 17:43:47 +00:00
case bool:
if tag != TagBoolean {
2019-05-29 02:08:57 +00:00
return fmt.Errorf("tag for attribute %s does not match with value type", attribute)
2019-03-10 17:43:47 +00:00
}
if err := e.encodeTag(tag); err != nil {
return err
}
if err := e.encodeString(attribute); err != nil {
return err
}
if err := e.encodeBoolean(value.(bool)); err != nil {
return err
}
case []bool:
if tag != TagBoolean {
2019-05-29 02:08:57 +00:00
return fmt.Errorf("tag for attribute %s does not match with value type", attribute)
2019-03-10 17:43:47 +00:00
}
for index, val := range value.([]bool) {
if err := e.encodeTag(tag); err != nil {
return err
}
if index == 0 {
if err := e.encodeString(attribute); err != nil {
return err
}
} else {
if err := e.writeNullByte(); err != nil {
return err
}
}
if err := e.encodeBoolean(val); err != nil {
return err
}
}
case string:
if err := e.encodeTag(tag); err != nil {
return err
}
if err := e.encodeString(attribute); err != nil {
return err
}
if err := e.encodeString(value.(string)); err != nil {
return err
}
case []string:
for index, val := range value.([]string) {
if err := e.encodeTag(tag); err != nil {
return err
}
if index == 0 {
if err := e.encodeString(attribute); err != nil {
return err
}
} else {
if err := e.writeNullByte(); err != nil {
return err
}
}
if err := e.encodeString(val); err != nil {
return err
}
}
default:
return fmt.Errorf("type %T is not supportet", value)
}
return nil
}
func (e *AttributeEncoder) encodeString(s string) error {
if err := binary.Write(e.writer, binary.BigEndian, int16(len(s))); err != nil {
return err
}
_, err := e.writer.Write([]byte(s))
return err
}
2019-03-13 21:54:08 +00:00
func (e *AttributeEncoder) encodeInteger(i int32) error {
2019-03-10 17:43:47 +00:00
if err := binary.Write(e.writer, binary.BigEndian, sizeInteger); err != nil {
return err
}
return binary.Write(e.writer, binary.BigEndian, i)
}
func (e *AttributeEncoder) encodeBoolean(b bool) error {
if err := binary.Write(e.writer, binary.BigEndian, sizeBoolean); err != nil {
return err
}
return binary.Write(e.writer, binary.BigEndian, b)
}
2020-03-09 11:21:57 +00:00
func (e *AttributeEncoder) encodeTag(t byte) error {
return binary.Write(e.writer, binary.BigEndian, t)
2019-03-10 17:43:47 +00:00
}
func (e *AttributeEncoder) writeNullByte() error {
return binary.Write(e.writer, binary.BigEndian, int16(0))
}
type Attribute struct {
2020-03-09 11:21:57 +00:00
Tag byte
2019-03-13 21:54:08 +00:00
Name string
2019-03-10 17:43:47 +00:00
Value interface{}
}
type AttributeDecoder struct {
reader io.Reader
}
func NewAttributeDecoder(r io.Reader) *AttributeDecoder {
return &AttributeDecoder{r}
}
2020-03-09 11:21:57 +00:00
func (d *AttributeDecoder) Decode(tag byte) (*Attribute, error) {
2019-03-13 21:54:08 +00:00
attr := Attribute{Tag: tag}
2019-03-10 17:43:47 +00:00
name, err := d.decodeString()
if err != nil {
return nil, err
}
attr.Name = name
switch attr.Tag {
case TagEnum, TagInteger:
val, err := d.decodeInteger()
if err != nil {
return nil, err
}
attr.Value = val
case TagBoolean:
val, err := d.decodeBool()
if err != nil {
return nil, err
}
attr.Value = val
case TagDate:
val, err := d.decodeDate()
if err != nil {
return nil, err
}
attr.Value = val
case TagRange:
val, err := d.decodeRange()
if err != nil {
return nil, err
}
attr.Value = val
case TagResolution:
val, err := d.decodeResolution()
if err != nil {
return nil, err
}
attr.Value = val
default:
val, err := d.decodeString()
if err != nil {
return nil, err
}
attr.Value = val
}
return &attr, nil
}
func (d *AttributeDecoder) decodeBool() (b bool, err error) {
if _, err = d.readValueLength(); err != nil {
return
}
if err = binary.Read(d.reader, binary.BigEndian, &b); err != nil {
return
}
return
}
func (d *AttributeDecoder) decodeInteger() (i int, err error) {
if _, err = d.readValueLength(); err != nil {
return
}
2019-03-13 21:54:08 +00:00
var reti int32
if err = binary.Read(d.reader, binary.BigEndian, &reti); err != nil {
2019-03-10 17:43:47 +00:00
return
}
2019-03-13 21:54:08 +00:00
return int(reti), nil
2019-03-10 17:43:47 +00:00
}
2019-03-13 21:54:08 +00:00
func (d *AttributeDecoder) decodeString() (string, error) {
2019-03-10 17:43:47 +00:00
length, err := d.readValueLength()
if err != nil {
return "", err
}
if length == 0 {
return "", nil
}
bs := make([]byte, length)
if _, err := d.reader.Read(bs); err != nil {
return "", nil
}
return string(bs), nil
}
2019-03-13 21:54:08 +00:00
func (d *AttributeDecoder) decodeDate() ([]int, error) {
2019-03-10 17:43:47 +00:00
length, err := d.readValueLength()
if err != nil {
return nil, err
}
is := make([]int, length)
var ti uint8
for i := int16(0); i < length; i++ {
if err = binary.Read(d.reader, binary.BigEndian, &ti); err != nil {
return nil, err
}
is[i] = int(ti)
}
return is, nil
}
func (d *AttributeDecoder) decodeRange() ([]int, error) {
length, err := d.readValueLength()
if err != nil {
return nil, err
}
// initialize range element count (c) and range slice (r)
c := length / 4
r := make([]int, c)
for i := int16(0); i < c; i++ {
var ti int
if err = binary.Read(d.reader, binary.BigEndian, &ti); err != nil {
return nil, err
}
r[i] = ti
}
return r, nil
}
type Resolution struct {
Height int
2019-03-13 21:54:08 +00:00
Width int
Depth uint8
2019-03-10 17:43:47 +00:00
}
func (d *AttributeDecoder) decodeResolution() (res Resolution, err error) {
_, err = d.readValueLength()
if err != nil {
return
}
if err = binary.Read(d.reader, binary.BigEndian, &res.Height); err != nil {
return
}
if err = binary.Read(d.reader, binary.BigEndian, &res.Width); err != nil {
return
}
if err = binary.Read(d.reader, binary.BigEndian, &res.Depth); err != nil {
return
}
return
}
func (d *AttributeDecoder) readValueLength() (length int16, err error) {
err = binary.Read(d.reader, binary.BigEndian, &length)
return
}