/// <summary>
        /// Extracts aMetadata
        /// </summary>
        /// <param name="aMetadata">where to add aMetadata</param>
        /// <returns>the aMetadata found</returns>
        public override Metadata Extract(Metadata aMetadata)
        {
            if (base.data == null)
            {
                return aMetadata;
            }

            AbstractDirectory lcDirectory = aMetadata.GetDirectory("com.drew.metadata.jpeg.JpegCommentDirectory");
            string comment = Utils.Decode(base.data, true);
            lcDirectory.SetObject(JpegCommentDirectory.TAG_JPEG_COMMENT,comment);
            return aMetadata;
        }
		/// <summary>
		/// Extracts aMetadata from a SegmentReader
		/// </summary>
		/// <param name="aSegmentReader">where to extract aMetadata</param>
		/// <returns>the aMetadata found</returns>
		private static Metadata ExtractJpegSegmentReaderMetadata(JpegSegmentReader aSegmentReader) 
		{
			Metadata lcMetadata = new Metadata();
			try 
			{
				byte[] lcExifSegment =
					aSegmentReader.ReadSegment(JpegSegmentReader.SEGMENT_APP1);
				new ExifReader(lcExifSegment).Extract(lcMetadata);
			}
            catch (Exception e) 
			{
                Trace.TraceWarning("Error in reading Exif segment ("+e.Message+")");
				// in the interests of catching as much data as possible, continue
			}

			try 
			{
				byte[] lcIptcSegment =
					aSegmentReader.ReadSegment(JpegSegmentReader.SEGMENT_APPD);
				new IptcReader(lcIptcSegment).Extract(lcMetadata);
			} 
			catch (Exception e) 
			{
                Trace.TraceWarning("Error in reading Iptc segment (" + e.Message + ")");
			}

			try 
			{
				byte[] lcJpegSegment =
					aSegmentReader.ReadSegment(JpegSegmentReader.SEGMENT_SOF0);
				new JpegReader(lcJpegSegment).Extract(lcMetadata);
			}
            catch (Exception e) 
			{
                Trace.TraceWarning("Error in reading Jpeg segment (" + e.Message + ")");
			}

			try 
			{
				byte[] lcJpegCommentSegment =
					aSegmentReader.ReadSegment(JpegSegmentReader.SEGMENT_COM);
				new JpegCommentReader(lcJpegCommentSegment).Extract(lcMetadata);
			}
            catch (Exception e) 
			{
                Trace.TraceWarning("Error in reading Jpeg Comment segment (" + e.Message + ")");
			}

			return lcMetadata;
		}
        /// <summary>
        /// Constructor of the object.
        /// </summary>
        /// <param name="aStream">Where to read information from. Caution, you are responsible for closing this stream.</param>
        /// <returns>a meta data object</returns>
        public static Metadata ReadMetadata(Stream aStream)
        {
            Metadata metadata = new Metadata();
            try
            {
                byte[] buffer = new byte[(int)aStream.Length];
                aStream.Read(buffer, 0, buffer.Length);

                new ExifReader(buffer).ExtractTiff(metadata);
            }
            catch (MetadataException e)
            {
                throw new TiffProcessingException(e);
            }
            return metadata;
        }
 /// <summary>
 /// Constructor of the object.
 /// </summary>
 /// <param name="aMetadata">the metadata that shoud be transformed into XML</param>
 public XmlOutPutStreamHandler(Metadata aMetadata)
     : base()
 {
     this.Metadata = aMetadata;
     this.DtdFileName = "MetadataExtractor.dtd";
 }
 /// <summary>
 /// Constructor of the object.
 /// </summary>
 /// <param name="aMetadata">the metadata that shoud be transformed into txt</param>
 public TxtOutPutStreamHandler(Metadata aMetadata)
     : base()
 {
     this.Metadata = aMetadata;
 }
		/// <summary>
		/// Extracts aMetadata
		/// </summary>
		/// <param name="aMetadata">where to add aMetadata</param>
		/// <returns>the aMetadata found</returns>
		public override Metadata Extract(Metadata aMetadata) 
		{
			if (base.data == null) 
			{
				return aMetadata;
			}

			AbstractDirectory lcDirectory = aMetadata.GetDirectory("com.drew.metadata.jpeg.JpegDirectory");

			try 
			{
				// data precision
				int dataPrecision =
					base.Get16Bits(JpegDirectory.TAG_JPEG_DATA_PRECISION);
				lcDirectory.SetObject(
					JpegDirectory.TAG_JPEG_DATA_PRECISION,
					dataPrecision);

				// process height
				int height = base.Get32Bits(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT);
				lcDirectory.SetObject(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT, height);

				// process width
				int width = base.Get32Bits(JpegDirectory.TAG_JPEG_IMAGE_WIDTH);
				lcDirectory.SetObject(JpegDirectory.TAG_JPEG_IMAGE_WIDTH, width);

				// number of components
				int numberOfComponents =
					base.Get16Bits(JpegDirectory.TAG_JPEG_NUMBER_OF_COMPONENTS);
				lcDirectory.SetObject(
					JpegDirectory.TAG_JPEG_NUMBER_OF_COMPONENTS,
					numberOfComponents);

				// for each component, there are three bytes of data:
				// 1 - Component ID: 1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q
				// 2 - Sampling factors: bit 0-3 vertical, 4-7 horizontal
				// 3 - Quantization table number
				int offset = 6;
				for (int i = 0; i < numberOfComponents; i++) 
				{
					int componentId = base.Get16Bits(offset++);
					int samplingFactorByte = base.Get16Bits(offset++);
					int quantizationTableNumber = base.Get16Bits(offset++);
					JpegComponent lcJpegComponent =
						new JpegComponent(
						componentId,
						samplingFactorByte,
						quantizationTableNumber);
					lcDirectory.SetObject(
						JpegDirectory.TAG_JPEG_COMPONENT_DATA_1 + i,
						lcJpegComponent);
				}

			} 
			catch (MetadataException me) 
			{
                lcDirectory.HasError = true;
				Trace.TraceError("MetadataException: " + me.Message);
			}

			return aMetadata;
		}
 /// <summary>
 /// Extracts aMetadata
 /// </summary>
 /// <param name="aMetadata">where to add aMetadata</param>
 /// <returns>the aMetadata found</returns>
 public abstract Metadata Extract(Metadata metadata);
        /// <summary>
        /// Extracts aMetadata
        /// </summary>
        /// <param name="aMetadata">where to add aMetadata</param>
        /// <returns>the aMetadata found</returns>
        public override Metadata Extract(Metadata aMetadata)
        {
            if (base.data == null)
            {
                return aMetadata;
            }

            AbstractDirectory lcDirectory = aMetadata.GetDirectory("com.drew.metadata.iptc.IptcDirectory");

            // find start of data
            int offset = 0;
            try
            {
                while (offset < base.data.Length - 1 && Get32Bits(offset) != 0x1c02)
                {
                    offset++;
                }
            }
            catch (MetadataException e)
            {
                lcDirectory.HasError = true;
                Trace.TraceError(
                    "Couldn't find start of Iptc data (invalid segment) ("+e.Message+")");
                return aMetadata;
            }

            // for each tag
            while (offset < base.data.Length)
            {
                // identifies start of a tag
                if (base.data[offset] != 0x1c)
                {
                    break;
                }
                // we need at least five bytes left to read a tag
                if ((offset + 5) >= base.data.Length)
                {
                    break;
                }

                offset++;

                int directoryType;
                int tagType;
                int tagByteCount;
                try
                {
                    directoryType = base.data[offset++];
                    tagType = base.data[offset++];
                    tagByteCount = Get32Bits(offset);
                }
                catch (MetadataException e)
                {
                    lcDirectory.HasError = true;
                    Trace.TraceError(
                        "Iptc data segment ended mid-way through tag descriptor ("+e.Message+")");
                    return aMetadata;
                }
                offset += 2;
                if ((offset + tagByteCount) > base.data.Length)
                {
                    lcDirectory.HasError = true;
                    Trace.TraceError(
                        "Data for tag extends beyond end of IPTC segment");
                    break;
                }

                ProcessTag(lcDirectory, directoryType, tagType, offset, tagByteCount);
                offset += tagByteCount;
            }

            return aMetadata;
        }
 /// <summary>
 /// Constructor of the object.
 /// </summary>
 /// <param name="aMetadata">the metadata that shoud be transformed into XML</param>
 public XmlNewOutPutStreamHandler(Metadata aMetadata)
     : base()
 {
     this.Metadata = aMetadata;
     this.DtdFileName = "MetadataExtractorNew.dtd";
     XmlNewOutPutStreamHandler.FORBIDEN_CHAR = XmlNewOutPutStreamHandler.BuildForbidenChar();
 }
        /// <summary>
        /// Reads metatdata from raw file.
        /// </summary>
        /// <param name="aMetadata">a meta data</param>
        /// <param name="aTiffHeaderOffset">an offset</param>
        /// <returns>the metadata found</returns>
        private Metadata ExtractIFD(Metadata aMetadata, int aTiffHeaderOffset)
        {
            this.metadata = aMetadata;
            if (base.data == null)
            {
                return this.metadata;
            }

            ExifDirectory directory = this.ExifDirectory;

            // this should be either "MM" or "II"
            string byteOrderIdentifier = Utils.Decode(base.data, aTiffHeaderOffset, 2, false);
            if (!this.SetByteOrder(byteOrderIdentifier))
            {
                directory.HasError = true;
                Trace.TraceError("Unclear distinction between Motorola/Intel byte ordering: "
                        + byteOrderIdentifier);
                return this.metadata;
            }

            // Check the next two values for correctness.
            if (this.Get16Bits(2 + aTiffHeaderOffset) != 0x2a)
            {
              //  directory.AddError("Invalid Exif start - should have 0x2A at offset 8 in Exif header");
              //  return this.metadata;
            }

            int firstDirectoryOffset = this.Get32Bits(4 + aTiffHeaderOffset) + aTiffHeaderOffset;

            // David Ekholm sent an digital camera image that has this problem
            if (firstDirectoryOffset >= base.data.Length - 1)
            {
                directory.HasError = true;
                Trace.TraceError("First exif directory offset is beyond end of Exif data segment");
                // First directory normally starts 14 bytes in -- try it here and catch another error in the worst case
                firstDirectoryOffset = 14;
            }

            IDictionary<int, string> processedDirectoryOffsets = new Dictionary<int, string>();

            // 0th IFD (we merge with Exif IFD)
            try
            {
                this.ProcessDirectory(directory, processedDirectoryOffsets,
                    firstDirectoryOffset, aTiffHeaderOffset);
            }
            catch (Exception e)
            {
                throw new MetadataException(e);
            }

            // after the extraction process, if we have the correct tags, we may be able to store thumbnail information
            this.StoreThumbnailBytes(directory, aTiffHeaderOffset);

            return this.metadata;
        }
 /// <summary>
 /// Extract tiff information (used by raw files)
 /// </summary>
 /// <param name="aMetadata">where to extract information</param>
 /// <returns>the information extracted</returns>
 public Metadata ExtractTiff(Metadata aMetadata)
 {
     return this.ExtractIFD(aMetadata, 0);
 }
        /// <summary>
        /// Performs the Exif data extraction, adding found values to the specified instance of Metadata.
        /// </summary>
        /// <param name="aMetadata">where to add meta data</param>
        /// <returns>the aMetadata</returns>
        public override Metadata Extract(Metadata metadata)
        {
            this.metadata = metadata;
            if (base.data == null)
            {
                return this.metadata;
            }

            // once we know there'str some data, create the directory and start working on it
            AbstractDirectory directory = this.metadata.GetDirectory("com.drew.metadata.exif.ExifDirectory");

            if (base.data.Length <= 14)
            {
                directory.HasError = true;
                Trace.TraceError("Exif data segment must contain at least 14 bytes");
                return this.metadata;
            }
            if (!"Exif\0\0".Equals(Utils.Decode(base.data, 0, 6, false)))
            {
                directory.HasError = true;
                Trace.TraceError("Exif data segment doesn't begin with 'Exif'");
                return this.metadata;
            }

            // this should be either "MM" or "II"
            string byteOrderIdentifier = Utils.Decode(base.data, 6, 2, false);
            if (!SetByteOrder(byteOrderIdentifier))
            {
                directory.HasError = true;
                Trace.TraceError("Unclear distinction between Motorola/Intel byte ordering");
                return this.metadata;
            }

            // Check the next two values for correctness.
            if (Get16Bits(8) != 0x2a)
            {
                directory.HasError = true;
                Trace.TraceError("Invalid Exif start - should have 0x2A at offSet 8 in Exif header");
                return this.metadata;
            }

            int firstDirectoryOffSet = Get32Bits(10) + TIFF_HEADER_START_OFFSET;

            // David Ekholm sent an digital camera image that has this problem
            if (firstDirectoryOffSet >= base.data.Length - 1)
            {
                directory.HasError = true;
                Trace.TraceError("First exif directory offSet is beyond end of Exif data segment");
                // First directory normally starts 14 bytes in -- try it here and catch another error in the worst case
                firstDirectoryOffSet = 14;
            }

            // 0th IFD (we merge with Exif IFD)
            //ProcessDirectory(directory, firstDirectoryOffSet);
            // after the extraction process, if we have the correct tags, we may be able to extract thumbnail information
            //ExtractThumbnail(directory);

            Dictionary<int, string> processedDirectoryOffsets = new Dictionary<int, string>();

            // 0th IFD (we merge with Exif IFD)
            ProcessDirectory(directory, processedDirectoryOffsets, firstDirectoryOffSet, TIFF_HEADER_START_OFFSET);

            // after the extraction process, if we have the correct tags, we may be able to store thumbnail information
            StoreThumbnailBytes(directory, TIFF_HEADER_START_OFFSET);

            return this.metadata;
        }
		/// <summary>
		/// Reads aMetadata from a JPEGDecodeParam object
		/// </summary>
		/// <param name="aDecodeParam">where to find aMetadata</param>
		/// <returns>the aMetadata found</returns>
		public static Metadata ReadMetadata(JPEGDecodeParam aDecodeParam) 
		{
			Metadata lcMetadata = new Metadata();

			// We should only really be seeing Exif in _data[0]... the 2D array exists
			// because markers can theoretically appear multiple times in the aFile.			
			// TODO test this method
			byte[][] lcExifSegment =
				aDecodeParam.GetMarkerData(JPEGDecodeParam.APP1_MARKER);
			if (lcExifSegment != null && lcExifSegment[0].Length > 0) 
			{
				new ExifReader(lcExifSegment[0]).Extract(lcMetadata);
			}

			// similarly, use only the first IPTC segment
			byte[][] lcIptcSegment =
				aDecodeParam.GetMarkerData(JPEGDecodeParam.APPD_MARKER);
			if (lcIptcSegment != null && lcIptcSegment[0].Length > 0) 
			{
				new IptcReader(lcIptcSegment[0]).Extract(lcMetadata);
			}

			// NOTE: Unable to utilise JpegReader for the SOF0 frame here, as the aDecodeParam doesn't contain the byte[]

			// similarly, use only the first Jpeg Comment segment
			byte[][] lcJpegCommentSegment =
				aDecodeParam.GetMarkerData(JPEGDecodeParam.COMMENT_MARKER);
			if (lcJpegCommentSegment != null && lcJpegCommentSegment[0].Length > 0) 
			{
				new JpegCommentReader(lcJpegCommentSegment[0]).Extract(lcMetadata);
			}

			return lcMetadata;
		}