Ignore:
Timestamp:
2016-08-20T20:58:03+02:00 (10 years ago)
Author:
Don-vip
Message:

update to metadata-extractor 2.9.1

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/com/drew/metadata/Directory.java

    r8243 r10862  
    11/*
    2  * Copyright 2002-2015 Drew Noakes
     2 * Copyright 2002-2016 Drew Noakes
    33 *
    44 *    Licensed under the Apache License, Version 2.0 (the "License");
     
    2424import com.drew.lang.annotations.NotNull;
    2525import com.drew.lang.annotations.Nullable;
    26 import com.drew.lang.annotations.SuppressWarnings;
    2726
    2827import java.io.UnsupportedEncodingException;
    2928import java.lang.reflect.Array;
    3029import java.text.DateFormat;
     30import java.text.DecimalFormat;
    3131import java.text.ParseException;
    3232import java.text.SimpleDateFormat;
    3333import java.util.*;
     34import java.util.regex.Matcher;
     35import java.util.regex.Pattern;
    3436
    3537/**
     
    4143public abstract class Directory
    4244{
     45    private static final DecimalFormat _floatFormat = new DecimalFormat("0.###");
     46
    4347    /** Map of values hashed by type identifiers. */
    4448    @NotNull
     
    5963    protected TagDescriptor _descriptor;
    6064
     65    @Nullable
     66    private Directory _parent;
     67
    6168// ABSTRACT METHODS
    6269
     
    171178    {
    172179        return _errorList.size();
     180    }
     181
     182    @Nullable
     183    public Directory getParent()
     184    {
     185        return _parent;
     186    }
     187
     188    public void setParent(@NotNull Directory parent)
     189    {
     190        _parent = parent;
    173191    }
    174192
     
    701719    /** Returns the specified tag's value as a boolean.  If the tag is not set or cannot be converted, <code>null</code> is returned. */
    702720    @Nullable
    703     @SuppressWarnings(value = "NP_BOOLEAN_RETURN_NULL", justification = "keep API interface consistent")
    704721    public Boolean getBooleanObject(int tagType)
    705722    {
     
    725742     * <p>
    726743     * If the underlying value is a {@link String}, then attempts will be made to parse the string as though it is in
    727      * the current {@link TimeZone}.  If the {@link TimeZone} is known, call the overload that accepts one as an argument.
     744     * the GMT {@link TimeZone}.  If the {@link TimeZone} is known, call the overload that accepts one as an argument.
    728745     */
    729746    @Nullable
    730747    public java.util.Date getDate(int tagType)
    731748    {
    732         return getDate(tagType, null);
     749        return getDate(tagType, null, null);
    733750    }
    734751
     
    738755     * If the underlying value is a {@link String}, then attempts will be made to parse the string as though it is in
    739756     * the {@link TimeZone} represented by the {@code timeZone} parameter (if it is non-null).  Note that this parameter
    740      * is only considered if the underlying value is a string and parsing occurs, otherwise it has no effect.
     757     * is only considered if the underlying value is a string and it has no time zone information, otherwise it has no effect.
    741758     */
    742759    @Nullable
    743760    public java.util.Date getDate(int tagType, @Nullable TimeZone timeZone)
    744761    {
    745         Object o = getObject(tagType);
    746 
    747         if (o == null)
    748             return null;
     762        return getDate(tagType, null, timeZone);
     763    }
     764
     765    /**
     766     * Returns the specified tag's value as a java.util.Date.  If the value is unset or cannot be converted, <code>null</code> is returned.
     767     * <p>
     768     * If the underlying value is a {@link String}, then attempts will be made to parse the string as though it is in
     769     * the {@link TimeZone} represented by the {@code timeZone} parameter (if it is non-null).  Note that this parameter
     770     * is only considered if the underlying value is a string and it has no time zone information, otherwise it has no effect.
     771     * In addition, the {@code subsecond} parameter, which specifies the number of digits after the decimal point in the seconds,
     772     * is set to the returned Date. This parameter is only considered if the underlying value is a string and is has
     773     * no subsecond information, otherwise it has no effect.
     774     *
     775     * @param tagType the tag identifier
     776     * @param subsecond the subsecond value for the Date
     777     * @param timeZone the time zone to use
     778     * @return a Date representing the time value
     779     */
     780    @Nullable
     781    public java.util.Date getDate(int tagType, @Nullable String subsecond, @Nullable TimeZone timeZone)
     782    {
     783        Object o = getObject(tagType);
    749784
    750785        if (o instanceof java.util.Date)
    751786            return (java.util.Date)o;
    752787
     788        java.util.Date date = null;
     789
    753790        if (o instanceof String) {
    754             // This seems to cover all known Exif date strings
     791            // This seems to cover all known Exif and Xmp date strings
    755792            // Note that "    :  :     :  :  " is a valid date string according to the Exif spec (which means 'unknown date'): http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif/datetimeoriginal.html
    756793            String datePatterns[] = {
     
    760797                    "yyyy-MM-dd HH:mm",
    761798                    "yyyy.MM.dd HH:mm:ss",
    762                     "yyyy.MM.dd HH:mm" };
     799                    "yyyy.MM.dd HH:mm",
     800                    "yyyy-MM-dd'T'HH:mm:ss",
     801                    "yyyy-MM-dd'T'HH:mm",
     802                    "yyyy-MM-dd",
     803                    "yyyy-MM",
     804                    "yyyy" };
    763805            String dateString = (String)o;
     806
     807            // if the date string has subsecond information, it supersedes the subsecond parameter
     808            Pattern subsecondPattern = Pattern.compile("(\\d\\d:\\d\\d:\\d\\d)(\\.\\d+)");
     809            Matcher subsecondMatcher = subsecondPattern.matcher(dateString);
     810            if (subsecondMatcher.find()) {
     811                subsecond = subsecondMatcher.group(2).substring(1);
     812                dateString = subsecondMatcher.replaceAll("$1");
     813            }
     814
     815            // if the date string has time zone information, it supersedes the timeZone parameter
     816            Pattern timeZonePattern = Pattern.compile("(Z|[+-]\\d\\d:\\d\\d)$");
     817            Matcher timeZoneMatcher = timeZonePattern.matcher(dateString);
     818            if (timeZoneMatcher.find()) {
     819                timeZone = TimeZone.getTimeZone("GMT" + timeZoneMatcher.group().replaceAll("Z", ""));
     820                dateString = timeZoneMatcher.replaceAll("");
     821            }
     822
    764823            for (String datePattern : datePatterns) {
    765824                try {
     
    770829                        parser.setTimeZone(TimeZone.getTimeZone("GMT")); // don't interpret zone time
    771830
    772                     return parser.parse(dateString);
     831                    date = parser.parse(dateString);
     832                    break;
    773833                } catch (ParseException ex) {
    774834                    // simply try the next pattern
     
    776836            }
    777837        }
    778         return null;
     838
     839        if (date == null)
     840            return null;
     841
     842        if (subsecond == null)
     843            return date;
     844
     845        try {
     846            int millisecond = (int) (Double.parseDouble("." + subsecond) * 1000);
     847            if (millisecond >= 0 && millisecond < 1000) {
     848                Calendar calendar = Calendar.getInstance();
     849                calendar.setTime(date);
     850                calendar.set(Calendar.MILLISECOND, millisecond);
     851                return calendar.getTime();
     852            }
     853            return date;
     854        } catch (NumberFormatException e) {
     855            return date;
     856        }
    779857    }
    780858
     
    835913            int arrayLength = Array.getLength(o);
    836914            final Class<?> componentType = o.getClass().getComponentType();
    837             boolean isObjectArray = Object.class.isAssignableFrom(componentType);
    838             boolean isFloatArray = componentType.getName().equals("float");
    839             boolean isDoubleArray = componentType.getName().equals("double");
    840             boolean isIntArray = componentType.getName().equals("int");
    841             boolean isLongArray = componentType.getName().equals("long");
    842             boolean isByteArray = componentType.getName().equals("byte");
    843             boolean isShortArray = componentType.getName().equals("short");
     915
    844916            StringBuilder string = new StringBuilder();
    845             for (int i = 0; i < arrayLength; i++) {
    846                 if (i != 0)
    847                     string.append(' ');
    848                 if (isObjectArray)
     917
     918            if (Object.class.isAssignableFrom(componentType)) {
     919                // object array
     920                for (int i = 0; i < arrayLength; i++) {
     921                    if (i != 0)
     922                        string.append(' ');
    849923                    string.append(Array.get(o, i).toString());
    850                 else if (isIntArray)
     924                }
     925            } else if (componentType.getName().equals("int")) {
     926                for (int i = 0; i < arrayLength; i++) {
     927                    if (i != 0)
     928                        string.append(' ');
    851929                    string.append(Array.getInt(o, i));
    852                 else if (isShortArray)
     930                }
     931            } else if (componentType.getName().equals("short")) {
     932                for (int i = 0; i < arrayLength; i++) {
     933                    if (i != 0)
     934                        string.append(' ');
    853935                    string.append(Array.getShort(o, i));
    854                 else if (isLongArray)
     936                }
     937            } else if (componentType.getName().equals("long")) {
     938                for (int i = 0; i < arrayLength; i++) {
     939                    if (i != 0)
     940                        string.append(' ');
    855941                    string.append(Array.getLong(o, i));
    856                 else if (isFloatArray)
    857                     string.append(Array.getFloat(o, i));
    858                 else if (isDoubleArray)
    859                     string.append(Array.getDouble(o, i));
    860                 else if (isByteArray)
    861                     string.append(Array.getByte(o, i));
    862                 else
    863                     addError("Unexpected array component type: " + componentType.getName());
    864             }
     942                }
     943            } else if (componentType.getName().equals("float")) {
     944                for (int i = 0; i < arrayLength; i++) {
     945                    if (i != 0)
     946                        string.append(' ');
     947                    string.append(_floatFormat.format(Array.getFloat(o, i)));
     948                }
     949            } else if (componentType.getName().equals("double")) {
     950                for (int i = 0; i < arrayLength; i++) {
     951                    if (i != 0)
     952                        string.append(' ');
     953                    string.append(_floatFormat.format(Array.getDouble(o, i)));
     954                }
     955            } else if (componentType.getName().equals("byte")) {
     956                for (int i = 0; i < arrayLength; i++) {
     957                    if (i != 0)
     958                        string.append(' ');
     959                    string.append(Array.getByte(o, i) & 0xff);
     960                }
     961            } else {
     962                addError("Unexpected array component type: " + componentType.getName());
     963            }
     964
    865965            return string.toString();
    866966        }
     967
     968        if (o instanceof Double)
     969            return _floatFormat.format(((Double)o).doubleValue());
     970
     971        if (o instanceof Float)
     972            return _floatFormat.format(((Float)o).floatValue());
    867973
    868974        // Note that several cameras leave trailing spaces (Olympus, Nikon) but this library is intended to show
Note: See TracChangeset for help on using the changeset viewer.