static void Parse(TextWriter tw, int depth, AsnElt ae) { Indent(tw, depth); tw.Write("("); switch (ae.TagClass) { case AsnElt.APPLICATION: tw.Write("[application " + ae.TagValue + "]"); break; case AsnElt.CONTEXT: tw.Write("[" + ae.TagValue + "]"); break; case AsnElt.PRIVATE: tw.Write("[private " + ae.TagValue + "]"); break; default: switch (ae.TagValue) { case AsnElt.BOOLEAN: tw.Write("bool " + ae.GetBoolean() + ")"); return; case AsnElt.INTEGER: tw.Write("int " + ae.GetIntegerHex() + ")"); return; case AsnElt.BIT_STRING: int bitLen; byte[] bs = ae.GetBitString(out bitLen); tw.Write("bits " + (bs.Length * 8 - bitLen)); PrintBytes(tw, depth, bs); tw.Write(")"); return; case AsnElt.OCTET_STRING: tw.Write("blob"); PrintBytes(tw, depth, ae.CopyValue()); tw.Write(")"); return; case AsnElt.NULL: ae.CheckNull(); tw.Write("null)"); return; case AsnElt.OBJECT_IDENTIFIER: string oid = ae.GetOID(); if (!numOID) { oid = AsnOID.ToName(oid); } tw.Write("oid " + oid + ")"); return; case AsnElt.NumericString: tw.Write("numeric " + EscapeString(ae.GetString()) + ")"); return; case AsnElt.PrintableString: tw.Write("printable " + EscapeString(ae.GetString()) + ")"); return; case AsnElt.IA5String: tw.Write("ia5 " + EscapeString(ae.GetString()) + ")"); return; case AsnElt.TeletexString: tw.Write("teletex " + EscapeString(ae.GetString()) + ")"); return; case AsnElt.UTF8String: tw.Write("utf8 " + EscapeString(ae.GetString()) + ")"); return; case AsnElt.BMPString: tw.Write("bmp " + EscapeString(ae.GetString()) + ")"); return; case AsnElt.UniversalString: tw.Write("utf32 " + EscapeString(ae.GetString()) + ")"); return; case AsnElt.UTCTime: tw.Write("utc " + EscapeString(ae.GetString()) + " {" + ae.GetTime() + "} )"); return; case AsnElt.GeneralizedTime: tw.Write("gentime " + EscapeString(ae.GetString()) + " {" + ae.GetTime() + "} )"); return; case AsnElt.SEQUENCE: if (!ae.Constructed) { throw new AsnException( "Non-constructed SEQUENCE"); } tw.Write("sequence"); ParseSubs(tw, depth, ae); tw.Write(")"); return; case AsnElt.SET: if (!ae.Constructed) { throw new AsnException( "Non-constructed SET"); } tw.Write("set"); ParseSubs(tw, depth, ae); tw.Write(")"); return; default: tw.Write( "[universal " + ae.TagValue + "]"); break; } break; } if (ae.Constructed) { tw.Write("sequence"); ParseSubs(tw, depth, ae); tw.Write(")"); } else { tw.Write("blob"); PrintBytes(tw, depth, ae.CopyValue()); tw.Write(")"); } }
/* * Build next element; will return null if (and only if) the next * non-whitespace character is not an opening parenthesis. */ static AsnElt BuildNext() { int c = PeekNextChar(); if (c != '(') { return(null); } LowRead(); c = NextChar(); int tagClass = -1; int tagValue = -1; if (c == '[') { c = NextChar(); if (!IsWordChar(c)) { throw new IOException( "expected tag class/value"); } string w1 = ParseWord(c); c = NextChar(); string w2 = null; if (IsWordChar(c)) { w2 = ParseWord(c); c = NextChar(); } if (c != ']') { throw new IOException( "invalid tag specification"); } if (w2 == null) { tagClass = AsnElt.CONTEXT; tagValue = ParseTagValue(w1); } else { tagClass = ParseTagClass(w1); tagValue = ParseTagValue(w2); } c = NextChar(); } if (c < 0) { throw new IOException("truncated input"); } if (!IsWordChar(c)) { throw new IOException("expected type name"); } string tn = ParseWord(c); AsnElt ret; switch (tn.ToLowerInvariant()) { case "bool": case "boolean": string bv = ParseWord(); switch (bv.ToLowerInvariant()) { case "true": case "on": case "yes": case "1": ret = AsnElt.BOOL_TRUE; break; case "false": case "off": case "no": case "0": ret = AsnElt.BOOL_FALSE; break; default: throw new IOException( "invalid boolean value: " + bv); } break; case "int": case "integer": string iv = ParseWord(); ret = BuildInteger(iv); break; case "bits": string ibw = ParseWord(); int ignb; if (!Int32.TryParse(ibw, out ignb) || ignb < 0 || ignb > 7) { throw new IOException("invalid number of" + " ignored bits: " + ibw); } byte[] bsb = ParseHexBytes(); int imask = 0xFF >> (8 - ignb); if (ignb > 0 && (bsb.Length == 0 || (bsb[bsb.Length - 1] & imask) != 0)) { throw new IOException("non-zero ignored bits"); } ret = AsnElt.MakeBitString(ignb, bsb); break; case "blob": case "bytes": ret = AsnElt.MakeBlob(ParseHexBytes()); break; case "null": ret = AsnElt.NULL_V; break; case "oid": string oid = AsnOID.ToOID(ParseWord()); ret = AsnElt.MakeOID(oid); break; case "numeric": case "numericstring": ret = AsnElt.MakeString( AsnElt.NumericString, ParseString()); break; case "printable": case "printablestring": ret = AsnElt.MakeString( AsnElt.PrintableString, ParseString()); break; case "ia5": case "ia5string": ret = AsnElt.MakeString( AsnElt.IA5String, ParseString()); break; case "teletex": case "teletexstring": ret = AsnElt.MakeString( AsnElt.TeletexString, ParseString()); break; case "utf8": case "utf-8": case "utf8string": ret = AsnElt.MakeString( AsnElt.UTF8String, ParseString()); break; case "utf16": case "utf-16": case "bmp": case "bmpstring": ret = AsnElt.MakeString( AsnElt.BMPString, ParseString()); break; case "utf32": case "utf-32": case "universal": case "universalstring": ret = AsnElt.MakeString( AsnElt.UniversalString, ParseString()); break; case "utc": case "utctime": ret = AsnElt.MakeString( AsnElt.UTCTime, ParseString()); break; case "gentime": case "generalizedtime": ret = AsnElt.MakeString( AsnElt.GeneralizedTime, ParseString()); break; case "setof": ret = BuildSetOf(); break; case "set": ret = BuildConstructed(AsnElt.SET); break; case "sequence": ret = BuildConstructed(AsnElt.SEQUENCE); break; default: throw new IOException("unknown type name: " + tn); } if (NextChar() != ')') { throw new IOException("expected closing parenthesis"); } /* * Apply the implicit tag, if any. */ if (tagClass >= 0) { ret = AsnElt.MakeImplicit(tagClass, tagValue, ret); } return(ret); }