module Krypt
  class KryptError < StandardError; end

  module ASN1
    class ASN1Error < KryptError; end
    class ParseError < ASN1Error; end
    class SerializeError < ASN1Error; end

    END_OF_CONTENTS = 0
    BOOLEAN = 1
    ...
    BMP_STRING = 30

    UNIVERSAL_TAG_NAME = ["END_OF_CONTENTS", "BOOLEAN", ... ]

    def self.decode(str_or_file_or_readable)
    end

    class ASN1Data
      attr_accessor :tag, :tag_class, :value
      attr_reader :infinite_length

      def initialize(value, tag, tag_class); end
      def to_der; end
      def encode_to(io); end #=> self
    end

    class Primitive < ASN1Data
    end

    class Constructive < ASN1Data
      attr_writer :infinite_length # ?
      def each; end
    end

    class EndOfContents < Primitive; end
    class Boolean < Primitive; end
    class Integer < Primitive; end
    class Enumerated < Primitive; end
    class BitString < Primitive; end
    class OctetString < Primitive; end
    class UTF8String < Primitive; end
    class NumericString < Primitive; end
    class PrintableString < Primitive; end
    class T61String < Primitive; end
    class VideotexString < Primitive; end
    class IA5String < Primitive; end
    class GraphicString < Primitive; end
    class ISO64String < Primitive; end
    class GeneralString < Primitive; end
    class UniversalString < Primitive; end
    class BMPString < Primitive; end
    class Null < Primitive; end
    class ObjectId < Primitive; end
    class UTCTime < Primitive; end
    class GeneralizedTime < Primitive; end

    class Sequence < Constructive; end
    class Set < Constructive; end

    class Parser
      def next(io); end #=> Header
    end

    class Header
      attr_reader :tag, :tag_class, :length, :header_length
      def constructed?; end
      def infinite?; end

      def bytes; end #=> String
      def encode_to(io); end #=> self

      def skip_value; end
      def value; end
      def value_io; end # get value (V of TLV) stream

      def to_s; end
    end

    class Instream
      def read(len = nil, buf = nil); end
      def seek(offset, whence = SEEK_SET); end
    end
  end
end
