internal void ClearAttributes()
 {
     TagEnum = Bms1Tag.Attribute;
     ObjectName = null;
     ObjectType = null;
     CollectionElementCount = Bms1Length.None; // -1
     CollectionElementBaseType = -1;
     NameValues = null;
     Namespaces = null;
     TagSetNumber = 0;
     IsCharacterType = false;
 }
        public void ReadTag(BinaryReader stream)
        {
            TagEnum = Bms1Tag.UnknownValue;
            IsArrayData = false;
            DataLength = 0;
            _lengthSpecifier = 0;
            BlockTypeId = -1;
            ChecksumAvailable = false;

            TagByte = stream.ReadByte(); // 0..255
            if (TagByte < 10)
            {
                if (TagByte == 0)
                {
                    throw new Bms1Exception("invalid value tag 0");
                }
                else if (TagByte == 7) TagEnum = Bms1Tag.Null;
                else if (TagByte == 8) TagEnum = Bms1Tag.BoolFalse;
                else if (TagByte == 9) TagEnum = Bms1Tag.BoolTrue;
            }
            else if (TagByte < 170) // Values
            {
                EvaluateDataLength(stream);
                if (DataLength == Bms1Length.Undefined)
                {
                    throw new Bms1Exception("undefined data length specifier 3");
                }

                if (TagByte < 150)
                {
                    // Known value tags
                    TagEnum = (Bms1Tag)(TagByte - _lengthSpecifier);
                }
            }
            else if (TagByte < 245) // Attributes --> skip unused data
            {
                EvaluateDataLength(stream);

                TagEnum = Bms1Tag.Attribute;
                var attributeGroup = TagByte; // special handling for 240 and above
                if (TagByte < 240)
                {
                    attributeGroup -= _lengthSpecifier; // normal groups below 240
                }

                switch (attributeGroup)
                {
                    case 170:
                        ObjectName = ReadDataString(stream);
                        break;

                    case 180:
                        ObjectType = ReadDataString(stream);
                        break;

                    case 190:
                        if (NameValues == null)
                        {
                            NameValues = new List<string>();
                        }
                        NameValues.Add(ReadDataString(stream));
                        break;

                    case 200:
                        if (Namespaces == null)
                        {
                            Namespaces = new List<string>();
                        }
                        Namespaces.Add(ReadDataString(stream));
                        break;

                    case 230:
                        if (_lengthSpecifier == 3) // 233
                        {
                            CollectionElementCount = Bms1Length.Open; // open collection
                        }
                        else if (_lengthSpecifier <= 4) // 230, 231, 232, 234
                        {
                            DataLength = _lengthSpecifier;
                            var len = ReadDataUInt(stream);
                            if (len > Int32.MaxValue) // TODO Max
                            {
                                throw new Bms1Exception("collection length " + len + " out of bounds for attribute " + TagByte);
                            }
                            CollectionElementCount = (int)len; // >=0: CollectionAtribute is set.
                        }
                        else
                        {
                            SkipData(stream); // yet unknown attributes
                        }
                        break;

                    case 240: IsCharacterType = true; break;
                    case 241: TagSetNumber = 1; break;
                    case 242: TagSetNumber = 2; break;
                    case 243: TagSetNumber = 3; break;
                    case 244: break;

                    default:
                        SkipData(stream);
                        break;
                }
            }
            else // >= 245: Framing tags with specific data length
            {
                switch (TagByte)
                {
                    case 245:
                        TagEnum = Bms1Tag.MessageStart;
                        var pattern = stream.ReadUInt32();
                        if (pattern != 0x544D4201) // decimal data [01, 66, 77, 83]
                        {
                            throw new Bms1Exception(string.Format("invalid message start pattern 0x{0:X}", pattern));
                        }
                        break;

                    case 246: TagEnum = Bms1Tag.BlockStart; break;
                    case 247: TagEnum = Bms1Tag.BlockStart; BlockTypeId = stream.ReadUInt16(); break;
                    case 248: TagEnum = Bms1Tag.NullBlock; BlockTypeId = stream.ReadUInt16(); break;
                    case 249: TagEnum = Bms1Tag.BlockEnd; break;
                    case 250: TagEnum = Bms1Tag.BlockEnd; Checksum = stream.ReadUInt32(); ChecksumAvailable = true; break;
                    case 251: TagEnum = Bms1Tag.MessageFooter; break;
                    case 252: TagEnum = Bms1Tag.MessageEnd; break;
                    case 253: stream.ReadUInt32(); break;
                    case 254: stream.ReadUInt32(); break;

                    default:
                        throw new Bms1Exception("invalid framing tag = " + TagByte); // 255
                }
            }
        }
 public void WriteDataSInt(Bms1Tag tag, Int32 data)
 {
     WriteAttributes();
     if (data == 0)
     {
         Stream.Write((byte)tag);
     }
     else if (data > 0)
     {
         // Positive, most significant bit must be zero
         if (data < 0x80)
         {
             Stream.Write((byte)(tag + Bms1LengthSpec.L1));
             Stream.Write((SByte)(data));
         }
         else if (data < 0x8000)
         {
             Stream.Write((byte)(tag + Bms1LengthSpec.L2));
             Stream.Write((Int16)(data));
         }
         else
         {
             Stream.Write((byte)(tag + Bms1LengthSpec.L4));
             Stream.Write(data);
         }
     }
     else
     {   // Negative, most significant bit must be set
         if (data >= -0x80)// > 0xFFFFFF70)
         {
             Stream.Write((byte)(tag + Bms1LengthSpec.L1));
             Stream.Write((SByte)(data));
         }
         else if (data >= -0x8000) // > 0xFFFF7000)
         {
             Stream.Write((byte)(tag + Bms1LengthSpec.L2));
             Stream.Write((Int16)(data));
         }
         else
         {
             Stream.Write((byte)(tag + Bms1LengthSpec.L4));
             Stream.Write(data);
         }
     }
 }
 public void WriteDataSInt64(Bms1Tag tag, Int64 data)
 {
     if (data >= 0)
     {
         if (data < 0x80000000)
         {
             WriteDataSInt(tag, (Int32)data);
         }
         else
         {
             WriteAttributes();
             Stream.Write((byte)(tag + Bms1LengthSpec.L8));
             Stream.Write(data);
         }
     }
     else
     {
         if (data >= -0x80000000)
         {
             WriteDataSInt(tag, (Int32)data);
         }
         else
         {
             WriteAttributes();
             Stream.Write((byte)(tag + Bms1LengthSpec.L8));
             Stream.Write(data);
         }
     }
 }
 public void WriteDataUInt64(Bms1Tag tag, UInt64 data)
 {
     WriteAttributes();
     if (data <= 0xFFFFFFFF)
     {
         WriteTagAndUInt((byte)tag, (UInt32)data);
     }
     else
     {
         Stream.Write((byte)(tag + Bms1LengthSpec.L8));
         Stream.Write(data);
     }
 }
 public void WriteDataUInt(Bms1Tag tag, UInt32 data)
 {
     WriteAttributes();
     WriteTagAndUInt((byte)tag, data);
 }
 public void WriteDataString(Bms1Tag tag, string data)
 {
     WriteAttributes();
     WriteTagAndString((byte)tag, data);
 }
 public void WriteAttributesAndTag(Bms1Tag tag, int dataLength)
 {
     WriteAttributes();
     WriteTagAndLength((byte)tag, dataLength);
 }
 public void WriteAttributesAndTag(Bms1Tag tag)
 {
     WriteAttributes();
     Stream.Write((byte)tag);
 }