| /* |
| * Copyright (C) 2007-2008 Esmertec AG. |
| * Copyright (C) 2007-2008 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.mms.dom.smil; |
| |
| import org.w3c.dom.DOMException; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.smil.Time; |
| |
| public class TimeImpl implements Time { |
| static final int ALLOW_INDEFINITE_VALUE = (1 << 0); |
| static final int ALLOW_OFFSET_VALUE = (1 << 1); |
| static final int ALLOW_SYNCBASE_VALUE = (1 << 2); |
| static final int ALLOW_SYNCTOPREV_VALUE = (1 << 3); |
| static final int ALLOW_EVENT_VALUE = (1 << 4); |
| static final int ALLOW_MARKER_VALUE = (1 << 5); |
| static final int ALLOW_WALLCLOCK_VALUE = (1 << 6); |
| static final int ALLOW_NEGATIVE_VALUE = (1 << 7); |
| static final int ALLOW_ALL = 0xFF; |
| |
| short mTimeType; |
| boolean mResolved; |
| double mResolvedOffset; |
| |
| /** |
| * Creates a TimeImpl representation of a time-value represented as a String. |
| * Time-values have the following syntax: |
| * <p> |
| * <pre> |
| * Time-val ::= ( smil-1.0-syncbase-value |
| * | "indefinite" |
| * | offset-value |
| * | syncbase-value |
| * | syncToPrev-value |
| * | event-value |
| * | media-marker-value |
| * | wallclock-sync-value ) |
| * Smil-1.0-syncbase-value ::= |
| * "id(" id-ref ")" ( "(" ( "begin" | "end" | clock-value ) ")" )? |
| * Offset-value ::= ( "+" | "-" )? clock-value |
| * Syncbase-value ::= ( id-ref "." ( "begin" | "end" ) ) ( ( "+" | "-" ) clock-value )? |
| * SyncToPrev-value ::= ( "prev.begin" | "prev.end" ) ( ( "+" | "-" ) clock-value )? |
| * Event-value ::= ( id-ref "." )? ( event-ref ) ( ( "+" | "-" ) clock-value )? |
| * Media-marker-value ::= id-ref ".marker(" marker-name ")" |
| * Wallclock-sync-value ::= "wallclock(" wallclock-value ")" |
| * </pre> |
| * |
| * @param timeValue A String in the representation specified above |
| * @param constraints Any combination of the #ALLOW_* flags |
| * @return A TimeImpl instance representing |
| * @exception java.lang.IllegalArgumentException if the timeValue input |
| * parameter does not comply with the defined syntax |
| * @exception java.lang.NullPointerException if the timekValue string is |
| * <code>null</code> |
| */ |
| TimeImpl(String timeValue, int constraints) { |
| /* |
| * We do not support yet: |
| * - smil-1.0-syncbase-value |
| * - syncbase-value |
| * - syncToPrev-value |
| * - event-value |
| * - Media-marker-value |
| * - Wallclock-sync-value |
| */ |
| // Will throw NullPointerException if timeValue is null |
| if (timeValue.equals("indefinite") |
| && ((constraints & ALLOW_INDEFINITE_VALUE) != 0) ) { |
| mTimeType = SMIL_TIME_INDEFINITE; |
| } else if ((constraints & ALLOW_OFFSET_VALUE) != 0) { |
| int sign = 1; |
| if (timeValue.startsWith("+")) { |
| timeValue = timeValue.substring(1); |
| } else if (timeValue.startsWith("-")) { |
| timeValue = timeValue.substring(1); |
| sign = -1; |
| } |
| mResolvedOffset = sign*parseClockValue(timeValue)/1000.0; |
| mResolved = true; |
| mTimeType = SMIL_TIME_OFFSET; |
| } else { |
| throw new IllegalArgumentException("Unsupported time value"); |
| } |
| } |
| |
| /** |
| * Converts a String representation of a clock value into the float |
| * representation used in this API. |
| * <p> |
| * Clock values have the following syntax: |
| * </p> |
| * <p> |
| * <pre> |
| * Clock-val ::= ( Full-clock-val | Partial-clock-val | Timecount-val ) |
| * Full-clock-val ::= Hours ":" Minutes ":" Seconds ("." Fraction)? |
| * Partial-clock-val ::= Minutes ":" Seconds ("." Fraction)? |
| * Timecount-val ::= Timecount ("." Fraction)? (Metric)? |
| * Metric ::= "h" | "min" | "s" | "ms" |
| * Hours ::= DIGIT+; any positive number |
| * Minutes ::= 2DIGIT; range from 00 to 59 |
| * Seconds ::= 2DIGIT; range from 00 to 59 |
| * Fraction ::= DIGIT+ |
| * Timecount ::= DIGIT+ |
| * 2DIGIT ::= DIGIT DIGIT |
| * DIGIT ::= [0-9] |
| * </pre> |
| * |
| * @param clockValue A String in the representation specified above |
| * @return A float value in milliseconds that matches the string |
| * representation given as the parameter |
| * @exception java.lang.IllegalArgumentException if the clockValue input |
| * parameter does not comply with the defined syntax |
| * @exception java.lang.NullPointerException if the clockValue string is |
| * <code>null</code> |
| */ |
| public static float parseClockValue(String clockValue) { |
| try { |
| float result = 0; |
| |
| // Will throw NullPointerException if clockValue is null |
| clockValue = clockValue.trim(); |
| |
| // Handle first 'Timecount-val' cases with metric |
| if (clockValue.endsWith("ms")) { |
| result = parseFloat(clockValue, 2, true); |
| } else if (clockValue.endsWith("s")) { |
| result = 1000*parseFloat(clockValue, 1, true); |
| } else if (clockValue.endsWith("min")) { |
| result = 60000*parseFloat(clockValue, 3, true); |
| } else if (clockValue.endsWith("h")) { |
| result = 3600000*parseFloat(clockValue, 1, true); |
| } else { |
| // Handle Timecount-val without metric |
| try { |
| return parseFloat(clockValue, 0, true) * 1000; |
| } catch (NumberFormatException _) { |
| // Ignore |
| } |
| |
| // Split in {[Hours], Minutes, Seconds} |
| String[] timeValues = clockValue.split(":"); |
| |
| // Read Hours if present and remember location of Minutes |
| int indexOfMinutes; |
| if (timeValues.length == 2) { |
| indexOfMinutes = 0; |
| } else if (timeValues.length == 3) { |
| result = 3600000*(int)parseFloat(timeValues[0], 0, false); |
| indexOfMinutes = 1; |
| } else { |
| throw new IllegalArgumentException(); |
| } |
| |
| // Read Minutes |
| int minutes = (int)parseFloat(timeValues[indexOfMinutes], 0, false); |
| if ((minutes >= 00) && (minutes <= 59)) { |
| result += 60000*minutes; |
| } else { |
| throw new IllegalArgumentException(); |
| } |
| |
| // Read Seconds |
| float seconds = parseFloat(timeValues[indexOfMinutes + 1], 0, true); |
| if ((seconds >= 00) && (seconds < 60)) { |
| result += 60000*seconds; |
| } else { |
| throw new IllegalArgumentException(); |
| } |
| |
| } |
| return result; |
| } catch (NumberFormatException e) { |
| throw new IllegalArgumentException(); |
| } |
| } |
| |
| /** |
| * Parse a value formatted as follows: |
| * <p> |
| * <pre> |
| * Value ::= Number ("." Decimal)? (Text)? |
| * Number ::= DIGIT+; any positive number |
| * Decimal ::= DIGIT+; any positive number |
| * Text ::= CHAR*; any sequence of chars |
| * DIGIT ::= [0-9] |
| * </pre> |
| * @param value The Value to parse |
| * @param ignoreLast The size of Text to ignore |
| * @param parseDecimal Whether Decimal is expected |
| * @return The float value without Text, rounded to 3 digits after '.' |
| * @throws IllegalArgumentException if Decimal was not expected but encountered |
| */ |
| private static float parseFloat(String value, int ignoreLast, boolean parseDecimal) { |
| // Ignore last characters |
| value = value.substring(0, value.length() - ignoreLast); |
| |
| float result; |
| int indexOfComma = value.indexOf('.'); |
| if (indexOfComma != -1) { |
| if (!parseDecimal) { |
| throw new IllegalArgumentException("int value contains decimal"); |
| } |
| // Ensure that there are at least 3 decimals |
| value = value + "000"; |
| // Read value up to 3 decimals and cut the rest |
| result = Float.parseFloat(value.substring(0, indexOfComma)); |
| result += Float.parseFloat( |
| value.substring(indexOfComma + 1, indexOfComma + 4))/1000; |
| } else { |
| result = Integer.parseInt(value); |
| } |
| |
| return result; |
| } |
| |
| /* |
| * Time Interface |
| */ |
| |
| public boolean getBaseBegin() { |
| // TODO Auto-generated method stub |
| return false; |
| } |
| |
| public Element getBaseElement() { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| public String getEvent() { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| public String getMarker() { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| public double getOffset() { |
| // TODO Auto-generated method stub |
| return 0; |
| } |
| |
| public boolean getResolved() { |
| return mResolved; |
| } |
| |
| public double getResolvedOffset() { |
| return mResolvedOffset; |
| } |
| |
| public short getTimeType() { |
| return mTimeType; |
| } |
| |
| public void setBaseBegin(boolean baseBegin) throws DOMException { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| public void setBaseElement(Element baseElement) throws DOMException { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| public void setEvent(String event) throws DOMException { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| public void setMarker(String marker) throws DOMException { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| public void setOffset(double offset) throws DOMException { |
| // TODO Auto-generated method stub |
| |
| } |
| } |