private static void WriteDirectory(BinaryWriter writer, Dictionary <ushort, ExifValue> tags, List <IFDEntry> entries, long ifdOffset) { writer.BaseStream.Position = ifdOffset; long nextIFDPointerOffset = ifdOffset + sizeof(ushort) + ((long)entries.Count * IFDEntry.SizeOf); writer.Write((ushort)entries.Count); foreach (IFDEntry entry in entries.OrderBy(e => e.Tag)) { entry.Write(writer); if (!ExifValueTypeUtil.ValueFitsInOffsetField(entry.Type, entry.Count)) { long oldPosition = writer.BaseStream.Position; writer.BaseStream.Position = entry.Offset; writer.Write(tags[entry.Tag].Data.AsArrayOrToArray()); writer.BaseStream.Position = oldPosition; } } writer.BaseStream.Position = nextIFDPointerOffset; // There is only one IFD in this directory. writer.Write(0); }
private string GetValueStringFromOffset() { string valueString; ExifValueType type = entry.Type; uint count = entry.Count; uint offset = entry.Offset; if (count == 0) { return(string.Empty); } int typeSizeInBytes = ExifValueTypeUtil.GetSizeInBytes(type); if (typeSizeInBytes == 1) { byte[] bytes = new byte[count]; if (offsetIsBigEndian) { switch (count) { case 1: bytes[0] = (byte)((offset >> 24) & 0x000000ff); break; case 2: bytes[0] = (byte)((offset >> 24) & 0x000000ff); bytes[1] = (byte)((offset >> 16) & 0x000000ff); break; case 3: bytes[0] = (byte)((offset >> 24) & 0x000000ff); bytes[1] = (byte)((offset >> 16) & 0x000000ff); bytes[2] = (byte)((offset >> 8) & 0x000000ff); break; case 4: bytes[0] = (byte)((offset >> 24) & 0x000000ff); bytes[1] = (byte)((offset >> 16) & 0x000000ff); bytes[2] = (byte)((offset >> 8) & 0x000000ff); bytes[3] = (byte)(offset & 0x000000ff); break; } } else { switch (count) { case 1: bytes[0] = (byte)(offset & 0x000000ff); break; case 2: bytes[0] = (byte)(offset & 0x000000ff); bytes[1] = (byte)((offset >> 8) & 0x000000ff); break; case 3: bytes[0] = (byte)(offset & 0x000000ff); bytes[1] = (byte)((offset >> 8) & 0x000000ff); bytes[2] = (byte)((offset >> 16) & 0x000000ff); break; case 4: bytes[0] = (byte)(offset & 0x000000ff); bytes[1] = (byte)((offset >> 8) & 0x000000ff); bytes[2] = (byte)((offset >> 16) & 0x000000ff); bytes[3] = (byte)((offset >> 24) & 0x000000ff); break; } } if (type == ExifValueType.Ascii) { valueString = Encoding.UTF8.GetString(bytes).TrimEnd('\0'); } else if (count == 1) { valueString = bytes[0].ToString(CultureInfo.InvariantCulture); } else { StringBuilder builder = new(); uint lastItemIndex = count - 1; for (int i = 0; i < count; i++) { builder.Append(bytes[i].ToString(CultureInfo.InvariantCulture)); if (i < lastItemIndex) { builder.Append(','); } } valueString = builder.ToString(); } } else if (typeSizeInBytes == 2) { ushort[] values = new ushort[count]; if (offsetIsBigEndian) { switch (count) { case 1: values[0] = (ushort)((offset >> 16) & 0x0000ffff); break; case 2: values[0] = (ushort)((offset >> 16) & 0x0000ffff); values[1] = (ushort)(offset & 0x0000ffff); break; } } else { switch (count) { case 1: values[0] = (ushort)(offset & 0x0000ffff); break; case 2: values[0] = (ushort)(offset & 0x0000ffff); values[1] = (ushort)((offset >> 16) & 0x0000ffff); break; } } if (count == 1) { switch (type) { case ExifValueType.SShort: valueString = ((short)values[0]).ToString(CultureInfo.InvariantCulture); break; case ExifValueType.Short: default: valueString = values[0].ToString(CultureInfo.InvariantCulture); break; } } else { switch (type) { case ExifValueType.SShort: valueString = ((short)values[0]).ToString(CultureInfo.InvariantCulture) + "," + ((short)values[1]).ToString(CultureInfo.InvariantCulture); break; case ExifValueType.Short: default: valueString = values[0].ToString(CultureInfo.InvariantCulture) + "," + values[1].ToString(CultureInfo.InvariantCulture); break; } } } else { valueString = offset.ToString(CultureInfo.InvariantCulture); } return(valueString); }
private static Dictionary <ExifPropertyPath, ExifValue> ConvertIFDEntriesToMetadataEntries(EndianBinaryReader reader, List <ParserIFDEntry> entries) { Dictionary <ExifPropertyPath, ExifValue> items = new(entries.Count); bool swapNumberByteOrder = reader.Endianess == Endianess.Big; for (int i = 0; i < entries.Count; i++) { ParserIFDEntry entry = entries[i]; byte[] propertyData; if (entry.OffsetFieldContainsValue) { propertyData = entry.GetValueBytesFromOffset(); if (propertyData == null) { continue; } } else { long bytesToRead = entry.Count * ExifValueTypeUtil.GetSizeInBytes(entry.Type); // Skip any tags that are empty or larger than 2 GB. if (bytesToRead == 0 || bytesToRead > int.MaxValue) { continue; } uint offset = entry.Offset; if ((offset + bytesToRead) > reader.Length) { continue; } reader.Position = offset; propertyData = reader.ReadBytes((int)bytesToRead); if (swapNumberByteOrder) { // Paint.NET converts all multi-byte numbers to little-endian. switch (entry.Type) { case ExifValueType.Short: case ExifValueType.SShort: propertyData = SwapShortArrayToLittleEndian(propertyData, entry.Count); break; case ExifValueType.Long: case ExifValueType.SLong: case ExifValueType.Float: propertyData = SwapLongArrayToLittleEndian(propertyData, entry.Count); break; case ExifValueType.Rational: case ExifValueType.SRational: propertyData = SwapRationalArrayToLittleEndian(propertyData, entry.Count); break; case ExifValueType.Double: propertyData = SwapDoubleArrayToLittleEndian(propertyData, entry.Count); break; case ExifValueType.Byte: case ExifValueType.Ascii: case ExifValueType.Undefined: default: break; } } } items.TryAdd(new ExifPropertyPath(entry.Section, entry.Tag), new ExifValue(entry.Type, propertyData)); } return(items); }