Added Android code
[wl-app.git] / Android / r2-streamer / r2-parser / src / main / java / org / readium / r2_streamer / model / publication / SMIL / SMILParser.java
1 package org.readium.r2_streamer.model.publication.SMIL;
2
3 import org.w3c.dom.Element;
4
5 /**
6  * Created by gautam chibde on 23/5/17.
7  */
8
9 public final class SMILParser {
10
11     //Describes the different time string format of the SMIL tags
12     private enum SMILTimeFormat {
13         SPLIT_MONADIC,
14         SPLIT_DYADIC,
15         SPLIT_TRIADIC,
16         MILLISECOND,
17         SECOND,
18         HOUR,
19     }
20
21     /**
22      * Converts a smile time string into seconds String.
23      *
24      * @param time The smile time String.
25      * @return The converted value in Seconds as String.
26      */
27     public static String smilTimeToSeconds(String time) {
28         if (time.contains("h")) {
29             return convertToSeconds(time, SMILTimeFormat.HOUR);
30         } else if (time.contains("s")) {
31             return convertToSeconds(time, SMILTimeFormat.SECOND);
32
33         } else if (time.contains("ms")) {
34             return convertToSeconds(time, SMILTimeFormat.MILLISECOND);
35         } else {
36             int count = time.split(":").length;
37             switch (count) {
38                 case 1:
39                     return convertToSeconds(time, SMILTimeFormat.SPLIT_MONADIC);
40                 case 2:
41                     return convertToSeconds(time, SMILTimeFormat.SPLIT_DYADIC);
42                 case 3:
43                     return convertToSeconds(time, SMILTimeFormat.SPLIT_TRIADIC);
44                 default:
45                     return ""; // Should return null?
46             }
47         }
48     }
49
50     /**
51      * Convert the smileTime to the equivalent in seconds given it's type.
52      *
53      * @param time The SMILTime String.
54      * @param type type format of smileTime
55      * @return The converted value in Seconds as String.
56      */
57     private static String convertToSeconds(String time, SMILTimeFormat type) {
58         double seconds = 0.0;
59         switch (type) {
60             case HOUR:
61                 double ms = Double.parseDouble(time.replaceAll("ms", ""));
62                 return String.valueOf(ms / 1000.0);
63             case SECOND:
64                 return time.replaceAll("s", "");
65             case MILLISECOND:
66                 String[] hourMin = time.split(time.replaceAll("h", ""));
67                 double hrToSec = Double.parseDouble(hourMin[0]) * 3600.0;
68                 double minToSec = Double.parseDouble(hourMin[1]) * 0.6 * 60.0;
69                 return String.valueOf(hrToSec + minToSec);
70             case SPLIT_MONADIC:
71                 return time;
72             case SPLIT_DYADIC:
73                 String[] minSec = time.split(":");
74                 seconds += Double.parseDouble(minSec[0]) * 60.0;
75                 seconds += parseSeconds(time);
76                 return String.valueOf(seconds);
77             case SPLIT_TRIADIC:
78                 String[] hourMinSec = time.split(":");
79
80                 seconds += (Double.parseDouble(hourMinSec[0])) * 3600.0;
81
82                 seconds += (Double.parseDouble(hourMinSec[1])) * 60.0;
83
84                 seconds += parseSeconds(hourMinSec[2]);
85                 return String.valueOf(seconds);
86             default:
87                 return "";
88         }
89     }
90
91     /**
92      * Parse the <audio> XML element, children of <par> elements.
93      *
94      * @param element The audio XML element.
95      * @return The formatted string representing the data
96      * format => audio_path#t=start_time,end_time.
97      */
98     public static String parseAudio(Element element, String href) {
99         String audio, clipBegin, clipEnd;
100         if (element.hasAttribute("src")) {
101             audio = element.getAttribute("src");
102         } else {
103             return null;
104         }
105         if (element.hasAttribute("clipBegin")) {
106             clipBegin = element.getAttribute("clipBegin");
107         } else {
108             return null;
109         }
110         if (element.hasAttribute("clipEnd")) {
111             clipEnd = element.getAttribute("clipEnd");
112         } else {
113             return null;
114         }
115
116         return getAbsoluteUriPath(href, audio) +
117                 "#t=" +
118                 smilTimeToSeconds(clipBegin) +
119                 "," +
120                 smilTimeToSeconds(clipEnd);
121     }
122
123     /**
124      * function creates absolute URI path for the audio file.
125      * in ref => https://github.com/readium/readium-2/issues/38.
126      * <p>
127      * TODO check with other Epub file. specifically with deep hierarchy
128      *
129      * @param href  path of SMIL file.
130      * @param audio audio path in SMIL file to update.
131      * @return absolute URI path.
132      */
133     private static String getAbsoluteUriPath(String href, String audio) {
134         StringBuilder toAppend = new StringBuilder();
135         if (href.contains("/")) {
136             // removes file name from path
137             int startIndex = href.lastIndexOf("/");
138             String filePath = href.substring(0, startIndex);
139
140             int count = countSubString(audio, "../");
141             String[] items = filePath.split("/");
142
143             for (int i = 0; i < count; i++) {
144                 if (items.length > i) {
145                     if ((items.length - i - 2) >= 0) {
146                         toAppend.insert(0, items[items.length - i - 2] + "/");
147                     }
148                 }
149             }
150         }
151         if (audio.contains("../")) {
152             audio = audio.replace("../", "");
153         }
154         return toAppend.toString() + audio;
155     }
156
157     /**
158      * Return the seconds double value from a possible SS.MS format.
159      *
160      * @param time The seconds String.
161      * @return The translated Double value.
162      */
163     private static double parseSeconds(String time) {
164         String[] sec = time.split(":");
165         double seconds;
166         if (sec.length == 2) {
167             seconds = Double.parseDouble(sec[0]);
168             seconds += (Double.parseDouble(sec[1])) / 1000.0;
169         } else {
170             seconds = Double.parseDouble(time);
171         }
172         return seconds;
173     }
174
175     /**
176      * Returns number of occurrences of string b in string a.
177      *
178      * @param a string in which to find occurrences.
179      * @param b input substring
180      * @return count
181      */
182     private static int countSubString(String a, String b) {
183         int lastIndex = 0;
184         int count = 0;
185         while (lastIndex != -1) {
186
187             lastIndex = a.indexOf(b, lastIndex);
188
189             if (lastIndex != -1) {
190                 count++;
191                 lastIndex += b.length();
192             }
193         }
194         return count;
195     }
196 }