1f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// ================================================================================================= 2f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// ADOBE SYSTEMS INCORPORATED 3f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// Copyright 2006 Adobe Systems Incorporated 4f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// All Rights Reserved 5f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// 6f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms 7f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// of the Adobe license agreement accompanying it. 8f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// ================================================================================================= 9f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 10f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingpackage com.adobe.xmp.impl; 11f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 12f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport java.text.DecimalFormat; 13f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport java.text.DecimalFormatSymbols; 14f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport java.util.Locale; 15f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport java.util.SimpleTimeZone; 16f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 17f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.XMPDateTime; 18f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.XMPError; 19f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.XMPException; 20f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 21f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 22f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling/** 23f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Converts between ISO 8601 Strings and <code>Calendar</code> with millisecond resolution. 24f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 25f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @since 16.02.2006 26f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 27f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingpublic final class ISO8601Converter 28f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling{ 29f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** Hides public constructor */ 30f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling private ISO8601Converter() 31f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 32f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // EMPTY 33f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 34f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 35f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 36f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 37f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Converts an ISO 8601 string to an <code>XMPDateTime</code>. 38f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 39f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Parse a date according to ISO 8601 and 40f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * http://www.w3.org/TR/NOTE-datetime: 41f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <ul> 42f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>YYYY 43f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>YYYY-MM 44f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>YYYY-MM-DD 45f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>YYYY-MM-DDThh:mmTZD 46f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>YYYY-MM-DDThh:mm:ssTZD 47f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>YYYY-MM-DDThh:mm:ss.sTZD 48f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * </ul> 49f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 50f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Data fields: 51f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <ul> 52f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>YYYY = four-digit year 53f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>MM = two-digit month (01=January, etc.) 54f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>DD = two-digit day of month (01 through 31) 55f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>hh = two digits of hour (00 through 23) 56f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>mm = two digits of minute (00 through 59) 57f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>ss = two digits of second (00 through 59) 58f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>s = one or more digits representing a decimal fraction of a second 59f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>TZD = time zone designator (Z or +hh:mm or -hh:mm) 60f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * </ul> 61f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 62f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Note that ISO 8601 does not seem to allow years less than 1000 or greater 63f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * than 9999. We allow any year, even negative ones. The year is formatted 64f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * as "%.4d". 65f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <p> 66f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <em>Note:</em> Tolerate missing TZD, assume is UTC. Photoshop 8 writes 67f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * dates like this for exif:GPSTimeStamp.<br> 68f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <em>Note:</em> Tolerate missing date portion, in case someone foolishly 69f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * writes a time-only value that way. 70f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 71f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param iso8601String a date string that is ISO 8601 conform. 72f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @return Returns a <code>Calendar</code>. 73f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @throws XMPException Is thrown when the string is non-conform. 74f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 75f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling public static XMPDateTime parse(String iso8601String) throws XMPException 76f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 77f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return parse(iso8601String, new XMPDateTimeImpl()); 78f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 79f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 80f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 81f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 82f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param iso8601String a date string that is ISO 8601 conform. 83f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param binValue an existing XMPDateTime to set with the parsed date 84f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @return Returns an XMPDateTime-object containing the ISO8601-date. 85f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @throws XMPException Is thrown when the string is non-conform. 86f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 87f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling public static XMPDateTime parse(String iso8601String, XMPDateTime binValue) throws XMPException 88f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 89f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling ParameterAsserts.assertNotNull(iso8601String); 90f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 91f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling ParseState input = new ParseState(iso8601String); 92f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling int value; 93f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 94f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling boolean timeOnly = 95f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling input.ch(0) == 'T' || 96f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling (input.length() >= 2 && input.ch(1) == ':' || 97f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling (input.length() >= 3 && input.ch(2) == ':')); 98f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 99f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (!timeOnly) 100f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 101f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (input.ch(0) == '-') 102f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 103f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling input.skip(); 104f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 105f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 106f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 107f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Extract the year. 108f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling value = input.gatherInt("Invalid year in date string", 9999); 109f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (input.hasNext() && input.ch() != '-') 110f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 111f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Invalid date string, after year", XMPError.BADVALUE); 112f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 113f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 114f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (input.ch(0) == '-') 115f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 116f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling value = -value; 117f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 118f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling binValue.setYear(value); 119f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (!input.hasNext()) 120f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 121f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return binValue; 122f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 123f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling input.skip(); 124f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 125f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 126f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Extract the month. 127f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling value = input.gatherInt("Invalid month in date string", 12); 128f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (input.hasNext() && input.ch() != '-') 129f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 130f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Invalid date string, after month", XMPError.BADVALUE); 131f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 132f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling binValue.setMonth(value); 133f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (!input.hasNext()) 134f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 135f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return binValue; 136f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 137f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling input.skip(); 138f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 139f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 140f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Extract the day. 141f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling value = input.gatherInt("Invalid day in date string", 31); 142f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (input.hasNext() && input.ch() != 'T') 143f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 144f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Invalid date string, after day", XMPError.BADVALUE); 145f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 146f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling binValue.setDay(value); 147f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (!input.hasNext()) 148f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 149f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return binValue; 150f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 151f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 152f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else 153f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 154f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // set default day and month in the year 0000 155f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling binValue.setMonth(1); 156f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling binValue.setDay(1); 157f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 158f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 159f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (input.ch() == 'T') 160f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 161f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling input.skip(); 162f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 163f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (!timeOnly) 164f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 165f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Invalid date string, missing 'T' after date", 166f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPError.BADVALUE); 167f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 168f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 169f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 170f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Extract the hour. 171f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling value = input.gatherInt("Invalid hour in date string", 23); 172f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (input.ch() != ':') 173f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 174f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Invalid date string, after hour", XMPError.BADVALUE); 175f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 176f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling binValue.setHour(value); 177f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 178f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Don't check for done, we have to work up to the time zone. 179f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling input.skip(); 180f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 181f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 182f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Extract the minute. 183f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling value = input.gatherInt("Invalid minute in date string", 59); 184f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (input.hasNext() && 185f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling input.ch() != ':' && input.ch() != 'Z' && input.ch() != '+' && input.ch() != '-') 186f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 187f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Invalid date string, after minute", XMPError.BADVALUE); 188f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 189f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling binValue.setMinute(value); 190f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 191f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (input.ch() == ':') 192f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 193f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling input.skip(); 194f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling value = input.gatherInt("Invalid whole seconds in date string", 59); 195f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (input.hasNext() && input.ch() != '.' && input.ch() != 'Z' && 196f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling input.ch() != '+' && input.ch() != '-') 197f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 198f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Invalid date string, after whole seconds", 199f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPError.BADVALUE); 200f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 201f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling binValue.setSecond(value); 202f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (input.ch() == '.') 203f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 204f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling input.skip(); 205f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling int digits = input.pos(); 206f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling value = input.gatherInt("Invalid fractional seconds in date string", 999999999); 207f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (input.ch() != 'Z' && input.ch() != '+' && input.ch() != '-') 208f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 209f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Invalid date string, after fractional second", 210f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPError.BADVALUE); 211f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 212f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling digits = input.pos() - digits; 213f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling for (; digits > 9; --digits) 214f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 215f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling value = value / 10; 216f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 217f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling for (; digits < 9; ++digits) 218f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 219f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling value = value * 10; 220f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 221f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling binValue.setNanoSecond(value); 222f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 223f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 224f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 225f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling int tzSign = 0; 226f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling int tzHour = 0; 227f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling int tzMinute = 0; 228f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (input.ch() == 'Z') 229f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 230f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling input.skip(); 231f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 232f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (input.hasNext()) 233f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 234f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (input.ch() == '+') 235f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 236f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling tzSign = 1; 237f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 238f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (input.ch() == '-') 239f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 240f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling tzSign = -1; 241f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 242f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else 243f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 244f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Time zone must begin with 'Z', '+', or '-'", 245f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPError.BADVALUE); 246f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 247f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 248f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling input.skip(); 249f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Extract the time zone hour. 250f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling tzHour = input.gatherInt("Invalid time zone hour in date string", 23); 251f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (input.ch() != ':') 252f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 253f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Invalid date string, after time zone hour", 254f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPError.BADVALUE); 255f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 256f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling input.skip(); 257f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 258f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Extract the time zone minute. 259f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling tzMinute = input.gatherInt("Invalid time zone minute in date string", 59); 260f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 261f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 262f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // create a corresponding TZ and set it time zone 263f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling int offset = (tzHour * 3600 * 1000 + tzMinute * 60 * 1000) * tzSign; 264f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling binValue.setTimeZone(new SimpleTimeZone(offset, "")); 265f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 266f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 267f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (input.hasNext()) 268f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 269f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException( 270f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling "Invalid date string, extra chars at end", XMPError.BADVALUE); 271f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 272f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 273f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return binValue; 274f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 275f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 276f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 277f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 278f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Converts a <code>Calendar</code> into an ISO 8601 string. 279f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Format a date according to ISO 8601 and http://www.w3.org/TR/NOTE-datetime: 280f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <ul> 281f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>YYYY 282f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>YYYY-MM 283f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>YYYY-MM-DD 284f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>YYYY-MM-DDThh:mmTZD 285f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>YYYY-MM-DDThh:mm:ssTZD 286f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>YYYY-MM-DDThh:mm:ss.sTZD 287f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * </ul> 288f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 289f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Data fields: 290f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <ul> 291f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>YYYY = four-digit year 292f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>MM = two-digit month (01=January, etc.) 293f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>DD = two-digit day of month (01 through 31) 294f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>hh = two digits of hour (00 through 23) 295f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>mm = two digits of minute (00 through 59) 296f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>ss = two digits of second (00 through 59) 297f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>s = one or more digits representing a decimal fraction of a second 298f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <li>TZD = time zone designator (Z or +hh:mm or -hh:mm) 299f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * </ul> 300f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <p> 301f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <em>Note:</em> ISO 8601 does not seem to allow years less than 1000 or greater than 9999. 302f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * We allow any year, even negative ones. The year is formatted as "%.4d".<p> 303f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <em>Note:</em> Fix for bug 1269463 (silently fix out of range values) included in parsing. 304f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * The quasi-bogus "time only" values from Photoshop CS are not supported. 305f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 306f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param dateTime an XMPDateTime-object. 307f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @return Returns an ISO 8601 string. 308f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 309f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling public static String render(XMPDateTime dateTime) 310f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 311f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling StringBuffer buffer = new StringBuffer(); 312f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 313f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // year is rendered in any case, even 0000 314f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling DecimalFormat df = new DecimalFormat("0000", new DecimalFormatSymbols(Locale.ENGLISH)); 315f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling buffer.append(df.format(dateTime.getYear())); 316f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (dateTime.getMonth() == 0) 317f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 318f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return buffer.toString(); 319f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 320f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 321f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // month 322f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling df.applyPattern("'-'00"); 323f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling buffer.append(df.format(dateTime.getMonth())); 324f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (dateTime.getDay() == 0) 325f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 326f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return buffer.toString(); 327f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 328f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 329f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // day 330f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling buffer.append(df.format(dateTime.getDay())); 331f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 332f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // time, rendered if any time field is not zero 333f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (dateTime.getHour() != 0 || 334f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling dateTime.getMinute() != 0 || 335f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling dateTime.getSecond() != 0 || 336f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling dateTime.getNanoSecond() != 0 || 337f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling (dateTime.getTimeZone() != null && dateTime.getTimeZone().getRawOffset() != 0)) 338f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 339f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // hours and minutes 340f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling buffer.append('T'); 341f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling df.applyPattern("00"); 342f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling buffer.append(df.format(dateTime.getHour())); 343f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling buffer.append(':'); 344f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling buffer.append(df.format(dateTime.getMinute())); 345f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 346f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // seconds and nanoseconds 347f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (dateTime.getSecond() != 0 || dateTime.getNanoSecond() != 0) 348f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 349f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling double seconds = dateTime.getSecond() + dateTime.getNanoSecond() / 1e9d; 350f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 351f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling df.applyPattern(":00.#########"); 352f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling buffer.append(df.format(seconds)); 353f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 354f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 355f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // time zone 356f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (dateTime.getTimeZone() != null) 357f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 358f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // used to calculate the time zone offset incl. Daylight Savings 359f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling long timeInMillis = dateTime.getCalendar().getTimeInMillis(); 360f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling int offset = dateTime.getTimeZone().getOffset(timeInMillis); 361f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (offset == 0) 362f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 363f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // UTC 364f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling buffer.append('Z'); 365f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 366f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else 367f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 368f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling int thours = offset / 3600000; 369f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling int tminutes = Math.abs(offset % 3600000 / 60000); 370f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling df.applyPattern("+00;-00"); 371f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling buffer.append(df.format(thours)); 372f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling df.applyPattern(":00"); 373f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling buffer.append(df.format(tminutes)); 374f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 375f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 376f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 377f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return buffer.toString(); 378f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 379f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 380f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 381f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling} 382f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 383f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 384f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling/** 385f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @since 22.08.2006 386f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 387f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingclass ParseState 388f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling{ 389f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** */ 390f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling private String str; 391f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** */ 392f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling private int pos = 0; 393f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 394f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 395f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 396f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param str initializes the parser container 397f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 398f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling public ParseState(String str) 399f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 400f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling this.str = str; 401f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 402f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 403f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 404f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 405f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @return Returns the length of the input. 406f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 407f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling public int length() 408f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 409f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return str.length(); 410f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 411f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 412f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 413f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 414f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @return Returns whether there are more chars to come. 415f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 416f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling public boolean hasNext() 417f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 418f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return pos < str.length(); 419f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 420f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 421f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 422f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 423f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param index index of char 424f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @return Returns char at a certain index. 425f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 426f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling public char ch(int index) 427f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 428f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return index < str.length() ? 429f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling str.charAt(index) : 430f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 0x0000; 431f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 432f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 433f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 434f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 435f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @return Returns the current char or 0x0000 if there are no more chars. 436f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 437f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling public char ch() 438f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 439f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return pos < str.length() ? 440f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling str.charAt(pos) : 441f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 0x0000; 442f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 443f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 444f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 445f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 446f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Skips the next char. 447f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 448f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling public void skip() 449f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 450f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling pos++; 451f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 452f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 453f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 454f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 455f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @return Returns the current position. 456f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 457f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling public int pos() 458f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 459f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return pos; 460f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 461f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 462f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 463f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 464f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Parses a integer from the source and sets the pointer after it. 465f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param errorMsg Error message to put in the exception if no number can be found 466f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param maxValue the max value of the number to return 467f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @return Returns the parsed integer. 468f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @throws XMPException Thrown if no integer can be found. 469f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 470f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling public int gatherInt(String errorMsg, int maxValue) throws XMPException 471f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 472f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling int value = 0; 473f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling boolean success = false; 474f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling char ch = ch(pos); 475f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling while ('0' <= ch && ch <= '9') 476f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 477f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling value = (value * 10) + (ch - '0'); 478f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling success = true; 479f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling pos++; 480f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling ch = ch(pos); 481f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 482f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 483f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (success) 484f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 485f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (value > maxValue) 486f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 487f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return maxValue; 488f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 489f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (value < 0) 490f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 491f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return 0; 492f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 493f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else 494f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 495f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return value; 496f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 497f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 498f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else 499f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 500f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException(errorMsg, XMPError.BADVALUE); 501f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 502f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 503f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling} 504f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 505f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 506