diff options
Diffstat (limited to 'src/pkg/asn1/marshal.go')
-rw-r--r-- | src/pkg/asn1/marshal.go | 52 |
1 files changed, 46 insertions, 6 deletions
diff --git a/src/pkg/asn1/marshal.go b/src/pkg/asn1/marshal.go index a3e1145b8..7212c91ef 100644 --- a/src/pkg/asn1/marshal.go +++ b/src/pkg/asn1/marshal.go @@ -5,6 +5,7 @@ package asn1 import ( + "big" "bytes" "fmt" "io" @@ -125,6 +126,43 @@ func int64Length(i int64) (numBytes int) { return } +func marshalBigInt(out *forkableWriter, n *big.Int) (err os.Error) { + if n.Sign() < 0 { + // A negative number has to be converted to two's-complement + // form. So we'll subtract 1 and invert. If the + // most-significant-bit isn't set then we'll need to pad the + // beginning with 0xff in order to keep the number negative. + nMinus1 := new(big.Int).Neg(n) + nMinus1.Sub(nMinus1, bigOne) + bytes := nMinus1.Bytes() + for i := range bytes { + bytes[i] ^= 0xff + } + if len(bytes) == 0 || bytes[0]&0x80 == 0 { + err = out.WriteByte(0xff) + if err != nil { + return + } + } + _, err = out.Write(bytes) + } else if n.Sign() == 0 { + // Zero is written as a single 0 zero rather than no bytes. + err = out.WriteByte(0x00) + } else { + bytes := n.Bytes() + if len(bytes) > 0 && bytes[0]&0x80 != 0 { + // We'll have to pad this with 0x00 in order to stop it + // looking like a negative number. + err = out.WriteByte(0) + if err != nil { + return + } + } + _, err = out.Write(bytes) + } + return +} + func marshalLength(out *forkableWriter, i int) (err os.Error) { n := lengthLength(i) @@ -334,6 +372,8 @@ func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameter return marshalBitString(out, value.Interface().(BitString)) case objectIdentifierType: return marshalObjectIdentifier(out, value.Interface().(ObjectIdentifier)) + case bigIntType: + return marshalBigInt(out, value.Interface().(*big.Int)) } switch v := value; v.Kind() { @@ -351,7 +391,7 @@ func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameter startingField := 0 // If the first element of the structure is a non-empty - // RawContents, then we don't bother serialising the rest. + // RawContents, then we don't bother serializing the rest. if t.NumField() > 0 && t.Field(0).Type == rawContentsType { s := v.Field(0) if s.Len() > 0 { @@ -361,7 +401,7 @@ func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameter } /* The RawContents will contain the tag and * length fields but we'll also be writing - * those outselves, so we strip them out of + * those ourselves, so we strip them out of * bytes */ _, err = out.Write(stripTagAndLength(bytes)) return @@ -418,6 +458,10 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters) return marshalField(out, v.Elem(), params) } + if params.optional && reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) { + return + } + if v.Type() == rawValueType { rv := v.Interface().(RawValue) err = marshalTagAndLength(out, tagAndLength{rv.Class, rv.Tag, len(rv.Bytes), rv.IsCompound}) @@ -428,10 +472,6 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters) return } - if params.optional && reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) { - return - } - tag, isCompound, ok := getUniversalType(v.Type()) if !ok { err = StructuralError{fmt.Sprintf("unknown Go type: %v", v.Type())} |