Beispiel #1
0
        /// <summary>
        /// Writes the element value to the stream.
        /// </summary>
        /// <param name="stream">The stream to write that positioned at the proper location to write.</param>
        /// <param name="syntax">The tranfer syntax to use if the value is binary.</param>
        /// <param name="encoding">The specific character set to use if the value is text.</param>
        /// <param name="options">The options used to encode tags.</param>
        protected override void WriteValueOnStream(Stream stream, string syntax, SpecificCharacterSet encoding, DataSetOptions options)
        {
            EndianBinaryWriter writer = new EndianBinaryWriter(stream, Syntax.GetEndian(syntax));

            if (Syntax.CanEncapsulatePixelData(syntax))
            {
                WriteEncapsulatedPixelData(writer);
            }
            else
            {
                if (vr == "OW")
                {
                    short[] words = Value as short[];
                    foreach (short word in words)
                    {
                        writer.Write(word);
                    }
                }
                else if (vr == "OB")
                {
                    byte[] value = Value as byte[];
                    writer.Write((byte[])value);
                    if (value.Length % 2 != 0)
                    {
                        writer.Write('\0');
                    }
                }
                else
                {
                    throw new Exception(String.Format("Unexpected vr={0} in WriteValueOnStream", vr));
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Writes the element value to the stream.
        /// </summary>
        /// <param name="stream">The stream to write that positioned at the proper location to write.</param>
        /// <param name="syntax">The tranfer syntax to use if the value is binary.</param>
        /// <param name="encoding">The specific character set to use if the value is text.</param>
        /// <param name="options">The options used to encode tags.</param>
        protected override void WriteValueOnStream(Stream stream, string syntax, SpecificCharacterSet encoding, DataSetOptions options)
        {
            EndianBinaryWriter writer = new EndianBinaryWriter(stream, Syntax.GetEndian(syntax));

            unchecked
            {
                foreach (Elements elements in items)
                {
                    writer.Write((short)0xFFFE);
                    writer.Write((short)0xE000);

                    // each nested element list can have its own SpecificCharacterSet,
                    // and it is valid for all nested elements, unless overridden again further down
                    SpecificCharacterSet scoped = encoding;
                    if (elements.Contains(t.SpecificCharacterSet))
                    {
                        scoped = new SpecificCharacterSet(elements[t.SpecificCharacterSet].Value);
                    }

                    uint size = 0;
                    // and account for the size of each child element
                    foreach (Element child in elements)
                    {
                        size += child.GetSize(syntax, scoped);
                    }
                    writer.Write(size);

                    foreach (Element child in elements)
                    {
                        child.Write(writer.BaseStream, syntax, scoped, options);
                    }
                }
            }
        }
Beispiel #3
0
        /// <summary>
        /// Writes the collection to a stream using the specified transfer syntax.
        /// </summary>
        /// <param name="filename">The stream to write to.</param>
        /// <returns>The number of bytes written.</returns>
        /// <remarks>See <see cref="Part10Header"></see> for an explanation of the File Meta tags./></remarks>
        public long Write(Stream stream, string syntax)
        {
            if (syntax == Syntax.Unknown)
            {
                syntax = Syntax.ImplicitVrLittleEndian;
            }
            long results = 0;
            SpecificCharacterSet encoding = SpecificCharacterSet.Default;

            if (this.Contains(t.SpecificCharacterSet))
            {
                object text = this[t.SpecificCharacterSet].Value;
                encoding = new SpecificCharacterSet(text);
            }
            foreach (Element element in this)
            {
                //element.Dump();
                if (!GroupLengths && element.Tag.IsGroupLength)
                {
                    continue;
                }
                results += element.Write(stream, syntax, encoding, options);
            }
            return(results);
        }
Beispiel #4
0
        /// <summary>
        /// Just prior to writing, this sets the length of the Group Length tags in the DataSet
        /// </summary>
        /// <param name="tags"></param>
        /// <param name="encoding"></param>
        private void SetGroupLengths(Elements tags, SpecificCharacterSet encoding)
        {
            uint    size  = 0;
            Element group = null;

            foreach (Element element in tags)
            {
                if (element.element == 0x0000)
                {
                    if (group != null)
                    {
                        //Logging.Log("Setting GroupLength {0} to {1}.", group, size);
                        group.Value = size;
                    }
                    group = element;
                    size  = 0;
                }
                else
                {
                    size += element.GetSize((group != null && group.element == 0x0000) ? Syntax.ExplicitVrLittleEndian : syntax, encoding);
                }
            }
            if (group != null)
            {
                //Logging.Log("Setting GroupLength {0} to {1}.", group, size);
                group.Value = size;
            }
        }
Beispiel #5
0
        /// <summary>
        /// This method reads the value from the stream and sets the vm for string types
        /// </summary>
        /// <param name="stream">The stream to read the data from.</param>
        /// <param name="syntax">The transfer syntax used to interpret binary data.</param>
        /// <param name="encoding">The encoding to use to decode string data.</param>
        /// <param name="length">The length, in bytes, of the data to read.</param>
        /// <remarks>The stream is assumed to be positioned at the beginning of the encoded tag value.</remarks>
        protected override void ReadValueFromStream(Stream stream, string syntax, SpecificCharacterSet encoding, uint length)
        {
            this.length = length;
            value       = null;
            if (length != 0)
            {
                EndianBinaryReader reader = new EndianBinaryReader(stream, Syntax.GetEndian(syntax));

                //System.Diagnostics.Debug.WriteLine(String.Format("0x{0:X8}:{0}: Reading sequence of length={1}", stream.Position, (length == UInt32.MaxValue) ? "undefined" : length.ToString()));
                ReadSequence(reader, encoding, reader.BaseStream.Position);
                //System.Diagnostics.Debug.WriteLine(String.Format("0x{0:X8}:{0}: Finished reading sequence", stream.Position));
            }
        }
Beispiel #6
0
        /// <summary>
        /// The size in bytes of the collection if written.
        /// </summary>
        /// <param name="syntax"></param>
        /// <returns></returns>
        public ulong GetSize(string syntax)
        {
            ulong size = 0;
            SpecificCharacterSet encoding = SpecificCharacterSet.Default;

            if (Contains(t.SpecificCharacterSet))
            {
                object text = this[t.SpecificCharacterSet].Value;
                encoding = new SpecificCharacterSet(text);
            }
            foreach (KeyValuePair <string, Element> pair in elements)
            {
                uint temp = pair.Value.GetSize(syntax, encoding);
                //System.Diagnostics.Debug.WriteLine(String.Format("\t{0}:{1}:{2}:{3}", pair.Value.Tag.ToString(), pair.Value.VR, temp, pair.Value.ToString()));
                size += (ulong)temp;
            }
            //System.Diagnostics.Debug.WriteLine(String.Format("{0}", size));
            return(size);
        }
Beispiel #7
0
        /// <summary>
        /// This method reads the value from the stream and sets the vm for string types
        /// </summary>
        /// <param name="stream">The stream to read the data from.</param>
        /// <param name="syntax">The transfer syntax used to interpret binary data.</param>
        /// <param name="encoding">The encoding to use to decode string data.</param>
        /// <param name="length">The length, in bytes, of the data to read.</param>
        /// <remarks>The stream is assumed to be positioned at the beginning of the encoded tag value.</remarks>
        protected override void ReadValueFromStream(Stream stream, string syntax, SpecificCharacterSet encoding, uint length)
        {
            this.length = length;

            EndianBinaryReader reader = new EndianBinaryReader(stream, Syntax.GetEndian(syntax));

            if (length == 0xFFFFFFFF)
            {
                if (!Syntax.CanEncapsulatePixelData(syntax))
                {
                    throw new Exception(String.Format("Current syntax {0} does not support Encapsulated Pixel Data.", syntax, this.tag.Name));
                }
                ReadEncapsulatedPixelData(reader);
            }
            else
            {
                ReadNativePixelData(reader);
            }
        }
Beispiel #8
0
        /// <summary>
        /// Write the DataSet to a stream.
        /// </summary>
        /// <param name="filename">The stream to write to.</param>
        /// <returns>The number of bytes written.</returns>
        /// <remarks>See <see cref="Part10Header"></see> for an explanation of the File Meta tags./></remarks>
        public long Write(Stream stream)
        {
            long results = 0;

            // the transfer syntax as set in the dataset overrides the syntax property.
            if (Contains(t.TransferSyntaxUID))
            {
                syntax = (string)this[t.TransferSyntaxUID].Value;
            }
            if (syntax == Syntax.Unknown)
            {
                syntax = Syntax.ImplicitVrLittleEndian;
            }

            SpecificCharacterSet encoding = SpecificCharacterSet.Default;

            if (header)
            {
                CheckHeader();
                SetGroupLengths(metadata, encoding);
                BinaryWriter writer = new BinaryWriter(stream);
                byte[]       buffer = new byte[128];
                writer.Write(buffer, 0, buffer.Length);
                writer.Write("DICM".ToCharArray());
                results += buffer.Length + 4;
                // metadata is always written in ExplicitVrLittleEndian
                results += metadata.Write(stream, Syntax.ExplicitVrLittleEndian);
            }

            //Logging.Log(LogLevel.Verbose, "Writing {0}.", Reflection.GetName(typeof(Syntax), syntax));
            if (elements.Contains(t.SpecificCharacterSet))
            {
                object text = this[t.SpecificCharacterSet].Value;
                encoding = new SpecificCharacterSet(text);
            }
            SetGroupLengths(elements, encoding);
            results += elements.Write(stream, syntax);

            return(results);
        }
Beispiel #9
0
        /// <summary>
        /// The size in bytes of the Element if it were to be written.
        /// </summary>
        /// <param name="syntax">The TransferSyntax that will be used to write to the stream.</param>
        /// <param name="encoding">The encoding with which this element will be written.</param>
        /// <returns>The size in bytes of the Element.</returns>
        public override uint GetSize(string syntax, SpecificCharacterSet encoding)
        {
            uint size = GetFront(syntax, encoding);

            foreach (Elements elements in items)
            {
                // account for the size of each item tag and item value length
                size += sizeof(short) + sizeof(short) + sizeof(int);
                // each nested element list can have its own SpecificCharacterSet,
                // it is valid for all nested elements, unless overridden again further down
                SpecificCharacterSet scoped = encoding;
                if (elements.Contains(t.SpecificCharacterSet))
                {
                    scoped = new SpecificCharacterSet(elements[t.SpecificCharacterSet].Value);
                }
                // and then account for the size of each child element
                foreach (Element element in elements)
                {
                    size += element.GetSize(syntax, scoped);
                }
            }
            return(size);
        }
Beispiel #10
0
        private void ReadSequence(EndianBinaryReader reader, SpecificCharacterSet encoding, long start)
        {
            Tag lookahead = null;

            // if we have somethign to read and we are not at the end of the stream
            if (length != 0 && position != stream.Length)
            {
                // look ahead and see if we can find an item delimiter tag
                lookahead = DataSet.PeekTag(reader, this.syntax);
                //System.Diagnostics.Debug.WriteLine(String.Format("0x{0:X8}:{0}: Peek {1} in ReadSequence", stream.Position, lookahead.Description));

                // as long as we have item tags
                // TODO if we do not find an item tag that is a problem
                while (lookahead.Equals(t.Item))
                {
                    // position past the tag group and element
                    stream.Position += sizeof(ushort) + sizeof(ushort);
                    // find out the length of the item
                    uint count = reader.ReadUInt32();

                    //System.Diagnostics.Debug.WriteLine(String.Format("0x{0:X8}:{0}: Reading item of length={1}", stream.Position, (count == UInt32.MaxValue) ? "undefined" : count.ToString()));

                    Elements elements = new Elements();
                    items.Add(elements);

                    long place = stream.Position;
                    // call scan recursively, passing in the length limit which is the size of the
                    // entire item along with the sequence key name
                    long temp = (count != UInt32.MaxValue) ? (place + count) : -1;
                    place = DataSet.Scan(this, stream, elements, place, temp, UInt16.MaxValue, syntax, encoding);

                    //System.Diagnostics.Debug.WriteLine(String.Format("0x{0:X8}:{0}: Finished reading item", stream.Position));

                    if (stream.Position < stream.Length)
                    {
                        lookahead = DataSet.PeekTag(reader, this.syntax);
                        //System.Diagnostics.Debug.WriteLine(String.Format("0x{0:X8}:{0}: Peek {1} in ReadSequence", stream.Position, lookahead.Name));
                    }

                    // the next tag is either another item in the sequence, a sequence delimiter, or the next tag
                    // after the sequence. we only get the next tag if we are not at the end of the file and
                    // we have an undefined sequence length
                    if (length == UInt32.MaxValue)
                    {
                        if (lookahead.Equals(t.SequenceDelimitationItem))
                        {
                            //System.Diagnostics.Debug.WriteLine(String.Format("0x{0:X8}:{0}: undefined length, found {1}:{2}", stream.Position, lookahead.Description, lookahead.Name));
                            break;
                        }
                    }
                    else
                    {
                        if (stream.Position >= start + length)
                        {
                            break;
                        }
                        if (!lookahead.Equals(t.Item))
                        {
                        }
                    }
                }
                if (length == UInt32.MaxValue)
                {
                    if (lookahead.Equals(t.SequenceDelimitationItem))
                    {
                        //System.Diagnostics.Debug.WriteLine(String.Format("0x{0:X8}:{0}: undefined length, found {1}:{2}", stream.Position, lookahead.Description, lookahead.Name));
                        // position stream beyond delimitation tag
                        stream.Position += sizeof(ushort) * 2;
                        // no need to check zero
                        int zero = reader.ReadInt32();
                    }
                }
            }
        }
Beispiel #11
0
        /// <summary>
        /// Parses the stream for tags.
        /// </summary>
        /// <param name="parent">The parent Element that the tags will belong to, if any.</param>
        /// <param name="stream">The stream to Read from.</param>
        /// <param name="elements">The Elements collection to add the Elements to.</param>
        /// <param name="current">The current postion in the stream.</param>
        /// <param name="length">The maximum number of bytes to read.</param>
        /// <param name="stop">The group number ot read up to and including.</param>
        /// <param name="syntax">The Transfer Syntax of the stream.</param>
        /// <param name="encoding">The character encoding of the stream.</param>
        /// <returns>The final position in the stream Read to.</returns>
        public static long Scan(Element parent, Stream stream, Elements elements, long current, long length, ushort stop, string syntax, SpecificCharacterSet encoding)
        {
            //System.Diagnostics.Debug.WriteLine(String.Format("0x{0:X8}:{0}: Scan called parent={1}:{2}. current={3} length={4} stop={5}",
            //    stream.Position, (parent!=null)?parent.Tag.ToString():"root", (parent!=null)?parent.VR:"", current, length, stop));

            // we have to get the stream on top of the current position
            stream.Position = current;

            EndianBinaryReader reader = new EndianBinaryReader(stream, Syntax.GetEndian(syntax));

            // Scan stops when either the stream position exceeds length, or the group exceeds stop,
            // or we reach the end of a file, or we reach an ItemDelimiter or SequenceDelimiter, or
            // we can no longer read
            while (true)
            {
                if (!stream.CanRead)
                {
                    //System.Diagnostics.Debug.WriteLine("stream CanRead==false");
                    break;
                }

                if (length != -1 && (ulong)current >= (ulong)length)
                {
                    //System.Diagnostics.Debug.WriteLine(String.Format("0x{0:X8}:{0}: current={1} exceeds length={2}", stream.Position, current, length));
                    break;
                }

                // keep track of where we are before reading the next element
                long previous  = current;
                Tag  lookahead = PeekTag(reader, syntax);

                //System.Diagnostics.Debug.WriteLine(String.Format("0x{0:X8}:{0}: Peek {1} in Scan", stream.Position, lookahead.Name));

                // we scan up to and including the group specified by stop
                // so we check if we have gone beyond the specified group
                if (lookahead.Group > stop)
                {
                    //System.Diagnostics.Debug.WriteLine(String.Format("0x{0:X8}:{0}: group={1} exceeds stop={2}", stream.Position, lookahead.Group, stop));
                    // we need to rewind to before this element
                    current = previous;
                    break;
                }

                if (length == -1)
                {
                    //if (lookahead.Equals(t.ItemDelimitationItem) || lookahead.Equals(t.SequenceDelimitationItem))
                    if (lookahead.Equals(t.ItemDelimitationItem))
                    {
                        //System.Diagnostics.Debug.WriteLine(String.Format("0x{0:X8}:{0}: undefined length, found {1}:{2}", stream.Position, lookahead.Description, lookahead.Name));
                        // position stream beyond delimitation tag
                        stream.Position += sizeof(ushort) * 2;
                        // no need to check zero
                        int zero = reader.ReadInt32();
                        break;
                    }
                }

                Exception exception = null;
                Element   element   = Element.Factory(parent, lookahead);
                try
                {
                    //System.Diagnostics.Debug.WriteLine(String.Format("reading {0}", lookahead.ToString()));
                    element.Read(stream, syntax, encoding);
                }
                catch (Exception ex)
                {
                    // we are going to delay throwing an exception from reading
                    // until we see if we are going to add it to the collection
                    exception = ex;
                }

                current = stream.Position;

                // if we have the SpecificCharacterSet, create an Encoding for the rest of the DataSet
                if (element.Tag.Equals(t.SpecificCharacterSet))
                {
                    encoding = new SpecificCharacterSet(element.Value);
                }
                else if (element.Tag.Equals(t.PixelData) && !Syntax.IsExplicit(syntax))
                {
                    // if we have the PixelData, insure that it matches the BitsStored
                    // this can happen with implicit vrs and OW is the default

                    if (elements.Contains(t.BitsStored))
                    {
                        ushort stored = (ushort)elements[t.BitsStored].Value;
                        Type   type   = element.Value.GetType().GetElementType();
                        if (stored == 8 && element.Value is ushort[])
                        {
                            ushort[] pixels = element.Value as ushort[];
                            byte[]   bytes  = new byte[pixels.Length * 2];
                            Buffer.BlockCopy(pixels, 0, bytes, 0, bytes.Length);
                            element.Value = bytes;
                        }
                    }
                }
                else if (element.Tag.Equals(t.ItemDelimitationItem) || element.Tag.Equals(t.SequenceDelimitationItem) || element.Tag.Equals(t.Item))
                {
                    // if we have a sequence or item delimiter, stop scanning
                    if (length == -1)
                    {
                        return(current);
                    }
                }

                // now that we are about to add the tag, check and see if it parsed correctly
                if (exception != null)
                {
                    // we have failed to parse, so we create a tag that contains the rest of the data
                    stream.Position = previous;
                    element         = new Element("(BAAD,F00D)", reader.ReadBytes((int)(length - previous)));
                }

                string key = Tag.ToString(element);
                // and insert the tag name/value pair in the hash table, allows duplicates
                elements[key] = element;
                //Logging.Log("Adding {0}:{1}", key, element.ToString());

                // now we can throw the exception if there is one
                if (exception != null)
                {
                    throw exception;
                }

                if ((ulong)current >= (ulong)length)
                {
                    //System.Diagnostics.Debug.WriteLine(String.Format("0x{0:X8}:{0}: current={1} at or exceeds length={2}", stream.Position, current, length));
                    break;
                }
            }
            return(current);
        }