Represents a writer that provides the means to generate BER-encoded output, as specified in "X.690"X.690.
Only the subset defined in the "Ember+ Specification"Ember+ Specification is supported.
Inheritance: IDisposable
Exemple #1
0
        public void ExceptionTest()
        {
            AssertThrow <ArgumentNullException>(() => new EmberWriter(null, 1).Dispose());
            AssertThrow <ArgumentException>(() => new EmberWriter(new MemoryStream(), 0).Dispose());

            using (var writer = new EmberWriter(new MemoryStream(), 1))
            {
                var outer = EmberId.CreateApplication(0);

                AssertThrow <ArgumentNullException>(
                    () => writer.WriteValue(outer, (byte[])null),
                    () => writer.WriteValue(outer, (int[])null),
                    () => writer.WriteValue(outer, (string)null));

                AssertThrow <ArgumentOutOfRangeException>(
                    () => writer.WriteStartApplicationDefinedType(outer, InnerNumber.FirstApplication - 1));

                writer.Dispose();
                AssertThrow <ObjectDisposedException>(
                    () => writer.WriteValue(outer, true),
                    () => writer.WriteValue(outer, 0),
                    () => writer.WriteValue(outer, new byte[] { }),
                    () => writer.WriteValue(outer, 0.0),
                    () => writer.WriteValue(outer, string.Empty),
                    () => writer.WriteValue(outer, new int[] { }),
                    () => writer.WriteStartSequence(outer),
                    () => writer.WriteStartSet(outer),
                    () => writer.WriteStartApplicationDefinedType(outer, InnerNumber.FirstApplication),
                    () => writer.WriteEndContainer());
            }
        }
        /// <summary>Reads data and writes it to <paramref name="writer"/> until the end of the current container is
        /// reached.</summary>
        /// <returns>The contents of the of the data value with the outer id <paramref name="outerId"/>, if such a
        /// data value was found in the current container and its contents is primitive; otherwise, <c>null</c>.
        /// </returns>
        /// <exception cref="ObjectDisposedException"><see cref="Dispose"/> has been called.</exception>
        /// <remarks>
        /// <para>While <see cref="Read"/> returns <c>true</c> and <see cref="InnerNumber"/> is not equal to
        /// <see cref="Ember.InnerNumber.EndContainer"/>, calls <see cref="Copy"/>.</para>
        /// </remarks>
        public object CopyToEndContainer(EmberWriter writer, EmberId?outerId)
        {
            if (writer == null)
            {
                throw new ArgumentNullException(nameof(writer));
            }

            object result = null;
            var    inner  = -1;

            while (this.Read() && ((inner = this.innerNumber.GetValueOrDefault()) != Ember.InnerNumber.EndContainer))
            {
                var candidate = this.CopyCore(writer, inner);

                if (this.outer.HasValue && (this.outer.Value == outerId))
                {
                    result = candidate;
                }
            }

            if (inner == Ember.InnerNumber.EndContainer)
            {
                writer.WriteEndContainer();
            }

            return(result);
        }
        public void ExceptionTest()
        {
            AssertThrow<ArgumentNullException>(() => new EmberWriter(null, 1).Dispose());
            AssertThrow<ArgumentException>(() => new EmberWriter(new MemoryStream(), 0).Dispose());

            using (var writer = new EmberWriter(new MemoryStream(), 1))
            {
                var outer = EmberId.CreateApplication(0);

                AssertThrow<ArgumentNullException>(
                    () => writer.WriteValue(outer, (byte[])null),
                    () => writer.WriteValue(outer, (int[])null),
                    () => writer.WriteValue(outer, (string)null));

                AssertThrow<ArgumentOutOfRangeException>(
                    () => writer.WriteStartApplicationDefinedType(outer, InnerNumber.FirstApplication - 1));

                writer.Dispose();
                AssertThrow<ObjectDisposedException>(
                    () => writer.WriteValue(outer, true),
                    () => writer.WriteValue(outer, 0),
                    () => writer.WriteValue(outer, new byte[] { }),
                    () => writer.WriteValue(outer, 0.0),
                    () => writer.WriteValue(outer, string.Empty),
                    () => writer.WriteValue(outer, new int[] { }),
                    () => writer.WriteStartSequence(outer),
                    () => writer.WriteStartSet(outer),
                    () => writer.WriteStartApplicationDefinedType(outer, InnerNumber.FirstApplication),
                    () => writer.WriteEndContainer());
            }
        }
        private static void WriteRelativeObjectIdentifier(XmlReader reader, EmberWriter writer, EmberId fieldId)
        {
            var pathElements = ReadValue(reader, r => r.ReadContentAsString()).Split('.');
            var value        = (pathElements.Length == 1) && string.IsNullOrEmpty(pathElements[0]) ?
                               new int[0] : pathElements.Select(s => int.Parse(s, InvariantCulture)).ToArray();

            writer.WriteValue(fieldId, value);
        }
