package ipp import ( "encoding/binary" "fmt" "io" log "github.com/sirupsen/logrus" ) type ippRequestHeader struct { versionNumber versionNumber operationId operationId requestId uint32 } func (h *ippRequestHeader) marshal(byteStream io.Reader) { binary.Read(byteStream, binary.BigEndian, &h.versionNumber) binary.Read(byteStream, binary.BigEndian, &h.operationId) binary.Read(byteStream, binary.BigEndian, &h.requestId) } func (h ippRequestHeader) String() string { return fmt.Sprintf("Version number: %v Operation Id: %v Request Id: %v", h.versionNumber, h.operationId, h.requestId) } type Attribute interface { valueTag() tag //unmarshal(io.Reader) marshal() []byte size() int } type Request struct { header ippRequestHeader operationAttributes map[string]Attribute jobAttributes map[string]Attribute printerAttributes map[string]Attribute } func NewRequest() *Request { r := new(Request) r.operationAttributes = make(map[string]Attribute) r.jobAttributes = make(map[string]Attribute) r.printerAttributes = make(map[string]Attribute) return r } func (r Request) String() string { s := r.header.String() + "\n" + " OperationAttributes" + "\n" for _, a := range r.operationAttributes { s = s + fmt.Sprintf(" %v (%v)\n", a, a.valueTag()) } return s } func (r *Request) UnMarshal(body io.Reader) { r.header.marshal(body) log.Infof("Header %v", r.header) var tag tag err := binary.Read(body, binary.BigEndian, &tag) if err != nil { log.Error(err.Error()) } log.Infof("got tag - %v", tag) if tag == operationAttributes { var lastKeyword *keyWord nextoperationattr: for tag != endOfAttributes { err = binary.Read(body, binary.BigEndian, &tag) if err != nil { log.Error(err.Error()) } log.Infof("Value tag - %v", tag) switch tag { case endOfAttributes: err = binary.Read(body, binary.BigEndian, &tag) if err == io.EOF { // No more data return } if err != nil { log.Error(err.Error()) } log.Infof("got tag - %v", tag) err = binary.Read(body, binary.BigEndian, &tag) if err != nil { log.Error(err.Error()) } log.Infof("got tag - %v", tag) break nextoperationattr case charsetValueTag: c := NewCharSetValue("", "") c.unmarshal(body) r.operationAttributes[c.name] = c log.Infof("%v %v", c.name, c.value) case uriValueTag: u := newUriValue("", "") u.unmarshal(body) r.operationAttributes[u.name] = u log.Infof("%v %v", u.name, u.value) case naturalLanguagageValueTag: n := newNaturalLanguagage("", "") n.unmarshal(body) r.operationAttributes[n.name] = n log.Infof("%v %v", n.name, n.value) case keyWordValueTag: name, value := unmarshalSingleValue(body) if name == "" { lastKeyword.addValue(value) } else { k := newKeyWord() k.name = name k.addValue(value) r.operationAttributes[k.name] = k lastKeyword = k } default: log.Errorf("Unsupported tag %v", tag) } } log.Infof("Value tag %v", tag) } else { log.Error("unexpected tag") // TODO Return something sensible here } } func (r *Request) RequestId() uint32 { return r.header.requestId }