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.
16 // A forkableWriter is an in-memory buffer that can be
17 // 'forked' to create new forkableWriters that bracket the
19 // pre, post := w.fork();
20 // the overall sequence of bytes represented is logically w+pre+post.
21 type forkableWriter
struct {
23 pre
, post
*forkableWriter
26 func newForkableWriter() *forkableWriter
{
27 return &forkableWriter
{bytes
.NewBuffer(nil), nil, nil}
30 func (f
*forkableWriter
) fork() (pre
, post
*forkableWriter
) {
31 if f
.pre
!= nil || f
.post
!= nil {
32 panic("have already forked")
34 f
.pre
= newForkableWriter()
35 f
.post
= newForkableWriter()
39 func (f
*forkableWriter
) Len() (l
int) {
50 func (f
*forkableWriter
) writeTo(out io
.Writer
) (n
int, err os
.Error
) {
51 n
, err
= out
.Write(f
.Bytes())
59 nn
, err
= f
.pre
.writeTo(out
)
67 nn
, err
= f
.post
.writeTo(out
)
73 func marshalBase128Int(out
*forkableWriter
, n
int64) (err os
.Error
) {
75 err
= out
.WriteByte(0)
80 for i
:= n
; i
> 0; i
>>= 7 {
84 for i
:= l
- 1; i
>= 0; i
-- {
85 o
:= byte(n
>> uint(i
*7))
90 err
= out
.WriteByte(o
)
99 func marshalInt64(out
*forkableWriter
, i
int64) (err os
.Error
) {
103 err
= out
.WriteByte(byte(i
>> uint((n
-1)*8)))
112 func int64Length(i
int64) (numBytes
int) {
128 func marshalTagAndLength(out
*forkableWriter
, t tagAndLength
) (err os
.Error
) {
129 b
:= uint8(t
.class
) << 6
135 err
= out
.WriteByte(b
)
139 err
= marshalBase128Int(out
, int64(t
.tag
))
145 err
= out
.WriteByte(b
)
152 l
:= int64Length(int64(t
.length
))
153 err
= out
.WriteByte(0x80 |
byte(l
))
157 err
= marshalInt64(out
, int64(t
.length
))
162 err
= out
.WriteByte(byte(t
.length
))
171 func marshalBitString(out
*forkableWriter
, b BitString
) (err os
.Error
) {
172 paddingBits
:= byte((8 - b
.BitLength%8
) % 8)
173 err
= out
.WriteByte(paddingBits
)
177 _
, err
= out
.Write(b
.Bytes
)
181 func marshalObjectIdentifier(out
*forkableWriter
, oid
[]int) (err os
.Error
) {
182 if len(oid
) < 2 || oid
[0] > 6 || oid
[1] >= 40 {
183 return StructuralError
{"invalid object identifier"}
186 err
= out
.WriteByte(byte(oid
[0]*40 + oid
[1]))
190 for i
:= 2; i
< len(oid
); i
++ {
191 err
= marshalBase128Int(out
, int64(oid
[i
]))
200 func marshalPrintableString(out
*forkableWriter
, s
string) (err os
.Error
) {
202 for _
, c
:= range b
{
204 return StructuralError
{"PrintableString contains invalid character"}
208 _
, err
= out
.Write(b
)
212 func marshalIA5String(out
*forkableWriter
, s
string) (err os
.Error
) {
214 for _
, c
:= range b
{
216 return StructuralError
{"IA5String contains invalid character"}
220 _
, err
= out
.Write(b
)
224 func marshalTwoDigits(out
*forkableWriter
, v
int) (err os
.Error
) {
225 err
= out
.WriteByte(byte('0' + (v
/10)%10
))
229 return out
.WriteByte(byte('0' + v%10
))
232 func marshalUTCTime(out
*forkableWriter
, t
*time
.Time
) (err os
.Error
) {
234 case 1950 <= t
.Year
&& t
.Year
< 2000:
235 err
= marshalTwoDigits(out
, int(t
.Year
-1900))
236 case 2000 <= t
.Year
&& t
.Year
< 2050:
237 err
= marshalTwoDigits(out
, int(t
.Year
-2000))
239 return StructuralError
{"Cannot represent time as UTCTime"}
246 err
= marshalTwoDigits(out
, t
.Month
)
251 err
= marshalTwoDigits(out
, t
.Day
)
256 err
= marshalTwoDigits(out
, t
.Hour
)
261 err
= marshalTwoDigits(out
, t
.Minute
)
266 err
= marshalTwoDigits(out
, t
.Second
)
272 case t
.ZoneOffset
/60 == 0:
273 err
= out
.WriteByte('Z')
275 case t
.ZoneOffset
> 0:
276 err
= out
.WriteByte('+')
277 case t
.ZoneOffset
< 0:
278 err
= out
.WriteByte('-')
285 offsetMinutes
:= t
.ZoneOffset
/ 60
286 if offsetMinutes
< 0 {
287 offsetMinutes
= -offsetMinutes
290 err
= marshalTwoDigits(out
, offsetMinutes
/60)
295 err
= marshalTwoDigits(out
, offsetMinutes%60
)
299 func stripTagAndLength(in
[]byte) []byte {
300 _
, offset
, err
:= parseTagAndLength(in
, 0)
307 func marshalBody(out
*forkableWriter
, value reflect
.Value
, params fieldParameters
) (err os
.Error
) {
308 switch value
.Type() {
310 return marshalUTCTime(out
, value
.Interface().(*time
.Time
))
312 return marshalBitString(out
, value
.Interface().(BitString
))
313 case objectIdentifierType
:
314 return marshalObjectIdentifier(out
, value
.Interface().(ObjectIdentifier
))
317 switch v
:= value
.(type) {
318 case *reflect
.BoolValue
:
320 return out
.WriteByte(1)
322 return out
.WriteByte(0)
324 case *reflect
.IntValue
:
325 return marshalInt64(out
, int64(v
.Get()))
326 case *reflect
.StructValue
:
327 t
:= v
.Type().(*reflect
.StructType
)
331 // If the first element of the structure is a non-empty
332 // RawContents, then we don't bother serialising the rest.
333 if t
.NumField() > 0 && t
.Field(0).Type
== rawContentsType
{
334 s
:= v
.Field(0).(*reflect
.SliceValue
)
336 bytes
:= make([]byte, s
.Len())
337 for i
:= 0; i
< s
.Len(); i
++ {
338 bytes
[i
] = uint8(s
.Elem(i
).(*reflect
.UintValue
).Get())
340 /* The RawContents will contain the tag and
341 * length fields but we'll also be writing
342 * those outselves, so we strip them out of
344 _
, err
= out
.Write(stripTagAndLength(bytes
))
351 for i
:= startingField
; i
< t
.NumField(); i
++ {
352 var pre
*forkableWriter
353 pre
, out
= out
.fork()
354 err
= marshalField(pre
, v
.Field(i
), parseFieldParameters(t
.Field(i
).Tag
))
360 case *reflect
.SliceValue
:
361 sliceType
:= v
.Type().(*reflect
.SliceType
)
362 if sliceType
.Elem().Kind() == reflect
.Uint8
{
363 bytes
:= make([]byte, v
.Len())
364 for i
:= 0; i
< v
.Len(); i
++ {
365 bytes
[i
] = uint8(v
.Elem(i
).(*reflect
.UintValue
).Get())
367 _
, err
= out
.Write(bytes
)
371 var params fieldParameters
372 for i
:= 0; i
< v
.Len(); i
++ {
373 var pre
*forkableWriter
374 pre
, out
= out
.fork()
375 err
= marshalField(pre
, v
.Elem(i
), params
)
381 case *reflect
.StringValue
:
382 if params
.stringType
== tagIA5String
{
383 return marshalIA5String(out
, v
.Get())
385 return marshalPrintableString(out
, v
.Get())
390 return StructuralError
{"unknown Go type"}
393 func marshalField(out
*forkableWriter
, v reflect
.Value
, params fieldParameters
) (err os
.Error
) {
394 // If the field is an interface{} then recurse into it.
395 if v
, ok
:= v
.(*reflect
.InterfaceValue
); ok
&& v
.Type().(*reflect
.InterfaceType
).NumMethod() == 0 {
396 return marshalField(out
, v
.Elem(), params
)
399 if v
.Type() == rawValueType
{
400 rv
:= v
.Interface().(RawValue
)
401 err
= marshalTagAndLength(out
, tagAndLength
{rv
.Class
, rv
.Tag
, len(rv
.Bytes
), rv
.IsCompound
})
405 _
, err
= out
.Write(rv
.Bytes
)
409 if params
.optional
&& reflect
.DeepEqual(v
.Interface(), reflect
.MakeZero(v
.Type()).Interface()) {
413 tag
, isCompound
, ok
:= getUniversalType(v
.Type())
415 err
= StructuralError
{fmt
.Sprintf("unknown Go type: %v", v
.Type())}
418 class
:= classUniversal
420 if params
.stringType
!= 0 {
421 if tag
!= tagPrintableString
{
422 return StructuralError
{"Explicit string type given to non-string member"}
424 tag
= params
.stringType
428 if tag
!= tagSequence
{
429 return StructuralError
{"Non sequence tagged as set"}
434 tags
, body
:= out
.fork()
436 err
= marshalBody(body
, v
, params
)
441 bodyLen
:= body
.Len()
443 var explicitTag
*forkableWriter
445 explicitTag
, tags
= tags
.fork()
448 if !params
.explicit
&& params
.tag
!= nil {
451 class
= classContextSpecific
454 err
= marshalTagAndLength(tags
, tagAndLength
{class
, tag
, bodyLen
, isCompound
})
460 err
= marshalTagAndLength(explicitTag
, tagAndLength
{
461 class
: classContextSpecific
,
463 length
: bodyLen
+ tags
.Len(),
471 // Marshal returns the ASN.1 encoding of val.
472 func Marshal(val
interface{}) ([]byte, os
.Error
) {
474 v
:= reflect
.NewValue(val
)
475 f
:= newForkableWriter()
476 err
:= marshalField(f
, v
, fieldParameters
{})
480 _
, err
= f
.writeTo(&out
)
481 return out
.Bytes(), nil