Exemple #5
0
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        private static void AssertEncode(Action <EmberWriter> write, params byte[] expected)
        {
            MemoryStream stream;

            using (stream = new MemoryStream())
                using (var writer = new EmberWriter(stream, 1))
                {
                    write(writer);
                }

            CollectionAssert.AreEqual(expected, stream.ToArray());
        }
        /// <summary>Reads XML with <paramref name="reader"/> and returns the equivalent EmBER representation.</summary>
        /// <exception cref="ArgumentNullException"><paramref name="reader"/> equals <c>null</c>.</exception>
        /// <exception cref="XmlException">The XML is invalid, see <see cref="Exception.Message"/> for details.
        /// </exception>
        public byte[] FromXml(XmlReader reader)
        {
            using (var stream = new MemoryStream())
            {
                using (var writer = new EmberWriter(stream))
                {
                    this.FromXml(reader, writer);
                }

                return(stream.ToArray());
            }
        }
        /// <summary>Reads XML with <paramref name="reader"/> and writes the equivalent EmBER representation with
        /// <paramref name="writer"/>.</summary>
        /// <exception cref="ArgumentNullException"><paramref name="reader"/> and/or <paramref name="writer"/> equal
        /// <c>null</c>.</exception>
        /// <exception cref="XmlException">The XML is invalid, see <see cref="Exception.Message"/> for details.
        /// </exception>
        public void FromXml(XmlReader reader, EmberWriter writer)
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            if (writer == null)
            {
                throw new ArgumentNullException(nameof(writer));
            }

            this.FromXmlCore(reader, writer, default(FieldPath <string, string>), EmberGlobal.Name);
        }
        private object CopyCore(EmberWriter writer, int inner)
        {
            switch (inner)
            {
            case Ember.InnerNumber.Boolean:
                var boolean = this.ReadContentsAsBoolean();
                writer.WriteValue(this.outer.GetValueOrDefault(), boolean);
                return(boolean);

            case Ember.InnerNumber.Integer:
                var int64 = this.ReadContentsAsInt64();
                writer.WriteValue(this.outer.GetValueOrDefault(), int64);
                return(int64);

            case Ember.InnerNumber.Octetstring:
                var byteArray = this.ReadContentsAsByteArray();
                writer.WriteValue(this.outer.GetValueOrDefault(), byteArray);
                return(byteArray);

            case Ember.InnerNumber.Real:
                var dbl = this.ReadContentsAsDouble();
                writer.WriteValue(this.outer.GetValueOrDefault(), dbl);
                return(dbl);

            case Ember.InnerNumber.Utf8String:
                var str = this.ReadContentsAsString();
                writer.WriteValue(this.outer.GetValueOrDefault(), str);
                return(str);

            case Ember.InnerNumber.RelativeObjectIdentifier:
                var int32Array = this.ReadContentsAsInt32Array();
                writer.WriteValue(this.outer.GetValueOrDefault(), int32Array);
                return(int32Array);

            case Ember.InnerNumber.Sequence:
                writer.WriteStartSequence(this.outer.GetValueOrDefault());
                this.CopyToEndContainer(writer, null);
                return(null);

            case Ember.InnerNumber.Set:
                writer.WriteStartSet(this.outer.GetValueOrDefault());
                this.CopyToEndContainer(writer, null);
                return(null);

            default:
                writer.WriteStartApplicationDefinedType(this.outer.GetValueOrDefault(), inner);
                this.CopyToEndContainer(writer, null);
                return(null);
            }
        }
        private static void WriteOctetstring(XmlReader reader, EmberWriter writer, EmberId fieldId)
        {
            var buffer = new byte[1024];

            using (var stream = new MemoryStream())
            {
                var read = ReadValue(reader, r => (int?)r.ReadContentAsBinHex(buffer, 0, buffer.Length), 0);

                while (read > 0)
                {
                    stream.Write(buffer, 0, read.Value);
                    read = reader.ReadContentAsBinHex(buffer, 0, buffer.Length);
                }

                writer.WriteValue(fieldId, stream.ToArray());
            }
        }
        public void ExceptionTest()
        {
            AssertThrow<ArgumentNullException>(
                () => new EmberType(null).Ignore(),
                () => new EmberTypeBag(null).Ignore(),
                () => new EmberConverter(null).Ignore());

            AssertThrow<ArgumentException>(() => new EmberType().Ignore());

            using (var stream = new MemoryStream())
            using (var reader = new EmberReader(stream))
            using (var writer = XmlWriter.Create(new StringBuilder()))
            {
                var converter = new EmberConverter();
                AssertThrow<ArgumentNullException>(
                    () => converter.ToXml((byte[])null, writer),
                    () => converter.ToXml(new byte[0], null),
                    () => converter.ToXml((EmberReader)null, writer),
                    () => converter.ToXml(reader, null));
            }

            using (var stringReader = new StringReader(string.Empty))
            using (var reader = XmlReader.Create(stringReader))
            using (var stream = new MemoryStream())
            using (var writer = new EmberWriter(stream))
            {
                var converter = new EmberConverter();
                AssertThrow<ArgumentNullException>(
                    () => converter.FromXml(null),
                    () => converter.FromXml(null, writer),
                    () => converter.FromXml(reader, null));
            }

            AssertXmlException("<whatever type=\"A-11\"></whatever>", "Unknown field path: whatever.");
            AssertXmlException(
                "<A-0 type=\"Sequence\"><whatever type=\"Set\" /></A-0>", "Unknown field path: A-0.whatever.");
            AssertXmlException("<A-0 type=\"C-11\"></A-0>", "Unknown type: C-11.");
            AssertXmlException(
                "<A-0 type=\"A-11\" whatever=\"\"></A-0>",
                "Unexpected Attribute Count: Each element must have exactly one type attribute.");
            AssertXmlException(
                "<A-0 type=\"A-11\"><![CDATA[Whatever]]></A-0>",
                "Unexpected Node Type: Encountered CDATA while looking for Element.");
            AssertXmlException("<A-0 type=\"Boolean\" />", "Unexpected empty element for a field of type Boolean.");
        }
