Fantom

 

//
// Copyright (c) 2021, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
//   06 Aug 2021 Matthew Giannini Creation
//

**
** Models an ASN.1 binary primitive type. These types are backed by a Buf.
**
@NoDoc const class AsnBin : AsnObj
{

//////////////////////////////////////////////////////////////////////////
// Construction
//////////////////////////////////////////////////////////////////////////

  new make(AsnTag[] tags, Buf buf) : super(tags, Unsafe(buf.dup))
  {
  }

//////////////////////////////////////////////////////////////////////////
// AsnBin
//////////////////////////////////////////////////////////////////////////

  ** Does this represent the ASN.1 'ANY' type
  override Bool isAny() { this.univTag == AsnTag.univAny }

  ** Get the number of octets in this binary type
  Int size() { unsafeBuf.size }

  ** Convenience to read the contents of the binary object as a UTF-8 string
  Str readAllStr() { forRead.readAllStr(false) }

  ** Get a safe copy of the contents of this binary object
  override Buf buf() { unsafeBuf.dup }

  internal Buf forRead() { unsafeBuf.seek(0) }

  private Buf unsafeBuf() { ((Unsafe)val).val }

//////////////////////////////////////////////////////////////////////////
// Decode
//////////////////////////////////////////////////////////////////////////

  AsnObj decode(AsnObj? spec := null)
  {
    if (spec == null) return this

    r := BerReader(unsafeBuf.in)
    t := this.tags[0..<-1].add(spec.univTag)
    switch (spec.univTag)
    {
      case AsnTag.univSeq:      return AsnSeq(t, r.readItems)
      case AsnTag.univBool:     return AsnObj(t, r.readBool)
      case AsnTag.univInt:      return AsnObj(t, r.readInt)
      case AsnTag.univBits:     return AsnBin(t, r.readBits)
      case AsnTag.univOcts:     return AsnBin(t, r.readOcts)
      case AsnTag.univNull:     return AsnObj(t, null)
      case AsnTag.univOid:      return AsnOid(t, r.readOid)
      case AsnTag.univEnum:     return AsnObj(t, r.readInt)
      case AsnTag.univUtf8:
      case AsnTag.univPrintStr:
      case AsnTag.univIa5Str:
      case AsnTag.univVisStr:
        // fall-through
        return AsnObj(t, r.readUtf8)
      case AsnTag.univUtcTime:  return AsnObj(t, r.readUtcTime)
      case AsnTag.univGenTime:  return AsnObj(t, r.readGenTime)
      case AsnTag.univSet:      return AsnSet(t, r.readItems)

    }
    throw AsnErr("No reader for type: $spec")
  }

//////////////////////////////////////////////////////////////////////////
// AsnObj
//////////////////////////////////////////////////////////////////////////

  override AsnBin push(AsnTag tag)
  {
    AsnBin([tag].addAll(this.tags), forRead)
  }

  protected override Int valHash()
  {
    unsafeBuf.toHex.hash
  }

  protected override Bool valEquals(AsnObj obj)
  {
    that := obj as AsnBin
    if (that == null) return false
    if (this.size != that.size) return false
    if (this.unsafeBuf.toHex != that.unsafeBuf.toHex) return false
    return true
  }
}