public IFD(TIFFBinaryReader fileStream, uint offset, Endianness endian) { this.endian = endian; fileStream.Position = offset; tagNumber = fileStream.ReadUInt16(); tags = new Dictionary <TagType, Tag>(); for (int i = 0; i < tagNumber; i++) { Tag temp = new Tag(); temp.tagId = (TagType)fileStream.ReadUInt16(); //add the displayname temp.displayName = null; temp.dataType = (TiffDataType)fileStream.ReadUInt16(); temp.dataCount = fileStream.ReadUInt32(); //IF makernote, do not parse data //if (temp.tagId == TagType.MAKERNOTE || temp.tagId == TagType.MAKERNOTE_ALT) temp.dataCount = 0; temp.dataOffset = 0; if (((temp.dataCount * temp.getTypeSize(temp.dataType) > 4))) { temp.dataOffset = fileStream.ReadUInt32(); } //Get the tag data temp.data = new Object[temp.dataCount]; long firstPosition = fileStream.Position; if (temp.dataOffset > 1) { fileStream.Position = temp.dataOffset; //todo check if correct } if (temp.tagId != TagType.MAKERNOTE && temp.tagId != TagType.MAKERNOTE_ALT) { for (int j = 0; j < temp.dataCount; j++) { switch (temp.dataType) { case TiffDataType.BYTE: case TiffDataType.UNDEFINED: case TiffDataType.ASCII: case TiffDataType.OFFSET: temp.data[j] = fileStream.ReadByte(); break; case TiffDataType.SHORT: temp.data[j] = fileStream.ReadUInt16(); break; case TiffDataType.LONG: temp.data[j] = fileStream.ReadUInt32(); break; case TiffDataType.RATIONAL: temp.data[j] = fileStream.ReadDouble(); break; case TiffDataType.SBYTE: temp.data[j] = fileStream.ReadSByte(); break; case TiffDataType.SSHORT: temp.data[j] = fileStream.ReadInt16(); //if (temp.dataOffset == 0 && temp.dataCount == 1) fileStream.ReadInt16(); break; case TiffDataType.SLONG: temp.data[j] = fileStream.ReadInt32(); break; case TiffDataType.SRATIONAL: //Because the nikonmakernote is broken with the tag 0x19 wich is double but offset of zero. //TODO remove this Fix if (temp.dataOffset == 0) { temp.data[j] = .0; } else { temp.data[j] = fileStream.ReadDouble(); } break; case TiffDataType.FLOAT: temp.data[j] = fileStream.ReadSingle(); break; case TiffDataType.DOUBLE: temp.data[j] = fileStream.ReadDouble(); break; } } }//Special tag switch (temp.tagId) { case TagType.DNGPRIVATEDATA: { try { IFD maker_ifd = parseDngPrivateData(temp); if (maker_ifd != null) { subIFD.Add(maker_ifd); } temp.data = null; } catch (TiffParserException) { // Unparsable private data are added as entries } catch (IOException) { // Unparsable private data are added as entries } } break; case TagType.MAKERNOTE: case TagType.MAKERNOTE_ALT: { try { //save current position long pos = fileStream.Position; IFD makernote = parseMakerNote(fileStream, temp.dataOffset, endian); if (makernote != null) { subIFD.Add(makernote); } //correct here fileStream.BaseStream.Position = pos; //return to current position } catch (TiffParserException) { // Unparsable makernotes are added as entries } catch (IOException) { // Unparsable makernotes are added as entries } } break; case TagType.FUJI_RAW_IFD: if (temp.dataType == TiffDataType.OFFSET) // FUJI - correct type { temp.dataType = TiffDataType.LONG; } goto case TagType.SUBIFDS; case TagType.SUBIFDS: case TagType.EXIFIFDPOINTER: case TagType.NIKONTHUMB: long p = fileStream.Position; try { for (Int32 k = 0; k < temp.dataCount; k++) { subIFD.Add(new IFD(fileStream, Convert.ToUInt32(temp.data[k]), endian, depth)); } } catch (TiffParserException) { // Unparsable subifds are added as entries } catch (IOException) { // Unparsable subifds are added as entries } fileStream.BaseStream.Position = p; break; } //transform data ToString if (temp.dataType == TiffDataType.ASCII) { //remove \0 if any if ((byte)temp.data[temp.dataCount - 1] == 0) { temp.data[temp.dataCount - 1] = (byte)' '; } string t = Encoding.ASCII.GetString(temp.data.Cast <byte>().ToArray()); temp.data = new Object[1]; temp.data[0] = t; } if (temp.dataOffset > 1) { fileStream.BaseStream.Position = firstPosition; } else if (temp.dataOffset == 0) { int k = (int)temp.dataCount * temp.getTypeSize(temp.dataType); if (k < 4) { fileStream.ReadBytes(4 - k); } } /*else * { * temp.dataCount = 0; * temp.data = null; * }*/ if (!tags.ContainsKey(temp.tagId)) { tags.Add(temp.tagId, temp); } else { Debug.WriteLine("tags already exist"); } } nextOffset = fileStream.ReadUInt16(); }
IFD parseDngPrivateData(Tag t) { /* * 1. Six bytes containing the zero-terminated string "Adobe". (The DNG specification calls for the DNGPrivateData tag to start with an ASCII string identifying the creator/format). * 2. 4 bytes: an ASCII string ("MakN" for a Makernote), indicating what sort of data is being stored here. Note that this is not zero-terminated. * 3. A four-byte count (number of data bytes following); this is the length of the original MakerNote data. (This is always in "most significant byte first" format). * 4. 2 bytes: the byte-order indicator from the original file (the usual 'MM'/4D4D or 'II'/4949). * 5. 4 bytes: the original file offset for the MakerNote tag data (stored according to the byte order given above). * 6. The contents of the MakerNote tag. This is a simple byte-for-byte copy, with no modification. */ uint size = t.dataCount; Common.ConvertArray(ref t.data, out byte[] data); Common.ByteToChar(ref data, out char[] dataAsChar); string id = new String(dataAsChar); if (!id.StartsWith("Adobe")) { Debug.WriteLine("Not Adobe Private data"); return(null); } if (!(data[6] == 'M' && data[7] == 'a' && data[8] == 'k' && data[9] == 'N')) { Debug.WriteLine("Not Makernote"); return(null); } data = data.Skip(10).ToArray(); uint count; count = (uint)data[0] << 24 | (uint)data[1] << 16 | (uint)data[2] << 8 | data[3]; data = data.Skip(4).ToArray(); if (count > size) { Debug.WriteLine("Error reading TIFF structure (invalid size). File Corrupt"); return(null); } Endianness makernote_endian = Endianness.unknown; if (data[0] == 0x49 && data[1] == 0x49) { makernote_endian = Endianness.little; } else if (data[0] == 0x4D && data[1] == 0x4D) { makernote_endian = Endianness.big; } else { Debug.WriteLine("Cannot determine endianess of DNG makernote"); return(null); } data = data.Skip(2).ToArray(); uint org_offset; org_offset = (uint)data[0] << 24 | (uint)data[1] << 16 | (uint)data[2] << 8 | data[3]; data = data.Skip(4).ToArray(); /* We don't parse original makernotes that are placed after 300MB mark in the original file */ if (org_offset + count > 300 * 1024 * 1024) { Debug.WriteLine("Adobe Private data: original offset of makernote is past 300MB offset"); return(null); } /* Create fake tiff with original offsets */ //byte[] maker_data = new byte[count]; // Common.memcopy(ref maker_data, ref data, count, 0, 0); TIFFBinaryReader maker_map = new TIFFBinaryReader(TIFFBinaryReader.streamFromArray(data)); IFD maker_ifd; try { maker_ifd = parseMakerNote(maker_map, 0, makernote_endian); } catch (TiffParserException e) { Debug.WriteLine(e.Message); return(null); } return(maker_ifd); }