Repository navigation
Expand file tree
/
Copy pathtag.go
More file actions
356 lines (309 loc) · 10.9 KB
/
Copy pathtag.go
File metadata and controls
356 lines (309 loc) · 10.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
/* Go IPP - IPP core protocol implementation in pure Go
*
* Copyright (C) 2020 and up by Alexander Pevzner (pzz@apevzner.com)
* See LICENSE for license terms and conditions
*
* IPP Tags
*/
package goipp
import (
"fmt"
"math"
)
// Tag represents a tag used in the binary representation of an IPP message.
//
// Normally, a Tag is a single-byte value ranging from 0x00 to 0xff.
//
// However, IPP also provides an extension tag mechanism that supports
// 32-bit tags. When using this mechanism, the tag is set to [TagExtension],
// and the actual 32-bit tag value is encoded as a big-endian integer
// in the attribute value.
//
// This mechanism is described in RFC 8010, Section 3.5.2.
//
// To send an [Attribute] with an extended tag value:
//
// - Set the value tag to TagExtension
// - Use [Binary] to represent the Attribute value
// - Encode the extended tag value as a big-endian integer in the first
// 4 bytes of the attribute value
// - Note that the extended tag value must be within the allowed range
// (0x00000000 to 0x7fffffff, inclusive)
//
// The goipp library enforces these rules during message encoding and decoding.
//
// Note: This API has changed since version 1.1.0 of this library.
// Previously, the library automatically converted tags with values exceeding
// single-byte range into extended tag representation. However, this caused
// issues during reception because automatically converted tags with extended
// representation format but smaller values became indistinguishable from
// normal tags with the same value, despite requiring different handling.
type Tag int
// Tag values
const (
// Delimiter tags
TagZero Tag = 0x00 // Zero tag - used for separators
TagOperationGroup Tag = 0x01 // Operation group
TagJobGroup Tag = 0x02 // Job group
TagEnd Tag = 0x03 // End-of-attributes
TagPrinterGroup Tag = 0x04 // Printer group
TagUnsupportedGroup Tag = 0x05 // Unsupported attributes group
TagSubscriptionGroup Tag = 0x06 // Subscription group
TagEventNotificationGroup Tag = 0x07 // Event group
TagResourceGroup Tag = 0x08 // Resource group
TagDocumentGroup Tag = 0x09 // Document group
TagSystemGroup Tag = 0x0a // System group
TagFuture11Group Tag = 0x0b // Future group 11
TagFuture12Group Tag = 0x0c // Future group 12
TagFuture13Group Tag = 0x0d // Future group 13
TagFuture14Group Tag = 0x0e // Future group 14
TagFuture15Group Tag = 0x0f // Future group 15
// Value tags
TagUnsupportedValue Tag = 0x10 // Unsupported value
TagDefault Tag = 0x11 // Default value
TagUnknown Tag = 0x12 // Unknown value
TagNoValue Tag = 0x13 // No-value value
TagNotSettable Tag = 0x15 // Not-settable value
TagDeleteAttr Tag = 0x16 // Delete-attribute value
TagAdminDefine Tag = 0x17 // Admin-defined value
TagInteger Tag = 0x21 // Integer value
TagBoolean Tag = 0x22 // Boolean value
TagEnum Tag = 0x23 // Enumeration value
TagString Tag = 0x30 // Octet string value
TagDateTime Tag = 0x31 // Date/time value
TagResolution Tag = 0x32 // Resolution value
TagRange Tag = 0x33 // Range value
TagBeginCollection Tag = 0x34 // Beginning of collection value
TagTextLang Tag = 0x35 // Text-with-language value
TagNameLang Tag = 0x36 // Name-with-language value
TagEndCollection Tag = 0x37 // End of collection value
TagText Tag = 0x41 // Text value
TagName Tag = 0x42 // Name value
TagReservedString Tag = 0x43 // Reserved for future string value
TagKeyword Tag = 0x44 // Keyword value
TagURI Tag = 0x45 // URI value
TagURIScheme Tag = 0x46 // URI scheme value
TagCharset Tag = 0x47 // Character set value
TagLanguage Tag = 0x48 // Language value
TagMimeType Tag = 0x49 // MIME media type value
TagMemberName Tag = 0x4a // Collection member name value
TagExtension Tag = 0x7f // Extension point for 32-bit tags
)
// IsDelimiter returns true for delimiter tags
func (tag Tag) IsDelimiter() bool {
return uint(tag) < 0x10
}
// IsGroup returns true for group tags
func (tag Tag) IsGroup() bool {
return tag.IsDelimiter() && tag != TagZero && tag != TagEnd
}
// Type returns Type of Value that corresponds to the tag
func (tag Tag) Type() Type {
if tag.IsDelimiter() {
return TypeInvalid
}
switch tag {
case TagInteger, TagEnum:
return TypeInteger
case TagBoolean:
return TypeBoolean
case TagUnsupportedValue, TagDefault, TagUnknown, TagNotSettable,
TagNoValue, TagDeleteAttr, TagAdminDefine:
// These tags not expected to have value
return TypeVoid
case TagText, TagName, TagReservedString, TagKeyword, TagURI, TagURIScheme,
TagCharset, TagLanguage, TagMimeType, TagMemberName:
return TypeString
case TagDateTime:
return TypeDateTime
case TagResolution:
return TypeResolution
case TagRange:
return TypeRange
case TagTextLang, TagNameLang:
return TypeTextWithLang
case TagBeginCollection:
return TypeCollection
case TagEndCollection:
return TypeVoid
case TagExtension:
return TypeBinary
default:
return TypeBinary
}
}
// String() returns a tag name, as defined by RFC 8010
func (tag Tag) String() string {
if 0 <= tag && int(tag) < len(tagNames) {
if s := tagNames[tag]; s != "" {
return s
}
}
if tag < 0x100 {
return fmt.Sprintf("0x%2.2x", uint32(tag))
}
return fmt.Sprintf("0x%8.8x", uint(tag))
}
// GoString returns string that represents Tag in Go syntax, i.e.,
// "goipp.TagBoolean" or "goipp.Tag(0x12) for unknown tags.
func (tag Tag) GoString() string {
if 0 <= tag && int(tag) < len(tagGoNames) {
if s := tagGoNames[tag]; s != "" {
return s
}
}
if tag < 0x100 {
return fmt.Sprintf("goipp.Tag(0x%2.2x)", uint32(tag))
}
return fmt.Sprintf("goipp.Tag(0x%8.8x)", uint(tag))
}
// Limits returns min/max limits, implied by the value tag.
//
// If tag doesn't imply the value limit, [math.MinInt32] is
// returned for the lower bound and [math.MaxInt32] is returned
// for the upper bound. In particular, it happens for the
// non-value tags.
func (tag Tag) Limits() (min, max int32) {
switch tag {
case TagText, TagTextLang:
// RFC8011, 5.1.2.
return 0, 1023
case TagName, TagNameLang:
// RFC8011, 5.1.3.
return 0, 255
case TagKeyword:
// RFC8011, 5.1.4.
return 1, 255
case TagEnum:
// RFC8011, 5.1.5.
return 1, math.MaxInt32
case TagURI:
// RFC8011, 5.1.6.
return 0, 1023
case TagURIScheme:
// RFC8011, 5.1.7.
return 0, 63
case TagCharset:
// RFC8011, 5.1.8.
return 0, 63
case TagLanguage:
// RFC8011, 5.1.9.
return 0, 63
case TagMimeType:
// RFC8011, 5.1.10.
return 0, 255
case TagString:
// RFC8011, 5.1.11.
return 0, 1023
case TagBoolean:
// RFC8011, 5.1.12.
// No implied limit
return math.MinInt32, math.MaxInt32
case TagInteger, TagRange:
// RFC8011, 5.1.13., 5.1.14.
// All 32-bit signed range available
return math.MinInt32, math.MaxInt32
case TagDateTime:
// RFC8011, 5.1.15.
// No implied limit
return math.MinInt32, math.MaxInt32
case TagResolution:
// RFC8011, 5.1.16.
// Limit not applicable
return math.MinInt32, math.MaxInt32
case TagBeginCollection:
// RFC8011, 5.1.16.
// Limit not applicable
return math.MinInt32, math.MaxInt32
case TagReservedString:
// Limit not applicable
return math.MinInt32, math.MaxInt32
}
return math.MinInt32, math.MaxInt32
}
var tagNames = [...]string{
// Delimiter tags
TagZero: "zero",
TagOperationGroup: "operation-attributes-tag",
TagJobGroup: "job-attributes-tag",
TagEnd: "end-of-attributes-tag",
TagPrinterGroup: "printer-attributes-tag",
TagUnsupportedGroup: "unsupported-attributes-tag",
TagSubscriptionGroup: "subscription-attributes-tag",
TagEventNotificationGroup: "event-notification-attributes-tag",
TagResourceGroup: "resource-attributes-tag",
TagDocumentGroup: "document-attributes-tag",
TagSystemGroup: "system-attributes-tag",
// Value tags
TagUnsupportedValue: "unsupported",
TagDefault: "default",
TagUnknown: "unknown",
TagNoValue: "no-value",
TagNotSettable: "not-settable",
TagDeleteAttr: "delete-attribute",
TagAdminDefine: "admin-define",
TagInteger: "integer",
TagBoolean: "boolean",
TagEnum: "enum",
TagString: "octetString",
TagDateTime: "dateTime",
TagResolution: "resolution",
TagRange: "rangeOfInteger",
TagBeginCollection: "collection",
TagTextLang: "textWithLanguage",
TagNameLang: "nameWithLanguage",
TagEndCollection: "endCollection",
TagText: "textWithoutLanguage",
TagName: "nameWithoutLanguage",
TagKeyword: "keyword",
TagURI: "uri",
TagURIScheme: "uriScheme",
TagCharset: "charset",
TagLanguage: "naturalLanguage",
TagMimeType: "mimeMediaType",
TagMemberName: "memberAttrName",
TagExtension: "extension",
}
var tagGoNames = [...]string{
// Delimiter tags
TagZero: "goipp.TagZero",
TagOperationGroup: "goipp.TagOperationGroup",
TagJobGroup: "goipp.TagJobGroup",
TagEnd: "goipp.TagEnd",
TagPrinterGroup: "goipp.TagPrinterGroup",
TagUnsupportedGroup: "goipp.TagUnsupportedGroup",
TagSubscriptionGroup: "goipp.TagSubscriptionGroup",
TagEventNotificationGroup: "goipp.TagEventNotificationGroup",
TagResourceGroup: "goipp.TagResourceGroup",
TagDocumentGroup: "goipp.TagDocumentGroup",
TagSystemGroup: "goipp.TagSystemGroup",
// Value tags
TagUnsupportedValue: "goipp.TagUnsupportedValue",
TagDefault: "goipp.TagDefault",
TagUnknown: "goipp.TagUnknown",
TagNoValue: "goipp.TagNoValue",
TagNotSettable: "goipp.TagNotSettable",
TagDeleteAttr: "goipp.TagDeleteAttr",
TagAdminDefine: "goipp.TagAdminDefine",
TagInteger: "goipp.TagInteger",
TagBoolean: "goipp.TagBoolean",
TagEnum: "goipp.TagEnum",
TagString: "goipp.TagString",
TagDateTime: "goipp.TagDateTime",
TagResolution: "goipp.TagResolution",
TagRange: "goipp.TagRange",
TagBeginCollection: "goipp.TagBeginCollection",
TagTextLang: "goipp.TagTextLang",
TagNameLang: "goipp.TagNameLang",
TagEndCollection: "goipp.TagEndCollection",
TagText: "goipp.TagText",
TagName: "goipp.TagName",
TagKeyword: "goipp.TagKeyword",
TagURI: "goipp.TagURI",
TagURIScheme: "goipp.TagURIScheme",
TagCharset: "goipp.TagCharset",
TagLanguage: "goipp.TagLanguage",
TagMimeType: "goipp.TagMimeType",
TagMemberName: "goipp.TagMemberName",
TagExtension: "goipp.TagExtension",
}