Exemple #11
0
        public void ExceptionTest()
        {
            AssertThrow <ArgumentNullException>(
                () => new EmberType(null).Ignore(),
                () => new EmberTypeBag(null).Ignore(),
                () => new EmberConverter(null).Ignore());

            AssertThrow <ArgumentException>(() => new EmberType().Ignore());

            using (var stream = new MemoryStream())
                using (var reader = new EmberReader(stream))
                    using (var writer = XmlWriter.Create(new StringBuilder()))
                    {
                        var converter = new EmberConverter();
                        AssertThrow <ArgumentNullException>(
                            () => converter.ToXml((byte[])null, writer),
                            () => converter.ToXml(new byte[0], null),
                            () => converter.ToXml((EmberReader)null, writer),
                            () => converter.ToXml(reader, null));
                    }

            using (var stringReader = new StringReader(string.Empty))
                using (var reader = XmlReader.Create(stringReader))
                    using (var stream = new MemoryStream())
                        using (var writer = new EmberWriter(stream))
                        {
                            var converter = new EmberConverter();
                            AssertThrow <ArgumentNullException>(
                                () => converter.FromXml(null),
                                () => converter.FromXml(null, writer),
                                () => converter.FromXml(reader, null));
                        }

            AssertXmlException("<whatever type=\"A-11\"></whatever>", "Unknown field path: whatever.");
            AssertXmlException(
                "<A-0 type=\"Sequence\"><whatever type=\"Set\" /></A-0>", "Unknown field path: A-0.whatever.");
            AssertXmlException("<A-0 type=\"C-11\"></A-0>", "Unknown type: C-11.");
            AssertXmlException(
                "<A-0 type=\"A-11\" whatever=\"\"></A-0>",
                "Unexpected Attribute Count: Each element must have exactly one type attribute.");
            AssertXmlException(
                "<A-0 type=\"A-11\"><![CDATA[Whatever]]></A-0>",
                "Unexpected Node Type: Encountered CDATA while looking for Element.");
            AssertXmlException("<A-0 type=\"Boolean\" />", "Unexpected empty element for a field of type Boolean.");
        }
