private static void ProcessTag(SequentialReader reader, Directory directory, int directoryType, int tagType, int tagByteCount) { var tagIdentifier = tagType | (directoryType << 8); // Some images have been seen that specify a zero byte tag, which cannot be of much use. // We elect here to completely ignore the tag. The IPTC specification doesn't mention // anything about the interpretation of this situation. // https://raw.githubusercontent.com/wiki/drewnoakes/metadata-extractor/docs/IPTC-IIMV4.2.pdf if (tagByteCount == 0) { directory.Set(tagIdentifier, string.Empty); return; } switch (tagIdentifier) { case IptcDirectory.TagCodedCharacterSet: { var bytes = reader.GetBytes(tagByteCount); var charset = Iso2022Converter.ConvertEscapeSequenceToEncodingName(bytes); if (charset == null) { // Unable to determine the charset, so fall through and treat tag as a regular string charset = Encoding.UTF8.GetString(bytes, 0, bytes.Length); } directory.Set(tagIdentifier, charset); return; } case IptcDirectory.TagEnvelopeRecordVersion: case IptcDirectory.TagApplicationRecordVersion: case IptcDirectory.TagFileVersion: case IptcDirectory.TagArmVersion: case IptcDirectory.TagProgramVersion: { // short if (tagByteCount == 2) { var shortValue = reader.GetUInt16(); reader.Skip(tagByteCount - 2); directory.Set(tagIdentifier, shortValue); return; } break; } case IptcDirectory.TagUrgency: { // byte directory.Set(tagIdentifier, reader.GetByte()); reader.Skip(tagByteCount - 1); return; } } // If we haven't returned yet, treat it as a string // NOTE that there's a chance we've already loaded the value as a string above, but failed to parse the value var encodingName = directory.GetString(IptcDirectory.TagCodedCharacterSet); Encoding?encoding = null; if (encodingName != null) { try { encoding = Encoding.GetEncoding(encodingName); } catch (ArgumentException) { } } StringValue str; if (encoding != null) { str = reader.GetStringValue(tagByteCount, encoding); } else { var bytes = reader.GetBytes(tagByteCount); encoding = Iso2022Converter.GuessEncoding(bytes); str = new StringValue(bytes, encoding); } if (directory.ContainsTag(tagIdentifier)) { // this fancy string[] business avoids using an ArrayList for performance reasons var oldStrings = directory.GetStringValueArray(tagIdentifier); StringValue[] newStrings; if (oldStrings == null) { // TODO hitting this block means any prior value(s) are discarded newStrings = new StringValue[1]; } else { newStrings = new StringValue[oldStrings.Length + 1]; Array.Copy(oldStrings, 0, newStrings, 0, oldStrings.Length); } newStrings[newStrings.Length - 1] = str; directory.Set(tagIdentifier, newStrings); } else { directory.Set(tagIdentifier, str); } }
private static void ProcessTag([NotNull] SequentialReader reader, [NotNull] Directory directory, int directoryType, int tagType, int tagByteCount) { var tagIdentifier = tagType | (directoryType << 8); // Some images have been seen that specify a zero byte tag, which cannot be of much use. // We elect here to completely ignore the tag. The IPTC specification doesn't mention // anything about the interpretation of this situation. // https://raw.githubusercontent.com/wiki/drewnoakes/metadata-extractor/docs/IPTC-IIMV4.2.pdf if (tagByteCount == 0) { directory.Set(tagIdentifier, string.Empty); return; } string str = null; switch (tagIdentifier) { case IptcDirectory.TagCodedCharacterSet: { var bytes = reader.GetBytes(tagByteCount); var charset = Iso2022Converter.ConvertEscapeSequenceToEncodingName(bytes); if (charset == null) { // Unable to determine the charset, so fall through and treat tag as a regular string str = Encoding.UTF8.GetString(bytes); break; } directory.Set(tagIdentifier, charset); return; } case IptcDirectory.TagEnvelopeRecordVersion: case IptcDirectory.TagApplicationRecordVersion: case IptcDirectory.TagFileVersion: case IptcDirectory.TagArmVersion: case IptcDirectory.TagProgramVersion: { // short if (tagByteCount >= 2) { var shortValue = reader.GetUInt16(); reader.Skip(tagByteCount - 2); directory.Set(tagIdentifier, shortValue); return; } break; } case IptcDirectory.TagUrgency: { // byte directory.Set(tagIdentifier, reader.GetByte()); reader.Skip(tagByteCount - 1); return; } case IptcDirectory.TagReleaseDate: case IptcDirectory.TagDateCreated: case IptcDirectory.TagDigitalDateCreated: { // Date object if (tagByteCount >= 8) { str = reader.GetString(tagByteCount); Debug.Assert(str.Length >= 8); int year, month, day; if (int.TryParse(str.Substring(0, 4), out year) && int.TryParse(str.Substring(4, 2), out month) && int.TryParse(str.Substring(6, 2), out day) && DateUtil.IsValidDate(year, month, day)) { directory.Set(tagIdentifier, new DateTime(year, month, day, 0, 0, 0, DateTimeKind.Unspecified)); return; } } else { // fall through and we'll process the 'string' value below reader.Skip(tagByteCount); } break; } } // If we haven't returned yet, treat it as a string // NOTE that there's a chance we've already loaded the value as a string above, but failed to parse the value if (str == null) { var encodingName = directory.GetString(IptcDirectory.TagCodedCharacterSet); Encoding encoding = null; if (encodingName != null) { try { encoding = Encoding.GetEncoding(encodingName); } catch { } } var bytes = reader.GetBytes(tagByteCount); if (encoding == null) { encoding = Iso2022Converter.GuessEncoding(bytes); } if (encoding == null) { encoding = Encoding.UTF8; } str = encoding.GetString(bytes); } if (directory.ContainsTag(tagIdentifier)) { // this fancy string[] business avoids using an ArrayList for performance reasons var oldStrings = directory.GetStringArray(tagIdentifier); string[] newStrings; if (oldStrings == null) { // TODO hitting this block means any prior value(s) are discarded newStrings = new string[1]; } else { newStrings = new string[oldStrings.Length + 1]; Array.Copy(oldStrings, 0, newStrings, 0, oldStrings.Length); } newStrings[newStrings.Length - 1] = str; directory.Set(tagIdentifier, newStrings); } else { directory.Set(tagIdentifier, str); } }