<<Grammar
Name="BERTree"
encoding_class="binary"
reference="source:http://en.wikipedia.org/wiki/Basic_encoding_rules"
>>
Top
{
int @byte;
int tag, length, n,tagclass;
bool init_() { tag = 0; length = 0; return true; }
bool add_Tag_() { tag *= 128; tag += n; return true; }
bool addLength_() { length *= 256; length+= @byte;return true; }
}
CREATE
{
#region overrides
public override string TreeNodeToString(PegNode node)
{
string s= GetRuleNameFromId(node.id_);
BERTreeNode berNode= node as BERTreeNode;
if( berNode!=null ) s+= ": " + berNode.TreeNodeToString(src_);
return s;
}
#endregion overrides
#region PegNode subclasses for BERTree
abstract class BERTreeNode : PegNode
{
internal BERTreeNode(PegNode parent, int id): base(parent, id){}
internal abstract string TreeNodeToString(byte[] src);
}
class TagNode : BERTreeNode
{
internal TagNode(PegNode parent, int id) : base(parent, id) {tagValue_ = -1;}
internal override string TreeNodeToString(byte[] src) {return tagValue_.ToString();}
internal int tagValue_;
}
class LengthNode : BERTreeNode
{
internal LengthNode(PegNode parent, int id) : base(parent, id) { lengthValue_ = 0;}
internal override string TreeNodeToString(byte[] src)
{
if (lengthValue_ <= 0) return "\u221E";
return lengthValue_.ToString();
}
internal int lengthValue_;
}
class PrimitiveValueNode : BERTreeNode
{
const int maxShow = 16;
internal PrimitiveValueNode(PegNode parent, int id)
: base(parent, id)
{ }
bool GetAsInteger(byte[] src, out string sInt)
{
int len = match_.Length, pos0 = match_.posBeg_, pos1 = match_.posEnd_;
sInt = "";
if (len == 0 || src[pos0] == 0 && len > 1 && (src[pos0 + 1] & 0x80) == 0) return false;
long val = (src[pos0] & 0x80) != 0 ? -1 : 0;
for (; pos0 != pos1; ++pos0)
{
val <<= 8;
val |= src[pos0];
}
sInt = val.ToString();
return true;
}
string GetAsAsciiString(byte[] src)
{
int pos0 = match_.posBeg_, pos1 = match_.posEnd_;
if (pos1 - pos0 > 16) pos1 = pos0 + 16;
StringBuilder sb= new StringBuilder();
for (; pos0 < pos1; ++pos0){
if (src[pos0] <= 0x7F && !char.IsControl(((char)src[pos0]))){
sb.Append((char)src[pos0]);
}
else{
sb.Append('.');
}
}
if (match_.posEnd_ > pos1) sb.Append("...");
return sb.ToString();
}
internal override string TreeNodeToString(byte[] src)
{
string display="";
if (match_.Length <= 8 && GetAsInteger(src, out display)){
display += " / ";
}
display += GetAsAsciiString(src);
return display;
}
}
#endregion PegNode subclasses for BERTree
PegNode TagNodeCreator(ECreatorPhase phase,PegNode parentOrCreated, int id)
{
if (phase == ECreatorPhase.eCreate || phase == ECreatorPhase.eCreateAndComplete){
return new TagNode(parentOrCreated, id);
}else{
((TagNode)parentOrCreated).tagValue_ = top.tag;
return null;
}
}
PegNode LengthNodeCreator(ECreatorPhase phase,PegNode parentOrCreated, int id)
{
if (phase == ECreatorPhase.eCreate || phase == ECreatorPhase.eCreateAndComplete){
return new LengthNode(parentOrCreated, id);
}else{
((LengthNode)parentOrCreated).lengthValue_ = top.length;
return null;
}
}
PegNode PrimitiveValueNodeCreator(ECreatorPhase phase, PegNode parentOrCreated, int id)
{
if (phase == ECreatorPhase.eCreate || phase == ECreatorPhase.eCreateAndComplete)
{
return new PrimitiveValueNode(parentOrCreated, id);
}
else
{
return null;
}
}
}
[1] ProtocolDataUnit: TLV;
[2] ^^TLV: init_
( TagWithConstructedFlag ConstructedLengthValue
/ Tag Length PrimitiveValue
);
[30]ConstructedLengthValue:
NoLength ConstructedDelimValue @(#0#0)
/ Length ConstructedValue;
[3]Tag: &BITS<7-8,.,:tagclass>
(OneOctetTag / MultiOctetTag / FATAL<"illegal TAG">);
[4] TagWithConstructedFlag:
&BITS<6,#1> Tag;
[5] ^^CREATE<TagNodeCreator> OneOctetTag:
!BITS<1-5,#b11111> BITS<1-5,.,:tag>;
[6] ^^CREATE<TagNodeCreator> MultiOctetTag:
.
(&BITS<8,#1> BITS<1-7,.,:n> add_Tag_)*
BITS<1-7,.,:n> add_Tag_;
[7] Length : OneOctetLength
/ NoLength
/ MultiOctetLength
/ FATAL<"illegal LENGTH">;
[8]^^CREATE<LengthNodeCreator> OneOctetLength:
&BITS<8,#0> BITS<1-7,.,:length>;
[9]^^CREATE<LengthNodeCreator> NoLength:
#x80;
[10]^^CREATE<LengthNodeCreator> MultiOctetLength:
&BITS<8,#1> BITS<1-7,.,:n>
(( .:byte addLength_){:n}/FATAL<"illegal Length">) ;
[11]^^CREATE<PrimitiveValueNodeCreator> PrimitiveValue:
(.{:length} / FATAL<"BER input ends before VALUE ends">);
[12]^^ConstructedDelimValue:
(!(#0#0) TLV)*;
[13]^^ConstructedValue
{
internal _ConstructedValue(BERTree ber)
{
parent = ber; len = 0; begEnd.posBeg_ = 0; begEnd.posEnd_ = 0;
}
BERTree parent;
int len;
PegBegEnd begEnd;
bool save_() { len = parent.top.length; return true; }
bool at_end_() { return len <= 0; }
bool decr_()
{
len -= begEnd.posEnd_ - begEnd.posBeg_;
return len >= 0;
}
}: save_
(!at_end_ TLV:begEnd (decr_/FATAL<"illegal length">))*;
<</Grammar>>