Exemple #12
0
        public void InvalidXmlCharactersTest()
        {
            using (var stream = new MemoryStream())
            {
                using (var writer = new EmberWriter(stream))
                {
                    writer.WriteValue(EmberId.CreateContextSpecific(0), "\0");
                }

                var builder = new StringBuilder();

                using (var xmlWriter = XmlWriter.Create(builder))
                {
                    var converter = new EmberConverter();
                    converter.ToXml(stream.ToArray(), xmlWriter);
                }
            }
        }
        public void InvalidXmlCharactersTest()
        {
            using (var stream = new MemoryStream())
            {
                using (var writer = new EmberWriter(stream))
                {
                    writer.WriteValue(EmberId.CreateContextSpecific(0), "\0");
                }

                var builder = new StringBuilder();

                using (var xmlWriter = XmlWriter.Create(builder))
                {
                    var converter = new EmberConverter();
                    converter.ToXml(stream.ToArray(), xmlWriter);
                }
            }
        }
Exemple #14
0
        private void AssertEqual <T>(
            Action <EmberWriter, EmberId, T> write, Func <EmberLib.EmberReader, T> read, T value, Action <T, T> assertEqual)
        {
            var number = this.Random.Next();
            var outer  = EmberId.CreateApplication(number);
            var tag    = new BerTag(BerClass.Application, (uint)number);

            MemoryStream output;

            using (output = new MemoryStream())
                using (var writer = new EmberWriter(output, 1))
                {
                    write(writer, outer, value);
                }

            var input  = new BerMemoryInput(output.ToArray());
            var reader = new EmberLib.EmberReader(input);

            Assert.IsTrue(reader.Read());
            Assert.AreEqual(tag, reader.Tag);
            assertEqual(value, read(reader));
        }
