OSDN Git Service

4a5eca1450f0f61e6fef1ae0fc0ca588ea9dfa85
[pf3gnuchains/gcc-fork.git] / libgo / go / asn1 / common.go
1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package asn1
6
7 import (
8         "reflect"
9         "strconv"
10         "strings"
11 )
12
13 // ASN.1 objects have metadata preceeding them:
14 //   the tag: the type of the object
15 //   a flag denoting if this object is compound or not
16 //   the class type: the namespace of the tag
17 //   the length of the object, in bytes
18
19 // Here are some standard tags and classes
20
21 const (
22         tagBoolean         = 1
23         tagInteger         = 2
24         tagBitString       = 3
25         tagOctetString     = 4
26         tagOID             = 6
27         tagEnum            = 10
28         tagSequence        = 16
29         tagSet             = 17
30         tagPrintableString = 19
31         tagT61String       = 20
32         tagIA5String       = 22
33         tagUTCTime         = 23
34         tagGeneralizedTime = 24
35 )
36
37 const (
38         classUniversal       = 0
39         classApplication     = 1
40         classContextSpecific = 2
41         classPrivate         = 3
42 )
43
44 type tagAndLength struct {
45         class, tag, length int
46         isCompound         bool
47 }
48
49 // ASN.1 has IMPLICIT and EXPLICIT tags, which can be translated as "instead
50 // of" and "in addition to". When not specified, every primitive type has a
51 // default tag in the UNIVERSAL class.
52 //
53 // For example: a BIT STRING is tagged [UNIVERSAL 3] by default (although ASN.1
54 // doesn't actually have a UNIVERSAL keyword). However, by saying [IMPLICIT
55 // CONTEXT-SPECIFIC 42], that means that the tag is replaced by another.
56 //
57 // On the other hand, if it said [EXPLICIT CONTEXT-SPECIFIC 10], then an
58 // /additional/ tag would wrap the default tag. This explicit tag will have the
59 // compound flag set.
60 //
61 // (This is used in order to remove ambiguity with optional elements.)
62 //
63 // You can layer EXPLICIT and IMPLICIT tags to an arbitrary depth, however we
64 // don't support that here. We support a single layer of EXPLICIT or IMPLICIT
65 // tagging with tag strings on the fields of a structure.
66
67 // fieldParameters is the parsed representation of tag string from a structure field.
68 type fieldParameters struct {
69         optional     bool   // true iff the field is OPTIONAL
70         explicit     bool   // true iff and EXPLICIT tag is in use.
71         defaultValue *int64 // a default value for INTEGER typed fields (maybe nil).
72         tag          *int   // the EXPLICIT or IMPLICIT tag (maybe nil).
73         stringType   int    // the string tag to use when marshaling.
74         set          bool   // true iff this should be encoded as a SET
75
76         // Invariants:
77         //   if explicit is set, tag is non-nil.
78 }
79
80 // Given a tag string with the format specified in the package comment,
81 // parseFieldParameters will parse it into a fieldParameters structure,
82 // ignoring unknown parts of the string.
83 func parseFieldParameters(str string) (ret fieldParameters) {
84         for _, part := range strings.Split(str, ",", -1) {
85                 switch {
86                 case part == "optional":
87                         ret.optional = true
88                 case part == "explicit":
89                         ret.explicit = true
90                         if ret.tag == nil {
91                                 ret.tag = new(int)
92                                 *ret.tag = 0
93                         }
94                 case part == "ia5":
95                         ret.stringType = tagIA5String
96                 case part == "printable":
97                         ret.stringType = tagPrintableString
98                 case strings.HasPrefix(part, "default:"):
99                         i, err := strconv.Atoi64(part[8:])
100                         if err == nil {
101                                 ret.defaultValue = new(int64)
102                                 *ret.defaultValue = i
103                         }
104                 case strings.HasPrefix(part, "tag:"):
105                         i, err := strconv.Atoi(part[4:])
106                         if err == nil {
107                                 ret.tag = new(int)
108                                 *ret.tag = i
109                         }
110                 case part == "set":
111                         ret.set = true
112                 }
113         }
114         return
115 }
116
117 // Given a reflected Go type, getUniversalType returns the default tag number
118 // and expected compound flag.
119 func getUniversalType(t reflect.Type) (tagNumber int, isCompound, ok bool) {
120         switch t {
121         case objectIdentifierType:
122                 return tagOID, false, true
123         case bitStringType:
124                 return tagBitString, false, true
125         case timeType:
126                 return tagUTCTime, false, true
127         case enumeratedType:
128                 return tagEnum, false, true
129         }
130         switch t := t.(type) {
131         case *reflect.BoolType:
132                 return tagBoolean, false, true
133         case *reflect.IntType:
134                 return tagInteger, false, true
135         case *reflect.StructType:
136                 return tagSequence, true, true
137         case *reflect.SliceType:
138                 if t.Elem().Kind() == reflect.Uint8 {
139                         return tagOctetString, false, true
140                 }
141                 if strings.HasSuffix(t.Name(), "SET") {
142                         return tagSet, true, true
143                 }
144                 return tagSequence, true, true
145         case *reflect.StringType:
146                 return tagPrintableString, false, true
147         }
148         return 0, false, false
149 }