How Unmarshal Works And Alternatives

The Unmarshal function is the most convenient way to decode, but taking a look at how it works also provides alternatives, should you want them.

First, we'll look at the other BER decode functions that are generated. There are two general forms:

          func BerDecode<type name>(pctxt *asn1rt.OSRTContext, impltag bool, impllen *asn1rt.BerLength) (value <go type>, err error)
          
          func (pvalue *<type name>) BerDecode(pctxt *asn1rt.OSRTContext, impltag bool, impllen *asn1rt.BerLength) (err error)
        

Here are two examples from the employee sample:

          func BerDecodeDate(pctxt *asn1rt.OSRTContext, impltag bool, impllen *asn1rt.BerLength) (value int64, err error)
          
          func (pvalue *Name) BerDecode(pctxt *asn1rt.OSRTContext, impltag bool, impllen *asn1rt.BerLength) (err error)
        

The first form is used when the Go type for the ASN.1 type is a built-in Go type - so basically it's used for the simple, nonconstructed ASN.1 types. The second form is used when the Go type is a generated type. The 'impltag' and 'impllen' arguments are for dealing with implicit tags. A user calling a function of this form at the top level would almost always set these arguments to 'false' and 'nil' respectively.

Now we can look at the Unmarshal function to see what it does and how these functions are used:

   // Create context object to manage encoding
   pctxt := new(asn1rt.OSRTContext)
   pctxt.InitDecodeBytes(b)   // Initialize for decoding; b holds the encoded data
   ...     
   err = v.BerDecode(pctxt, false, nil)   // Invoke the decode function; v is a generated type
   ...
   return pctxt.BufferRemBytes(), err