Exemple #15
0
        public void SkipContentsTest()
        {
            using (var stream = new MemoryStream(new byte[] { 0x60, 0x03, 0x01, 0x01, 0xFF, 0x60, 0x03, 0x01, 0x01, 0x00 }))
                using (var reader = new EmberReader(stream, 1))
                {
                    Assert.IsTrue(reader.Read());
                    Assert.IsTrue(reader.Read());
                    Assert.IsFalse(reader.ReadContentsAsBoolean());
                }

            var original = new byte[64];

            this.Random.NextBytes(original);
            byte[] encoded;

            using (var stream = new MemoryStream())
            {
                using (var writer = new EmberWriter(stream))
                {
                    writer.WriteValue(EmberId.CreateApplication(0), original);
                    writer.WriteValue(EmberId.CreateApplication(1), true);
                }

                encoded = stream.ToArray();
            }

            using (var stream = new MemoryStream(encoded))
                using (var reader = new EmberReader(stream, 1))
                {
                    Assert.IsTrue(reader.Read());
                    Assert.AreEqual(InnerNumber.Octetstring, reader.InnerNumber);
                    Assert.IsTrue(reader.Read());
                    Assert.AreEqual(InnerNumber.Boolean, reader.InnerNumber);
                    Assert.AreEqual(true, reader.ReadContentsAsBoolean());
                    Assert.IsFalse(reader.Read());
                }
        }
        private void FromXmlCore(
            XmlReader reader, EmberWriter writer, FieldPath <string, string> previousPath, string currentType)
        {
            if (reader.IsEmptyElement)
            {
                writer.WriteEndContainer();
                return;
            }

            while (ReadNext(reader))
            {
                if (reader.NodeType == XmlNodeType.EndElement)
                {
                    writer.WriteEndContainer();
                    return;
                }

                if (reader.NodeType != XmlNodeType.Element)
                {
                    const string Format = "Unexpected Node Type: Encountered {0} while looking for {1}.";
                    throw new XmlException(
                              string.Format(InvariantCulture, Format, reader.NodeType, XmlNodeType.Element));
                }

                var currentPath = Combine(previousPath, new Field <string, string>(currentType, reader.Name));
                var fieldId     = this.GetFieldId(currentPath);

                if (reader.AttributeCount != 1)
                {
                    throw new XmlException(
                              "Unexpected Attribute Count: Each element must have exactly one type attribute.");
                }

                var nextType = reader.GetAttribute(0);

                switch (nextType)
                {
                case BerBoolean.Name:
                    writer.WriteValue(fieldId, ReadValue(reader, r => r.ReadContentAsBoolean()));
                    break;

                case BerInteger.Name:
                    writer.WriteValue(fieldId, ReadValue(reader, r => r.ReadContentAsLong()));
                    break;

                case BerOctetstring.Name:
                    WriteOctetstring(reader, writer, fieldId);
                    break;

                case BerReal.Name:
                    writer.WriteValue(fieldId, ReadValue(reader, r => r.ReadContentAsDouble()));
                    break;

                case BerUtf8String.Name:
                    var value = ReadValue(reader, r => r.ReadContentAsString(), string.Empty);

                    switch (currentPath.ToString())
                    {
                    case "Parameter.contents.formula":
                    case "Parameter.contents.enumeration":
                    case "Parameter.contents.schemaIdentifiers":
                    case "QualifiedParameter.contents.formula":
                    case "QualifiedParameter.contents.enumeration":
                    case "QualifiedParameter.contents.schemaIdentifiers":
                    case "Node.contents.schemaIdentifiers":
                    case "QualifiedNode.contents.schemaIdentifiers":
                    case "Matrix.contents.schemaIdentifiers":
                    case "QualifiedMatrix.contents.schemaIdentifiers":
                        value = value.Replace(Environment.NewLine, "\n");
                        break;

                    default:
                        // Intentionally do nothing
                        break;
                    }

                    writer.WriteValue(fieldId, value);
                    break;

                case BerRelativeObjectIdentifier.Name:
                    WriteRelativeObjectIdentifier(reader, writer, fieldId);
                    break;

                case BerSequence.Name:
                    writer.WriteStartSequence(fieldId);
                    this.FromXmlCore(reader, writer, currentPath, nextType);
                    break;

                case BerSet.Name:
                    writer.WriteStartSet(fieldId);
                    this.FromXmlCore(reader, writer, currentPath, nextType);
                    break;

                default:
                    writer.WriteStartApplicationDefinedType(fieldId, this.GetInnerNumber(nextType));
                    this.FromXmlCore(reader, writer, currentPath, nextType);
                    break;
                }
            }
        }
 /// <summary>Reads the current data value and writes it to <paramref name="writer"/>.</summary>
 /// <returns>The contents of the of the data value if it is primitive; otherwise, <c>null</c>.</returns>
 /// <exception cref="InvalidOperationException">
 /// <list type="bullet">
 /// <item><see cref="Read"/> has never been called, or</item>
 /// <item>The last <see cref="Read"/> call returned <c>false</c> or threw an exception.</item>
 /// </list></exception>
 /// <exception cref="ObjectDisposedException"><see cref="Dispose"/> has been called.</exception>
 /// <remarks>
 /// <para>If the <see cref="EmberReader"/> instance is currently placed on the start of a container, then skips
 /// to the end of the container, such that calling <see cref="Read"/> afterwards will place the reader on either
 /// a sibling of the container, the end of the parent container or the end of the stream.</para>
 /// <para>This method has no effect, if the reader is currently placed on a data value with primitive encoding
 /// (the next call to <see cref="Read"/> will skip possibly unread contents anyway).</para>
 /// </remarks>
 public object Copy(EmberWriter writer) => this.CopyCore(writer, this.InnerNumber);
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        private static void AssertEncode(Action<EmberWriter> write, params byte[] expected)
        {
            MemoryStream stream;

            using (stream = new MemoryStream())
            using (var writer = new EmberWriter(stream, 1))
            {
                write(writer);
            }

            CollectionAssert.AreEqual(expected, stream.ToArray());
        }
