/// <summary>
        /// ReadHyperlink reads a structure designed to hold an hyperlink for a Wang annotation.
        /// </summary>
        /// <remarks>
        /// This methods aplies when the specifications are mentionning the availability of an HYPERLINK_NB  structure.
        /// </remarks>
        /// <param name="stream">The stream to read the data in.</param>
        /// <param name="dataSize">The data size.</param>
        /// <returns>the hyperlink.</returns>
        public static WangHyperlink ReadHyperlink(IWangStream stream, int dataSize)
        {
            /*
             * HYPERLINK_NB
             * Type         Name                Description
             * int          nVersion            The version number of this data.
             * int          nLinkSize           The size of the link string in bytes.
             * char         szLinkString        The variable length multi-byte name string.
             * int          nLocationSize       The size of the location string.
             * char         szLocationString    The variable length multi-byte location string.
             * int          nWorkDirSize        The size of the working directory string.
             * char         szWorkDirString     The variable length multi-byte working directory string.
             * int          nFlags              One or more of the following flags OR’ed together:
             *                                  1 = Can remove hyperlink from mark.
             *                                  2 = Hyperlink refers to this document.
             */

            if (stream.AvailableBytes() < 4)
            {
                return(null);
            }

            int version = stream.ReadInt32();

            string[] stringInformation = new string[3];
            for (int index = 0; index < stringInformation.Length; index++)
            {
                if (stream.AvailableBytes() < 4)
                {
                    return(null);
                }

                int size = stream.ReadInt32();

                if (stream.AvailableBytes() < size)
                {
                    return(null);
                }

                stringInformation[index] = ReadCharString(stream, size);
            }

            if (stream.AvailableBytes() < 4)
            {
                return(null);
            }

            int flag = stream.ReadInt32();

            return(new WangHyperlink(stringInformation[0], stringInformation[1], stringInformation[2],
                                     ((int)flag & 1) != 0, ((int)flag & 2) != 0));
        }
        /// <summary>
        /// ReadAnoDatBlock reads an "OiAnoDat" block.
        /// </summary>
        /// <param name="properties">The properties to be updated with the data.</param>
        /// <param name="stream">The stream to read the data in.</param>
        /// <param name="dataSize">The size of the data</param>
        private static bool ReadAnoDatBlock(WangAnnotationProperties properties, IWangStream stream, int dataSize)
        {
#if DEBUG
            Debug.Assert(stream.AvailableBytes() >= dataSize);
#endif // DEBUG
            if (properties.HasMarkAttributes)
            {
                switch (properties.MarkAttributes.Type)
                {
                case WangMarkType.StraightLine:
                case WangMarkType.FreehandLine:
                case WangMarkType.HollowPolygon:
                case WangMarkType.FilledPolygon:
                    int [] points = WangAnnotationStructureReader.ReadPoints(stream, dataSize);
                    properties.SetPoints(points);
                    return(true);

                case WangMarkType.ImageEmbedded:
                    WangRotation rotation = WangAnnotationStructureReader.ReadRotation(stream, dataSize);
                    properties.SetRotation(rotation);
                    return(true);

                default:
                    // TODO - David Ometto - 2016-11-22 - Add support for all types
                    break;
                }
            }
            return(false);
        }
 /// <summary>
 /// ReadRectangle reads a structure designed to hold a rectangle for a Wang Annotation.
 /// </summary>
 /// <remarks>
 /// This methods aplies when the specifications are mentionning the availability of a RECT structure.
 /// </remarks>
 /// <param name="coordinates">An array to retrieve the coordinates of the rectangle.</param>
 /// <param name="stream">The stream to read the data in.</param>
 /// <returns>true if success otherwise false.</returns>
 public static bool ReadRectangle(int[] coordinates, IWangStream stream)
 {
     if (stream.AvailableBytes() >= 4 * 4)
     {
         // The order is left, top, right, bottom.
         stream.ReadInts32(coordinates, 4);
         return(true);
     }
     return(false);
 }
 /// <summary>
 /// ReadRgbQuad reads a structure designed to hold a color for a Wang annotation.
 /// </summary>
 /// <remarks>
 /// This methods aplies when the specifications are mentionning the availability of an RGBQUAD structure.
 /// </remarks>
 /// <param name="colors">An array to retrieve the components for the color.</param>
 /// <param name="stream">The stream to read the data in.</param>
 /// <returns>true if success otherwise false.</returns>
 public static bool ReadRgbQuad(byte[] colors, IWangStream stream)
 {
     if (stream.AvailableBytes() >= 4)
     {
         // The order is blue, green, red.
         stream.ReadBytes(colors, 3);
         // Skip the reserved data field.
         stream.SkipBytes(1);
         return(true);
     }
     return(false);
 }
 /// <summary>
 /// ReadDataType reads the datatype.
 /// </summary>
 /// <param name="dataType">To retrieve the data type.</param>
 /// <param name="dataSize">To retrieve the data size.</param>
 /// <param name="stream">The stream to read the data in.</param>
 /// <returns>true if the operation succeeded otherwise returns false.</returns>
 public static bool ReadDataType(out WangDataType dataType, out int dataSize, IWangStream stream)
 {
     if (stream.AvailableBytes() >= 8)
     {
         int intDataType = stream.ReadInt32();
         dataSize = stream.ReadInt32();
         dataType = intDataType < ConversionWangDataTypes.Length
             ? ConversionWangDataTypes[intDataType]
             : WangDataType.Invalid;
         return(true);
     }
     dataSize = 0;
     dataType = WangDataType.Invalid;
     return(false);
 }
 /// <summary>
 /// ReadLogFont reads a structure designed to hold font attributes.
 /// </summary>
 /// <remarks>
 /// This methods aplies when the specifications are mentionning the availability of a OIAN_MARK_ATTRIBUTES structure.
 /// </remarks>
 /// <param name="stream">The stream to read the data in.</param>
 /// <returns>The data read.</returns>
 public static WangLogFont ReadLogfont(IWangStream stream)
 {
     if (stream.AvailableBytes() >= 56)
     {
         /*
          * This implementation is based on the following C++ typedef:
          * typedef struct tagLOGFONT {
          *  LONG  lfHeight;
          *  LONG  lfWidth;
          *  LONG  lfEscapement;
          *  LONG  lfOrientation;
          *  LONG  lfWeight;
          *  BYTE  lfItalic;
          *  BYTE  lfUnderline;
          *  BYTE  lfStrikeOut;
          *  BYTE  lfCharSet;
          *  BYTE  lfOutPrecision;
          *  BYTE  lfClipPrecision;
          *  BYTE  lfQuality;
          *  BYTE  lfPitchAndFamily;
          *  TCHAR lfFaceName[LF_FACESIZE];
          *  } LOGFONT, *PLOGFONT;
          */
         WangLogFont readData = new WangLogFont();
         readData.Height         = stream.ReadInt32();
         readData.Width          = stream.ReadInt32();
         readData.Escapement     = stream.ReadInt32();
         readData.Orientation    = stream.ReadInt32();
         readData.Weight         = stream.ReadInt32();
         readData.Italic         = stream.ReadByte() != 0;
         readData.Underline      = stream.ReadByte() != 0;
         readData.StrikeOut      = stream.ReadByte() != 0;
         readData.CharSet        = stream.ReadByte();
         readData.OutPrecision   = stream.ReadByte();
         readData.ClipPrecision  = stream.ReadByte();
         readData.Quality        = stream.ReadByte();
         readData.PitchAndFamily = stream.ReadByte();
         readData.FaceName       = ReadCharString(stream, 28);
         return(readData);
     }
     return(null);
 }
 /// <summary>
 /// ReadHeader reads the header for the tag holding the Wang annotations.
 /// </summary>
 /// <param name="stream">The stream to read the data in.</param>
 /// <returns>true if the operation succeeded otherwise returns false.</returns>
 public static bool ReadHeader(IWangStream stream)
 {
     if (stream.AvailableBytes() >= 8)
     {
         /*
          * The annotation data itself consists of a 4-byte header, which is not currently used (reserved for future use).
          * The header should be skipped on read and written as zeros. Note, however, that it is included in the TIFF tag's Data Count field.
          *  The header is followed by four bytes in Intel order that specify size of INTs and UINTs and byte ordering:
          *  4 bytes:
          *    0 = Intel 16-bit (least-significant byte to most-significant byte and two-byte INTs and UINTs)
          *    1 = Intel 32-bit (least-significant byte to most-significant byte and four-byte INTs and UINTs)
          */
         stream.SkipBytes(4);
         if (stream.ReadInt32() == 0)
         {
             // 0 = Intel 16-bit (least-significant byte to most-significant byte and two-byte INTs and UINTs)
             // TODO - David Ometto - 2016-11-21 - Add support for 16-bit annotations.
             // TODO - David Ometto - 2016-11-21 - Find a good way to send the error.
         }
         return(true);
     }
     return(false);
 }
        /// <summary>
        /// ReadBlock reads the block and updates the properties accordingly.
        /// </summary>
        /// <param name="properties">The properties to update.</param>
        /// <param name="stream">The stream to read the data in.</param>
        /// <param name="dataSize">The size of the block.</param>
        /// <returns>true if the operation succeeded otherwise returns false.</returns>
        public static bool ReadBlock(WangAnnotationProperties properties, IWangStream stream, int dataSize)
        {
#if DEBUG
            Debug.Assert(stream.AvailableBytes() >= dataSize);
#endif // DEBUG
            WangNamedBlockHeader header = WangAnnotationStructureReader.ReadNamedBlockHeader(stream, dataSize);
            if (header == null || header.Size > stream.AvailableBytes())
            {
                return(false);
            }

            /*
             * Named Block          Associated Structure            Usage
             * OiAnoDat             For lines: AN_POINTS            List coordinates for lines and freehand marks.
             *                      For images:AN_NEW_ROTATE_STRUCT Hold scaling and resolution information for image marks.
             * OiFilNam             AN_NAME_STRUCT                  Hold file name for image marks.
             * OiDIB                AN_IMAGE_STRUCT                 Store DIB data.
             * OiGroup (required)   STR                             Create sets of marks (required).
             * OiIndex (required)   STR                             Assign unique number, originating at 0, for each mark.
             *                                                      To facilitate easy application control, the next available number is generated by incrementing by 1 the number just assigned and storing it in the default OiIndex mark.
             * OiAnText             OIAN_TEXTPRIVDATA               Display text annotation marks.
             * OiHypLnk             HYPERLINK_NB                    Turn mark into a hyperlink.
             */
            if (header.Name == "OiAnoDat")
            {
                // TODO - David Ometto - 2016-11-24 - Unit test this method
                return(ReadAnoDatBlock(properties, stream, header.Size));
            }
            else if (header.Name == "OiFilNam")
            {
                properties.SetFilename(WangAnnotationStructureReader.ReadCharString(stream, header.Size));
                return(true);
            }
            else if (header.Name == "OiDIB")
            {
                properties.SetDibInfo(WangAnnotationStructureReader.ReadDib(stream, header.Size));
                return(true);
            }
            else if (header.Name == "OiGroup")
            {
                properties.OiGroup = WangAnnotationStructureReader.ReadCharString(stream, header.Size);
                return(true);
            }
            else if (header.Name == "OiIndex")
            {
                properties.OiIndex = WangAnnotationStructureReader.ReadCharString(stream, header.Size);
                return(true);
            }
            else if (header.Name == "OiAnText")
            {
                WangDisplayText displayText = WangAnnotationStructureReader.ReadDisplayText(stream, header.Size);
                if (displayText == null)
                {
                    return(false);
                }
                properties.SetDisplayText(displayText);
                return(true);
            }
            else if (header.Name == "OiHypLnk")
            {
                WangHyperlink hyperlink = WangAnnotationStructureReader.ReadHyperlink(stream, header.Size);
                if (hyperlink == null)
                {
                    return(false);
                }
                properties.SetHyperlink(hyperlink);
                return(true);
            }
            else
            {
                // We just skip unknown data
                stream.SkipBytes(header.Size);
                return(true);
            }
        }