Exemple #1
0
        protected byte[] FillPow2(TypeLength tl)
        {
            int resLength = NextPow2(tl.Length);

            if (tl.Length == 1 || tl.Length == resLength)
            {
                return(_reader.ReadBytes(tl.Length));
            }

            var res = new byte[resLength];

            _reader.ReadBytes(tl.Length).CopyTo(res, resLength - tl.Length);

            /*  the specification is erroneous on this
             *  it allows _leading_ all-ones or all-zeros bytes to be omitted
             *  since it mandates big-endian, and in signed integers the sign will be in the MSB
             *  it can't possibly omit any bytes */

            for (int i = 0; i < (resLength - tl.Length); i++)
            {
                res[i] = 0x00;
            }

            return(res);
        }
Exemple #2
0
        protected void FillField(object obj, FieldInfo field)
        {
            var rawDataAttributes = field.GetCustomAttributes(typeof(RawData), false);

            if (rawDataAttributes.Length == 1)
            {
                var data     = (rawDataAttributes[0] as RawData).Data;
                var dataRead = _reader.ReadBytes(data.Length);
                if (!data.SequenceEqual(dataRead))
                {
                    throw new InvalidDataException("RawData attribute data and stream data mismatch");
                }
                // we don't bother filling the field with anything
                // RawData fields are only there to facilitate parsing
                return;
            }

            var isList = field.FieldType.IsGenericType && field.FieldType.GetGenericTypeDefinition() == typeof(List <>);

            if (isList)
            {
                var tl = new TypeLength(Source);
                if (tl.Type != SMLType.List)
                {
                    throw new InvalidDataException("Expected List");
                }
                if (tl.IsOptionalMarker)
                {
                    return;
                }

                var underlyingType = field.FieldType.GetGenericArguments()[0];
                var list           = Activator.CreateInstance(field.FieldType, tl.Length) as IList;
                for (int i = 0; i < tl.Length; i++)
                {
                    list.Add(ReadElement(underlyingType));
                }

                field.SetValue(obj, list);
            }
            else
            {
                var underlyingType = Nullable.GetUnderlyingType(field.FieldType);
                var isNullable     = underlyingType != null;
                var isOptional     = isNullable || (field.GetCustomAttributes(false).Any(attribute => attribute is Optional));
                var value          = ReadElement(isNullable ? underlyingType : field.FieldType, isOptional);

                // optional and not present in stream
                if (value == null)
                {
                    return;
                }

                field.SetValue(obj, value);
            }
        }
Exemple #3
0
        protected object HandleChoice(Type type, TypeLength tl)
        {
            if (tl.Type != SMLType.List || tl.Length != 2)
            {
                throw new InvalidDataException("Invalid Choice; expected list with two items (tag and element)");
            }

            var tag    = (uint)Convert.ChangeType(ReadPOD(), typeof(uint));
            var fields = type.GetFields();

            foreach (var field in fields)
            {
                var cases = field.GetCustomAttributes(typeof(ChoiceCase), false);

                // ignore fields without a ChoiceCase
                if (cases.Length <= 0)
                {
                    continue;
                }

                // throw on fields with more than one case; possible, but not in the specification
                if (cases.Length > 1)
                {
                    throw new ArgumentException("Type contains field (" + field.Name + ") with more than one ChoiceCase");
                }

                if ((cases[0] as ChoiceCase).Tag != tag)
                {
                    continue;
                }

                // we have the correct field
                var ret = Activator.CreateInstance(type);
                FillField(ret, field);
                return(ret);
            }

            throw new InvalidDataException("No case found for tag " + tag);
        }
Exemple #4
0
        public object Read(Type type)
        {
            var attributes = type.GetCustomAttributes(false);

            var tl = new TypeLength(Source);

            if (tl.IsOptionalMarker)
            {
                return(null);
            }

            if (attributes.Any(attribute => attribute is Sequence))
            {
                return(HandleSequence(type, tl));
            }

            if (attributes.Any(attribute => attribute is Choice))
            {
                return(HandleChoice(type, tl));
            }

            throw new ArgumentException("Type doesn't use any of the SML attributes");
        }
Exemple #5
0
        protected object HandleSequence(Type type, TypeLength tl)
        {
            if (tl.Type != SMLType.List)
            {
                throw new InvalidDataException("Expected list");
            }

            var fieldCount = tl.Length;
            var fields     = type.GetFields();

            if (fields.Count() != fieldCount)
            {
                throw new InvalidDataException("Read list with " + fieldCount + " items, expected " + fields.Count());
            }

            var ret = Activator.CreateInstance(type);

            foreach (var field in fields)
            {
                FillField(ret, field);
            }

            return(ret);
        }
Exemple #6
0
        protected object ReadPOD(bool optional)
        {
            var tl = new TypeLength(Source);

            if (optional && tl.IsOptionalMarker)
            {
                return(null);
            }

            switch (tl.Type)
            {
            case SMLType.Boolean:
                return(_reader.ReadByte() != 0);

            case SMLType.OctetString:
                return(_reader.ReadBytes(tl.Length));

            case SMLType.Integer:
            {
                var raw = FillPow2(tl);
                if (raw.Length == 1)
                {
                    return((sbyte)raw[0]);
                }
                if (raw.Length == 2)
                {
                    return(Endianness.Reverse(BitConverter.ToInt16(raw, 0)));
                }
                if (raw.Length == 4)
                {
                    return(Endianness.Reverse(BitConverter.ToInt32(raw, 0)));
                }
                if (raw.Length == 8)
                {
                    return(Endianness.Reverse(BitConverter.ToInt64(raw, 0)));
                }
                throw new InvalidDataException("Invalid integer, expected 1, 2, 4 or 8 bytes, got " + raw.Length);
            }

            case SMLType.Unsigned:
            {
                var raw = FillPow2(tl);
                if (raw.Length == 1)
                {
                    return(raw[0]);
                }
                if (raw.Length == 2)
                {
                    return(Endianness.Reverse(BitConverter.ToUInt16(raw, 0)));
                }
                if (raw.Length == 4)
                {
                    return(Endianness.Reverse(BitConverter.ToUInt32(raw, 0)));
                }
                if (raw.Length == 8)
                {
                    return(Endianness.Reverse(BitConverter.ToUInt64(raw, 0)));
                }
                throw new InvalidDataException("Invalid unsigned, expected 1, 2, 4 or 8 bytes, got " + raw.Length);
            }

            case SMLType.List:
                // we don't handle this directly, as in recursive
                // we could, but it doesn't fit into the reflection/type model
                throw new InvalidDataException("ReadPOD is only for POD types");
            }

            throw new InvalidDataException("Invalid TypeLength");
        }