Exemple #19
0
 private object CopyCore(EmberWriter writer, int inner)
 {
     switch (inner)
     {
         case Ember.InnerNumber.Boolean:
             var boolean = this.ReadContentsAsBoolean();
             writer.WriteValue(this.outer.GetValueOrDefault(), boolean);
             return boolean;
         case Ember.InnerNumber.Integer:
             var int64 = this.ReadContentsAsInt64();
             writer.WriteValue(this.outer.GetValueOrDefault(), int64);
             return int64;
         case Ember.InnerNumber.Octetstring:
             var byteArray = this.ReadContentsAsByteArray();
             writer.WriteValue(this.outer.GetValueOrDefault(), byteArray);
             return byteArray;
         case Ember.InnerNumber.Real:
             var dbl = this.ReadContentsAsDouble();
             writer.WriteValue(this.outer.GetValueOrDefault(), dbl);
             return dbl;
         case Ember.InnerNumber.Utf8String:
             var str = this.ReadContentsAsString();
             writer.WriteValue(this.outer.GetValueOrDefault(), str);
             return str;
         case Ember.InnerNumber.RelativeObjectIdentifier:
             var int32Array = this.ReadContentsAsInt32Array();
             writer.WriteValue(this.outer.GetValueOrDefault(), int32Array);
             return int32Array;
         case Ember.InnerNumber.Sequence:
             writer.WriteStartSequence(this.outer.GetValueOrDefault());
             this.CopyToEndContainer(writer, null);
             return null;
         case Ember.InnerNumber.Set:
             writer.WriteStartSet(this.outer.GetValueOrDefault());
             this.CopyToEndContainer(writer, null);
             return null;
         default:
             writer.WriteStartApplicationDefinedType(this.outer.GetValueOrDefault(), inner);
             this.CopyToEndContainer(writer, null);
             return null;
     }
 }
Exemple #20
0
        /// <summary>Reads data and writes it to <paramref name="writer"/> until the end of the current container is
        /// reached.</summary>
        /// <returns>The contents of the of the data value with the outer id <paramref name="outerId"/>, if such a
        /// data value was found in the current container and its contents is primitive; otherwise, <c>null</c>.
        /// </returns>
        /// <exception cref="ObjectDisposedException"><see cref="Dispose"/> has been called.</exception>
        /// <remarks>
        /// <para>While <see cref="Read"/> returns <c>true</c> and <see cref="InnerNumber"/> is not equal to
        /// <see cref="Ember.InnerNumber.EndContainer"/>, calls <see cref="Copy"/>.</para>
        /// </remarks>
        public object CopyToEndContainer(EmberWriter writer, EmberId? outerId)
        {
            if (writer == null)
            {
                throw new ArgumentNullException(nameof(writer));
            }

            object result = null;
            var inner = -1;

            while (this.Read() && ((inner = this.innerNumber.GetValueOrDefault()) != Ember.InnerNumber.EndContainer))
            {
                var candidate = this.CopyCore(writer, inner);

                if (this.outer.HasValue && (this.outer.Value == outerId))
                {
                    result = candidate;
                }
            }

            if (inner == Ember.InnerNumber.EndContainer)
            {
                writer.WriteEndContainer();
            }

            return result;
        }
Exemple #21
0
 /// <summary>Reads the current data value and writes it to <paramref name="writer"/>.</summary>
 /// <returns>The contents of the of the data value if it is primitive; otherwise, <c>null</c>.</returns>
 /// <exception cref="InvalidOperationException">
 /// <list type="bullet">
 /// <item><see cref="Read"/> has never been called, or</item>
 /// <item>The last <see cref="Read"/> call returned <c>false</c> or threw an exception.</item>
 /// </list></exception>
 /// <exception cref="ObjectDisposedException"><see cref="Dispose"/> has been called.</exception>
 /// <remarks>
 /// <para>If the <see cref="EmberReader"/> instance is currently placed on the start of a container, then skips
 /// to the end of the container, such that calling <see cref="Read"/> afterwards will place the reader on either
 /// a sibling of the container, the end of the parent container or the end of the stream.</para>
 /// <para>This method has no effect, if the reader is currently placed on a data value with primitive encoding
 /// (the next call to <see cref="Read"/> will skip possibly unread contents anyway).</para>
 /// </remarks>
 public object Copy(EmberWriter writer) => this.CopyCore(writer, this.InnerNumber);