package org.androiddaisyreader.model; import java.text.DecimalFormat; import org.xml.sax.Attributes; /** * Utility class to extract the timing values from the SMIL files. * * * Note: The npt= format is the required format for DAISY 2.02 books. * * http://www.daisy.org/z3986/specifications/daisy_202.html#smil (and search for * npt= in section 2.3.3.8 Attributes on the <audio> element) See also * http://www.w3.org/TR/REC-smil/ although this is not very enlightening. * * @author Julian Harty */ public class ExtractTimingValues { private static final int DAISYFORMAT202 = 202; private static final int DAISYFORMAT30 = 30; /** * Extract the effective value of the time offset for a given element. * * @param elementName the name of the element to extract the value for. * @param attributes the set of attributes which include the expected name. * @return the double representing the effective value of the time offset. */ @Deprecated static double extractTiming(String elementName, Attributes attributes) { String trimmedValue = getTrimmedValue(elementName, attributes); return Double.parseDouble(trimmedValue); } private static String getTrimmedValue(String elementName, Attributes attributes) { String rawValue = ParserUtilities.getValueForName(elementName, attributes); return rawValue.replace("npt=", "").replace("s", ""); } /** * Extract the effective value of the time offset for a given element of * daisy30. * * @param elementName the name of the element to extract the value for. * @param attributes the set of attributes which include the expected name. * @return the double representing the effective value of the time offset. */ @Deprecated static double extractTimingForDaisy30(String elementName, Attributes attributes) { return getTrimmedValueForDaisy30(elementName, attributes); } /** * Gets the trimmed value for daisy30. * * @param elementName the name of the element to extract the value for * @param attributes the set of attributes which include the expected name * @return the value as a double */ private static double getTrimmedValueForDaisy30(String elementName, Attributes attributes) { String rawValue = ParserUtilities.getValueForName(elementName, attributes); String[] splitRawValue = rawValue.split(":"); if (splitRawValue.length == 2) { rawValue = "0:" + rawValue; splitRawValue = rawValue.split(":"); } double trimmedValue = parseToMilliseconds(splitRawValue[0], splitRawValue[1], splitRawValue[2]); return trimmedValue; } /** * Extract the timing value as an int containing the number of mSecs. * * Notes: 1. I have a strong suspicion I'll end up revisiting this code as * we add support for more locales and test the software with international * DAISY content. (However, the current old code works with a mix of books * from various countries and languages so perhaps this'll work?) * * 2. This code is probably unnecessarily complicated, I will seek existing * java libraries which may more elegantly replace most of my code... * * @param elementName The name we want to extract the value for * @param attributes The set of attributes. * @return the int value representing the number of miliseconds for * elementName */ static int extractTimingAsMilliSeconds(String elementName, Attributes attributes, int daisyFormat) { final int convertToSecond = 1000; Double temp = getExtractTiming(elementName, attributes, daisyFormat); DecimalFormat milliseconds = new DecimalFormat("###.###"); // Added by LogiGear to fix bug NumberFormatException when user change // location is VietNam String formattedDouble = milliseconds.format(temp).replace(",", "."); String[] values = formattedDouble.split("\\."); if (values.length > 2 || values.length == 0) { throw new NumberFormatException( "Expected the number to be formatted with no more than 1 decimal point, got " + temp.toString()); } if (values.length == 1) { return Integer.parseInt(values[0]) * convertToSecond; } return Integer.parseInt(values[0]) * convertToSecond + extractMilliSeconds(values[1]); } /** * Gets the extract timing. * * @param elementName The name we want to extract the value for * @param attributes The set of attributes. * @param daisyFormat the daisy format 3.0 or daisy format 2.02 * @return the extract timing as a double */ private static double getExtractTiming(String elementName, Attributes attributes, int daisyFormat) { Double temp = 0.00; switch (daisyFormat) { case DAISYFORMAT30: temp = extractTimingForDaisy30(elementName, attributes); break; case DAISYFORMAT202: temp = extractTiming(elementName, attributes); break; default: break; } return temp; } /** * The following code compensates for values such as .6 which is 600 mS and * .15 which is 150 mS, etc. * * @param decimalPart the string representing the digits to the right of the * decimal point. * @return the value as an integer. */ private static int extractMilliSeconds(String decimalPart) { int multiplier = 1; switch (decimalPart.length()) { case 3: case 0: multiplier = 1; break; case 2: multiplier = 10; break; case 1: multiplier = 100; break; default: throw new NumberFormatException("Unexpected number of digits after decimal point, got " + decimalPart); } return Integer.parseInt(decimalPart) * multiplier; } /** * Parses the to milliseconds. * * @param hours the hours * @param minutes the minutes * @param seconds the seconds * @return the value as a double */ private static double parseToMilliseconds(String hours, String minutes, String seconds) { final int convertToMinute = 60; final int convertToHour = 3600; double result = (Double.parseDouble(hours) * convertToHour) + (Double.parseDouble(minutes) * convertToMinute) + Double.parseDouble(seconds); return result; } }