Simple roundtrip from ipptool works.
This commit is contained in:
9
go.mod
9
go.mod
@@ -5,10 +5,9 @@ go 1.14
|
|||||||
require (
|
require (
|
||||||
github.com/godbus/dbus/v5 v5.0.3
|
github.com/godbus/dbus/v5 v5.0.3
|
||||||
github.com/holoplot/go-avahi v0.0.0-20200423113835-c8b94bb23ec8
|
github.com/holoplot/go-avahi v0.0.0-20200423113835-c8b94bb23ec8
|
||||||
github.com/kr/pretty v0.1.0 // indirect
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||||
github.com/sirupsen/logrus v1.7.0
|
github.com/sirupsen/logrus v1.7.0
|
||||||
github.com/stretchr/testify v1.4.0 // indirect
|
github.com/stretchr/testify v1.6.1
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd // indirect
|
golang.org/x/sys v0.0.0-20201118182958-a01c418693c7 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
|
||||||
gopkg.in/yaml.v2 v2.2.4 // indirect
|
|
||||||
)
|
)
|
||||||
|
|||||||
24
go.sum
24
go.sum
@@ -6,26 +6,28 @@ github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME=
|
|||||||
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/holoplot/go-avahi v0.0.0-20200423113835-c8b94bb23ec8 h1:f2Do820Rplz3WUKjQvYg8PRcHs/7nHhCoKWdt6+GFZY=
|
github.com/holoplot/go-avahi v0.0.0-20200423113835-c8b94bb23ec8 h1:f2Do820Rplz3WUKjQvYg8PRcHs/7nHhCoKWdt6+GFZY=
|
||||||
github.com/holoplot/go-avahi v0.0.0-20200423113835-c8b94bb23ec8/go.mod h1:UVLO1hQkLAXpZDWt2qnPuHxGRZf8Yrh2fd2J44b+dxM=
|
github.com/holoplot/go-avahi v0.0.0-20200423113835-c8b94bb23ec8/go.mod h1:UVLO1hQkLAXpZDWt2qnPuHxGRZf8Yrh2fd2J44b+dxM=
|
||||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
|
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
|
||||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
|
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1 h1:a/mKvvZr9Jcc8oKfcmgzyp7OwF73JPWsQLvH1z2Kxck=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201118182958-a01c418693c7 h1:Z991aAXPjz0tLnj74pVXW3eWJ5lHMIBvbRfMq4M2jHA=
|
||||||
|
golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
|
|||||||
85
main.go
85
main.go
@@ -2,7 +2,8 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
"fmt"
|
||||||
|
"ippserver/packages/ipp"
|
||||||
"ippserver/packages/mdnsserver"
|
"ippserver/packages/mdnsserver"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
@@ -10,9 +11,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
customFormatter := new(log.TextFormatter)
|
||||||
|
customFormatter.TimestampFormat = "2006-01-02 15:04:05"
|
||||||
|
log.SetFormatter(customFormatter)
|
||||||
|
customFormatter.FullTimestamp = true
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel() // cancel when we are finished consuming integers
|
defer cancel()
|
||||||
go mdnsserver.Run(ctx)
|
go mdnsserver.Run(ctx)
|
||||||
|
|
||||||
http.HandleFunc("/ipp/print", handle)
|
http.HandleFunc("/ipp/print", handle)
|
||||||
@@ -30,70 +35,18 @@ func handle(w http.ResponseWriter, r *http.Request) {
|
|||||||
http.Error(w, "Unsupported method", http.StatusMethodNotAllowed)
|
http.Error(w, "Unsupported method", http.StatusMethodNotAllowed)
|
||||||
|
|
||||||
}
|
}
|
||||||
var request ippRequest
|
|
||||||
request.operationAttributes = make(map[string]string)
|
|
||||||
request.requestedAttributes = make([]string, 0)
|
|
||||||
log.Info(r.Header)
|
|
||||||
log.Info(r.ContentLength)
|
|
||||||
// body := make([]byte, r.ContentLength)
|
// body := make([]byte, r.ContentLength)
|
||||||
//r.Body.Read(body)
|
// io.ReadFull(r.Body, body)
|
||||||
binary.Read(r.Body, binary.BigEndian, &request.header.versionNumber)
|
// log.Infof("Body %x", body)
|
||||||
binary.Read(r.Body, binary.BigEndian, &request.header.operationId)
|
|
||||||
binary.Read(r.Body, binary.BigEndian, &request.header.requestId)
|
request := ipp.NewRequest()
|
||||||
var tag uint8
|
request.UnMarshal(r.Body)
|
||||||
binary.Read(r.Body, binary.BigEndian, &tag)
|
fmt.Printf("%v", request)
|
||||||
if tag == operationAttributesTag {
|
response := ipp.NewResponse(ipp.SuccessfulOk, request.RequestId())
|
||||||
var length uint16
|
a := ipp.NewCharSetValue("attributes-charset", "utf-8")
|
||||||
binary.Read(r.Body, binary.BigEndian, &tag)
|
response.AddOperatonAttribute(a)
|
||||||
for tag != endOfAttributesTag {
|
data := response.Marshal()
|
||||||
log.Infof("Value tag %x", tag)
|
log.Infof("% x", data)
|
||||||
switch tag {
|
w.Write(data)
|
||||||
case charsetValueTag, uriValueTag, naturalLanguagageValueTag:
|
|
||||||
binary.Read(r.Body, binary.BigEndian, &length)
|
|
||||||
attributeName := make([]byte, length)
|
|
||||||
binary.Read(r.Body, binary.BigEndian, attributeName)
|
|
||||||
binary.Read(r.Body, binary.BigEndian, &length)
|
|
||||||
attributeValue := make([]byte, length)
|
|
||||||
binary.Read(r.Body, binary.BigEndian, attributeValue)
|
|
||||||
request.operationAttributes[string(attributeName)] = string(attributeValue)
|
|
||||||
log.Infof("%v %v", string(attributeName), string(attributeValue))
|
|
||||||
binary.Read(r.Body, binary.BigEndian, &tag)
|
|
||||||
case keywordValueTag:
|
|
||||||
binary.Read(r.Body, binary.BigEndian, &length)
|
|
||||||
attributeName := make([]byte, length)
|
|
||||||
set := make([]string, 0)
|
|
||||||
binary.Read(r.Body, binary.BigEndian, &attributeName)
|
|
||||||
binary.Read(r.Body, binary.BigEndian, &length)
|
|
||||||
value := make([]byte, length)
|
|
||||||
binary.Read(r.Body, binary.BigEndian, &value)
|
|
||||||
set = append(set, string(value))
|
|
||||||
binary.Read(r.Body, binary.BigEndian, &tag)
|
|
||||||
for tag == keywordValueTag {
|
|
||||||
var additionalValue uint16
|
|
||||||
binary.Read(r.Body, binary.BigEndian, &additionalValue)
|
|
||||||
binary.Read(r.Body, binary.BigEndian, &length)
|
|
||||||
value = make([]byte, length)
|
|
||||||
binary.Read(r.Body, binary.BigEndian, &value)
|
|
||||||
set = append(set, string(value))
|
|
||||||
binary.Read(r.Body, binary.BigEndian, &tag)
|
|
||||||
}
|
|
||||||
if string(attributeName) == "requested-attributes" {
|
|
||||||
request.requestedAttributes = set
|
|
||||||
}
|
|
||||||
log.Infof("%v %v", string(attributeName), set)
|
|
||||||
default:
|
|
||||||
log.Error("Unsupported tag")
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.Infof("Value tag %x", tag)
|
|
||||||
} else {
|
|
||||||
log.Error("unexpected tag")
|
|
||||||
// TODO Return something sensible here
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Infof("request %+v", request)
|
|
||||||
//log.Infof("Body %v", string(body))
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
70
messages.go
70
messages.go
@@ -1,70 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
// References
|
|
||||||
// https://tools.ietf.org/html/rfc8010
|
|
||||||
// https://tools.ietf.org/html/rfc8011
|
|
||||||
|
|
||||||
// Defined atribute group tags
|
|
||||||
const (
|
|
||||||
beginAttributeGroupTag = 0x00
|
|
||||||
operationAttributesTag = 0x01
|
|
||||||
jobAttributesTag = 0x02
|
|
||||||
endOfAttributesTag = 0x03
|
|
||||||
printerAttributesTag = 0x04
|
|
||||||
unsupportedAttributesTag = 0x05
|
|
||||||
)
|
|
||||||
|
|
||||||
// Defined value tags
|
|
||||||
// from rfc8010
|
|
||||||
const (
|
|
||||||
// Out of band
|
|
||||||
unsupportedValueTag = 0x10
|
|
||||||
unknownValueTag = 0x12
|
|
||||||
noValueValueTag = 0x13
|
|
||||||
// Integer values
|
|
||||||
integerValueTag = 0x21
|
|
||||||
booleanIntegerTag = 0x22
|
|
||||||
enumValueTag = 0x23
|
|
||||||
// Character string values
|
|
||||||
textWithoutLanguagageValueTag = 0x41
|
|
||||||
nameWithoutLanguagageValueTag = 0x42
|
|
||||||
keywordValueTag = 0x44
|
|
||||||
uriValueTag = 0x45
|
|
||||||
uriSchemeValueTag = 0x46
|
|
||||||
charsetValueTag = 0x47
|
|
||||||
naturalLanguagageValueTag = 0x48
|
|
||||||
mimeMediaTypeValueTag = 0x49
|
|
||||||
memberAttrNameValueTag = 0x4a
|
|
||||||
)
|
|
||||||
|
|
||||||
// Operation-id, defined in rfc8011
|
|
||||||
const (
|
|
||||||
PrintJob = 0x0002
|
|
||||||
PrintURI = 0x0003
|
|
||||||
ValidateJob = 0x0004
|
|
||||||
CreateJob = 0x0005
|
|
||||||
SendDocument = 0x0006
|
|
||||||
SendURI = 0x0007
|
|
||||||
CancelJob = 0x0008
|
|
||||||
GetJobAttributes = 0x0009
|
|
||||||
GetJobs = 0x000a
|
|
||||||
GetPrinterAttributes = 0x000b
|
|
||||||
HoldJob = 0x000c
|
|
||||||
ReleaseJob = 0x000d
|
|
||||||
RestartJob = 0x000e
|
|
||||||
PausePrinter = 0x0010
|
|
||||||
ResumePrinter = 0x0011
|
|
||||||
PurgeJobs = 0x0012
|
|
||||||
)
|
|
||||||
|
|
||||||
type ippRequestHeader struct {
|
|
||||||
versionNumber uint16
|
|
||||||
operationId uint16
|
|
||||||
requestId uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type ippRequest struct {
|
|
||||||
header ippRequestHeader
|
|
||||||
operationAttributes map[string]string
|
|
||||||
requestedAttributes []string
|
|
||||||
}
|
|
||||||
5
packages/ipp/charsetAttribute.go
Normal file
5
packages/ipp/charsetAttribute.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package ipp
|
||||||
|
|
||||||
|
type charsetAttribute struct {
|
||||||
|
}
|
||||||
|
|
||||||
47
packages/ipp/charsetvalue.go
Normal file
47
packages/ipp/charsetvalue.go
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
package ipp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type charSetValue struct {
|
||||||
|
name string
|
||||||
|
value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCharSetValue(name string, value string) *charSetValue {
|
||||||
|
c := new(charSetValue)
|
||||||
|
c.name = name
|
||||||
|
c.value = value
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c charSetValue) String() string {
|
||||||
|
return c.name + ":" + c.value
|
||||||
|
}
|
||||||
|
func (c *charSetValue) valueTag() tag {
|
||||||
|
return charsetValueTag
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *charSetValue) unmarshal(byteStream io.Reader) {
|
||||||
|
c.name, c.value = unmarshalSingleValue(byteStream)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *charSetValue) marshal() []byte {
|
||||||
|
l := 5 + len(c.name) + len(c.value)
|
||||||
|
b := make([]byte, l, l)
|
||||||
|
b[0] = byte(charsetValueTag)
|
||||||
|
marshalNameValue(c.name, c.value, b[1:])
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *charSetValue) marshalInto([]byte) int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *charSetValue) size() int {
|
||||||
|
l := 1 + 4 // The attribute tag + 2 lengths
|
||||||
|
l += len(c.name)
|
||||||
|
l += len(c.value)
|
||||||
|
return l
|
||||||
|
}
|
||||||
45
packages/ipp/keyword.go
Normal file
45
packages/ipp/keyword.go
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package ipp
|
||||||
|
|
||||||
|
import "io"
|
||||||
|
|
||||||
|
type keyWord struct {
|
||||||
|
name string
|
||||||
|
values []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newKeyWord() *keyWord {
|
||||||
|
k := new(keyWord)
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *keyWord) string() string {
|
||||||
|
return "a uriValue"
|
||||||
|
}
|
||||||
|
func (k *keyWord) valueTag() tag {
|
||||||
|
return keyWordValueTag
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *keyWord) unmarshal(byteStream io.Reader) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *keyWord) marshal() []byte {
|
||||||
|
return []byte{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *keyWord) addValue(v string) {
|
||||||
|
k.values = append(k.values, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *keyWord) size() int {
|
||||||
|
l := 1 + 2 // The value tag (0x44) + name-length field (2 bytes)
|
||||||
|
l += len(k.name)
|
||||||
|
l += 2 // value-length field (2 bytes)
|
||||||
|
l += len(k.values[0])
|
||||||
|
// Add all additional values
|
||||||
|
for _, v := range k.values[1:] {
|
||||||
|
l += 1 + 4 // The value tag (0x44) + 2 length fields (2 bytes)
|
||||||
|
l += len(v)
|
||||||
|
}
|
||||||
|
return l
|
||||||
|
}
|
||||||
252
packages/ipp/messages.go
Normal file
252
packages/ipp/messages.go
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
package ipp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// References
|
||||||
|
// https://tools.ietf.org/html/rfc8010
|
||||||
|
// https://tools.ietf.org/html/rfc8011
|
||||||
|
|
||||||
|
// Defined value tags
|
||||||
|
// from rfc8010
|
||||||
|
type tag uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
// attribute group tags
|
||||||
|
beginAttribute tag = 0x00
|
||||||
|
operationAttributes tag = 0x01
|
||||||
|
jobAttributes tag = 0x02
|
||||||
|
endOfAttributes tag = 0x03
|
||||||
|
printerAttributes tag = 0x04
|
||||||
|
unsupportedAttributes tag = 0x05
|
||||||
|
// Out of band
|
||||||
|
unsupportedValueTag tag = 0x10
|
||||||
|
unknownValueTag tag = 0x12
|
||||||
|
noValueValueTag tag = 0x13
|
||||||
|
|
||||||
|
// Integer values
|
||||||
|
integerValueTag tag = 0x21
|
||||||
|
booleanValueTag tag = 0x22
|
||||||
|
enumValueTag tag = 0x23
|
||||||
|
|
||||||
|
// octetString Tags
|
||||||
|
octetStringValueTag tag = 0x30
|
||||||
|
dateTimeValueTag tag = 0x31
|
||||||
|
resolutionValueTag tag = 0x32
|
||||||
|
rangeOfIntegerValueTag tag = 0x33
|
||||||
|
begCollectionValueTag tag = 0x34
|
||||||
|
textWithLanguageValueTag tag = 0x35
|
||||||
|
nameWithLanguageValueTag tag = 0x36
|
||||||
|
endCollectionValueTag tag = 0x37
|
||||||
|
|
||||||
|
// Character string values
|
||||||
|
textWithoutLanguagageValueTag tag = 0x41
|
||||||
|
nameWithoutLanguagageValueTag tag = 0x42
|
||||||
|
keyWordValueTag tag = 0x44
|
||||||
|
uriValueTag tag = 0x45
|
||||||
|
uriSchemeValueTag tag = 0x46
|
||||||
|
charsetValueTag tag = 0x47
|
||||||
|
naturalLanguagageValueTag tag = 0x48
|
||||||
|
mimeMediaTypeValueTag tag = 0x49
|
||||||
|
memberAttrNameValueTag tag = 0x4a
|
||||||
|
)
|
||||||
|
|
||||||
|
// Operation-id, defined in rfc8011
|
||||||
|
type operationId uint16
|
||||||
|
|
||||||
|
const (
|
||||||
|
PrintJob operationId = 0x0002
|
||||||
|
PrintURI operationId = 0x0003
|
||||||
|
ValidateJob operationId = 0x0004
|
||||||
|
CreateJob operationId = 0x0005
|
||||||
|
SendDocument operationId = 0x0006
|
||||||
|
SendURI operationId = 0x0007
|
||||||
|
CancelJob operationId = 0x0008
|
||||||
|
GetJobAttributes operationId = 0x0009
|
||||||
|
GetJobs operationId = 0x000a
|
||||||
|
GetPrinterAttributes operationId = 0x000b
|
||||||
|
HoldJob operationId = 0x000c
|
||||||
|
ReleaseJob operationId = 0x000d
|
||||||
|
RestartJob operationId = 0x000e
|
||||||
|
PausePrinter operationId = 0x0010
|
||||||
|
ResumePrinter operationId = 0x0011
|
||||||
|
PurgeJobs operationId = 0x0012
|
||||||
|
)
|
||||||
|
|
||||||
|
type statusCode uint16
|
||||||
|
|
||||||
|
const (
|
||||||
|
SuccessfulOk statusCode = 0x0000
|
||||||
|
ClientErrorBadRequest statusCode = 0x0400
|
||||||
|
)
|
||||||
|
|
||||||
|
type versionNumber uint16
|
||||||
|
|
||||||
|
func (v versionNumber) String() string {
|
||||||
|
vn := uint16(v)
|
||||||
|
return fmt.Sprintf("%x.%x", vn&0xff00>>8, vn&0x00ff)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// log.Info(r.Header)
|
||||||
|
// log.Info(r.ContentLength)
|
||||||
|
|
||||||
|
//body := make([]byte, r.ContentLength)
|
||||||
|
//body.Read(body)
|
||||||
|
|
||||||
|
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 {
|
||||||
|
nextoperationattr:
|
||||||
|
for tag != endOfAttributes {
|
||||||
|
var lastKeyword *keyWord
|
||||||
|
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:
|
||||||
|
k := newKeyWord()
|
||||||
|
k.unmarshal(body)
|
||||||
|
r.operationAttributes[k.name] = k
|
||||||
|
if k.name == "" {
|
||||||
|
lastKeyword.addValue(k.values[0])
|
||||||
|
} else {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalSingleValue(byteStream io.Reader) (string, string) {
|
||||||
|
var length uint16
|
||||||
|
binary.Read(byteStream, binary.BigEndian, &length)
|
||||||
|
//log.Infof("Length %v", length)
|
||||||
|
attributeName := make([]byte, length)
|
||||||
|
if length > 0 {
|
||||||
|
binary.Read(byteStream, binary.BigEndian, attributeName)
|
||||||
|
//log.Infof("Valuename %v", string(attributeName))
|
||||||
|
}
|
||||||
|
binary.Read(byteStream, binary.BigEndian, &length)
|
||||||
|
//log.Infof("Length %v", length)
|
||||||
|
attributeValue := make([]byte, length)
|
||||||
|
binary.Read(byteStream, binary.BigEndian, attributeValue)
|
||||||
|
//log.Infof("Value %v", string(attributeValue))
|
||||||
|
return string(attributeName), string(attributeValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalNameValue(name, value string, b []byte) {
|
||||||
|
p := 0
|
||||||
|
binary.BigEndian.PutUint16(b[p:p+2], uint16(len(name)))
|
||||||
|
p += 2
|
||||||
|
copy(b[p:], []byte(name))
|
||||||
|
p += len(name)
|
||||||
|
binary.BigEndian.PutUint16(b[p:p+2], uint16(len(value)))
|
||||||
|
p += 2
|
||||||
|
copy(b[p:], []byte(value))
|
||||||
|
}
|
||||||
43
packages/ipp/naturallanguagage.go
Normal file
43
packages/ipp/naturallanguagage.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package ipp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type naturalLanguagage struct {
|
||||||
|
name string
|
||||||
|
value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newNaturalLanguagage(name, value string) *naturalLanguagage {
|
||||||
|
c := new(naturalLanguagage)
|
||||||
|
c.name = name
|
||||||
|
c.value = value
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c naturalLanguagage) String() string {
|
||||||
|
return c.name + ":" + c.value
|
||||||
|
}
|
||||||
|
func (c *naturalLanguagage) valueTag() tag {
|
||||||
|
return naturalLanguagageValueTag
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *naturalLanguagage) unmarshal(byteStream io.Reader) {
|
||||||
|
c.name, c.value = unmarshalSingleValue(byteStream)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *naturalLanguagage) marshal() []byte {
|
||||||
|
l := 5 + len(c.name) + len(c.value)
|
||||||
|
b := make([]byte, l, l)
|
||||||
|
b[0] = byte(naturalLanguagageValueTag)
|
||||||
|
marshalNameValue(c.name, c.value, b[1:])
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *naturalLanguagage) size() int {
|
||||||
|
l := 1 + 4 // The attribute tag + 2 lengths
|
||||||
|
l += len(c.name)
|
||||||
|
l += len(c.value)
|
||||||
|
return l
|
||||||
|
}
|
||||||
50
packages/ipp/operationid_string.go
Normal file
50
packages/ipp/operationid_string.go
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
// Code generated by "stringer -type operationId"; DO NOT EDIT.
|
||||||
|
|
||||||
|
package ipp
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||||
|
// Re-run the stringer command to generate them again.
|
||||||
|
var x [1]struct{}
|
||||||
|
_ = x[PrintJob-2]
|
||||||
|
_ = x[PrintURI-3]
|
||||||
|
_ = x[ValidateJob-4]
|
||||||
|
_ = x[CreateJob-5]
|
||||||
|
_ = x[SendDocument-6]
|
||||||
|
_ = x[SendURI-7]
|
||||||
|
_ = x[CancelJob-8]
|
||||||
|
_ = x[GetJobAttributes-9]
|
||||||
|
_ = x[GetJobs-10]
|
||||||
|
_ = x[GetPrinterAttributes-11]
|
||||||
|
_ = x[HoldJob-12]
|
||||||
|
_ = x[ReleaseJob-13]
|
||||||
|
_ = x[RestartJob-14]
|
||||||
|
_ = x[PausePrinter-16]
|
||||||
|
_ = x[ResumePrinter-17]
|
||||||
|
_ = x[PurgeJobs-18]
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
_operationId_name_0 = "PrintJobPrintURIValidateJobCreateJobSendDocumentSendURICancelJobGetJobAttributesGetJobsGetPrinterAttributesHoldJobReleaseJobRestartJob"
|
||||||
|
_operationId_name_1 = "PausePrinterResumePrinterPurgeJobs"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_operationId_index_0 = [...]uint8{0, 8, 16, 27, 36, 48, 55, 64, 80, 87, 107, 114, 124, 134}
|
||||||
|
_operationId_index_1 = [...]uint8{0, 12, 25, 34}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (i operationId) String() string {
|
||||||
|
switch {
|
||||||
|
case 2 <= i && i <= 14:
|
||||||
|
i -= 2
|
||||||
|
return _operationId_name_0[_operationId_index_0[i]:_operationId_index_0[i+1]]
|
||||||
|
case 16 <= i && i <= 18:
|
||||||
|
i -= 16
|
||||||
|
return _operationId_name_1[_operationId_index_1[i]:_operationId_index_1[i+1]]
|
||||||
|
default:
|
||||||
|
return "operationId(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||||
|
}
|
||||||
|
}
|
||||||
91
packages/ipp/response.go
Normal file
91
packages/ipp/response.go
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
package ipp
|
||||||
|
|
||||||
|
import "encoding/binary"
|
||||||
|
|
||||||
|
type ippResponseHeader struct {
|
||||||
|
versionNumber versionNumber
|
||||||
|
statusCode statusCode
|
||||||
|
requestId uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ippResponseHeader) marshal() []byte {
|
||||||
|
a := make([]byte, 8, 8)
|
||||||
|
binary.BigEndian.PutUint16(a[0:2], uint16(h.versionNumber))
|
||||||
|
binary.BigEndian.PutUint16(a[2:4], uint16(h.statusCode))
|
||||||
|
binary.BigEndian.PutUint32(a[4:8], h.requestId)
|
||||||
|
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
type Response struct {
|
||||||
|
header ippResponseHeader
|
||||||
|
operationAttributes []Attribute
|
||||||
|
jobAttributes []Attribute
|
||||||
|
printerAttributes []Attribute
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewResponse(code statusCode, requestId uint32) *Response {
|
||||||
|
r := new(Response)
|
||||||
|
r.header.versionNumber = 0x0101
|
||||||
|
r.header.requestId = requestId
|
||||||
|
r.header.statusCode = code
|
||||||
|
r.operationAttributes = make([]Attribute, 0)
|
||||||
|
r.printerAttributes = make([]Attribute, 0)
|
||||||
|
r.jobAttributes = make([]Attribute, 0)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// func (r *Response) length() int {
|
||||||
|
// l := 8 + 1
|
||||||
|
// if len(r.jobAttributes) > 0 {
|
||||||
|
// l += 1 //
|
||||||
|
// for _, e := range r.jobAttributes {
|
||||||
|
// l += e.length()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// for _, e := range r.operationAttributes {
|
||||||
|
// l += e.length()
|
||||||
|
// }
|
||||||
|
// for _, e := range r.printerAttributes {
|
||||||
|
// l += e.length()
|
||||||
|
// }
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (r *Response) Marshal() []byte {
|
||||||
|
a := make([]byte, 0, 20)
|
||||||
|
a = append(a, r.header.marshal()...)
|
||||||
|
if len(r.operationAttributes) > 0 {
|
||||||
|
a = append(a, byte(operationAttributes))
|
||||||
|
for _, e := range r.operationAttributes {
|
||||||
|
a = append(a, e.marshal()...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(r.jobAttributes) > 0 {
|
||||||
|
a = append(a, byte(jobAttributes))
|
||||||
|
for _, e := range r.jobAttributes {
|
||||||
|
a = append(a, e.marshal()...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(r.printerAttributes) > 0 {
|
||||||
|
a = append(a, byte(printerAttributes))
|
||||||
|
for _, e := range r.printerAttributes {
|
||||||
|
a = append(a, e.marshal()...)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
a = append(a, byte(endOfAttributes))
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) AddPrinterAttribute(a Attribute) {
|
||||||
|
r.printerAttributes = append(r.printerAttributes, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) AddOperatonAttribute(a Attribute) {
|
||||||
|
r.operationAttributes = append(r.operationAttributes, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Response) AddJobAttribute(a Attribute) {
|
||||||
|
r.jobAttributes = append(r.jobAttributes, a)
|
||||||
|
}
|
||||||
29
packages/ipp/response_test.go
Normal file
29
packages/ipp/response_test.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package ipp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMarshalResponseHeader(T *testing.T) {
|
||||||
|
var h ippResponseHeader
|
||||||
|
|
||||||
|
h.versionNumber = 0x0101
|
||||||
|
h.statusCode = SuccessfulOk
|
||||||
|
h.requestId = 0xdeadbeef
|
||||||
|
|
||||||
|
b := h.marshal()
|
||||||
|
fmt.Printf("% x\n", b)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMarshalCompleteResponse(T *testing.T) {
|
||||||
|
r := NewResponse(SuccessfulOk, 0xdeadbeef)
|
||||||
|
|
||||||
|
a := NewCharSetValue("attributes-charset", "UTF-8")
|
||||||
|
r.AddPrinterAttribute(a)
|
||||||
|
|
||||||
|
b := r.Marshal()
|
||||||
|
fmt.Printf("% x\n", b)
|
||||||
|
|
||||||
|
}
|
||||||
85
packages/ipp/tag_string.go
Normal file
85
packages/ipp/tag_string.go
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
// Code generated by "stringer -type tag"; DO NOT EDIT.
|
||||||
|
|
||||||
|
package ipp
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||||
|
// Re-run the stringer command to generate them again.
|
||||||
|
var x [1]struct{}
|
||||||
|
_ = x[beginAttribute-0]
|
||||||
|
_ = x[operationAttributes-1]
|
||||||
|
_ = x[jobAttributes-2]
|
||||||
|
_ = x[endOfAttributes-3]
|
||||||
|
_ = x[printerAttributes-4]
|
||||||
|
_ = x[unsupportedAttributes-5]
|
||||||
|
_ = x[unsupportedValueTag-16]
|
||||||
|
_ = x[unknownValueTag-18]
|
||||||
|
_ = x[noValueValueTag-19]
|
||||||
|
_ = x[integerValueTag-33]
|
||||||
|
_ = x[booleanValueTag-34]
|
||||||
|
_ = x[enumValueTag-35]
|
||||||
|
_ = x[octetStringValueTag-48]
|
||||||
|
_ = x[dateTimeValueTag-49]
|
||||||
|
_ = x[resolutionValueTag-50]
|
||||||
|
_ = x[rangeOfIntegerValueTag-51]
|
||||||
|
_ = x[begCollectionValueTag-52]
|
||||||
|
_ = x[textWithLanguageValueTag-53]
|
||||||
|
_ = x[nameWithLanguageValueTag-54]
|
||||||
|
_ = x[endCollectionValueTag-55]
|
||||||
|
_ = x[textWithoutLanguagageValueTag-65]
|
||||||
|
_ = x[nameWithoutLanguagageValueTag-66]
|
||||||
|
_ = x[keyWordValueTag-68]
|
||||||
|
_ = x[uriValueTag-69]
|
||||||
|
_ = x[uriSchemeValueTag-70]
|
||||||
|
_ = x[charsetValueTag-71]
|
||||||
|
_ = x[naturalLanguagageValueTag-72]
|
||||||
|
_ = x[mimeMediaTypeValueTag-73]
|
||||||
|
_ = x[memberAttrNameValueTag-74]
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
_tag_name_0 = "beginAttributeoperationAttributesjobAttributesendOfAttributesprinterAttributesunsupportedAttributes"
|
||||||
|
_tag_name_1 = "unsupportedValueTag"
|
||||||
|
_tag_name_2 = "unknownValueTagnoValueValueTag"
|
||||||
|
_tag_name_3 = "integerValueTagbooleanValueTagenumValueTag"
|
||||||
|
_tag_name_4 = "octetStringValueTagdateTimeValueTagresolutionValueTagrangeOfIntegerValueTagbegCollectionValueTagtextWithLanguageValueTagnameWithLanguageValueTagendCollectionValueTag"
|
||||||
|
_tag_name_5 = "textWithoutLanguagageValueTagnameWithoutLanguagageValueTag"
|
||||||
|
_tag_name_6 = "keywordValueTaguriValueTaguriSchemeValueTagcharsetValueTagnaturalLanguagageValueTagmimeMediaTypeValueTagmemberAttrNameValueTag"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_tag_index_0 = [...]uint8{0, 14, 33, 46, 61, 78, 99}
|
||||||
|
_tag_index_2 = [...]uint8{0, 15, 30}
|
||||||
|
_tag_index_3 = [...]uint8{0, 15, 30, 42}
|
||||||
|
_tag_index_4 = [...]uint8{0, 19, 35, 53, 75, 96, 120, 144, 165}
|
||||||
|
_tag_index_5 = [...]uint8{0, 29, 58}
|
||||||
|
_tag_index_6 = [...]uint8{0, 15, 26, 43, 58, 83, 104, 126}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (i tag) String() string {
|
||||||
|
switch {
|
||||||
|
case i <= 5:
|
||||||
|
return _tag_name_0[_tag_index_0[i]:_tag_index_0[i+1]]
|
||||||
|
case i == 16:
|
||||||
|
return _tag_name_1
|
||||||
|
case 18 <= i && i <= 19:
|
||||||
|
i -= 18
|
||||||
|
return _tag_name_2[_tag_index_2[i]:_tag_index_2[i+1]]
|
||||||
|
case 33 <= i && i <= 35:
|
||||||
|
i -= 33
|
||||||
|
return _tag_name_3[_tag_index_3[i]:_tag_index_3[i+1]]
|
||||||
|
case 48 <= i && i <= 55:
|
||||||
|
i -= 48
|
||||||
|
return _tag_name_4[_tag_index_4[i]:_tag_index_4[i+1]]
|
||||||
|
case 65 <= i && i <= 66:
|
||||||
|
i -= 65
|
||||||
|
return _tag_name_5[_tag_index_5[i]:_tag_index_5[i+1]]
|
||||||
|
case 68 <= i && i <= 74:
|
||||||
|
i -= 68
|
||||||
|
return _tag_name_6[_tag_index_6[i]:_tag_index_6[i+1]]
|
||||||
|
default:
|
||||||
|
return "tag(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||||
|
}
|
||||||
|
}
|
||||||
42
packages/ipp/urivalue.go
Normal file
42
packages/ipp/urivalue.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package ipp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type uriValue struct {
|
||||||
|
name string
|
||||||
|
value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newUriValue(name, value string) *uriValue {
|
||||||
|
u := new(uriValue)
|
||||||
|
u.name = name
|
||||||
|
u.value = value
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u uriValue) String() string {
|
||||||
|
return u.name + ":" + u.value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *uriValue) valueTag() tag {
|
||||||
|
return uriValueTag
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *uriValue) unmarshal(byteStream io.Reader) {
|
||||||
|
u.name, u.value = unmarshalSingleValue(byteStream)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *uriValue) marshal() []byte {
|
||||||
|
res := make([]byte, u.size())
|
||||||
|
res[0] = byte(uriValueTag)
|
||||||
|
marshalNameValue(u.name, u.value, res[1:])
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
func (u *uriValue) size() int {
|
||||||
|
l := 1 + 4 // The attribute tag + 2 lengths
|
||||||
|
l += len(u.name)
|
||||||
|
l += len(u.value)
|
||||||
|
return l
|
||||||
|
}
|
||||||
17
packages/ipp/urivalue_test.go
Normal file
17
packages/ipp/urivalue_test.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package ipp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMarshalUriValue(T *testing.T) {
|
||||||
|
var u uriValue
|
||||||
|
u.name = "foo"
|
||||||
|
u.value = "bar"
|
||||||
|
b := u.marshal()
|
||||||
|
assert.Len(T, b, 11)
|
||||||
|
fmt.Printf("% x\n", b)
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
../work/ippsample/tools/ipptool -v -f 1-untitled.ras ipp://brn30055cb5e3ae:631/ipp/print printjob.ipp
|
../work/ippsample/tools/ipptool -v -f 1-untitled.ras ipp://brn30055cb5e3ae:631/ipp/print printjob.ipp
|
||||||
|
|
||||||
|
ipptool -t -v ipp://brn30055cb5e3ae:631/ipp/print get-printer-attributes.test
|
||||||
|
|
||||||
ippserver -2 -M FUBAR -d . -vv -k -f image/pwg-raster testprinter
|
ippserver -2 -M FUBAR -d . -vv -k -f image/pwg-raster testprinter
|
||||||
|
|
||||||
henrik@drpork:~/ipp$ cat printjob.ipp
|
henrik@drpork:~/ipp$ cat printjob.ipp
|
||||||
|
|||||||
Reference in New Issue
Block a user