/******************************************************************************* * Copyright 2009 Robot Media SL * * 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 net.robotmedia.acv.comic; import java.io.IOException; import java.util.regex.Matcher; import java.util.regex.Pattern; import net.robotmedia.acv.comic.ACVComic.Message; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import android.content.res.Configuration; public class ACVParser { private static final String ATTRIBUTE_AUTOPLAY = "autoplay"; private static final String ATTRIBUTE_BGCOLOR = "bgcolor"; private static final String ATTRIBUTE_DIRECTION = "direction"; private static final String ATTRIBUTE_DURATION = "duration"; private static final String ATTRIBUTE_ID = "id"; private static final String ATTRIBUTE_INDEX = "index"; private static final String ATTRIBUTE_IMAGE_NAME_PATTERN = "imageNamePattern"; private static final String ATTRIBUTE_THUMBNAIL_NAME_PATTERN = "thumbnailNamePattern"; private static final String ATTRIBUTE_ORIGINAL_NAME_PATTERN = "originalNamePattern"; private static final String ATTRIBUTE_LENGTH = "length"; private static final String ATTRIBUTE_MIN_VIEWER_VERSION = "minViewerVersion"; private static final String ATTRIBUTE_ORIENTATION = "orientation"; private static final String ATTRIBUTE_PAID = "paid"; private static final String ATTRIBUTE_RELATIVE_AREA = "relativeArea"; private static final String ATTRIBUTE_SCALE_MODE = "scaleMode"; private static final String ATTRIBUTE_SOUND = "sound"; private static final String ATTRIBUTE_SOURCE = "src"; private static final String ATTRIBUTE_STARTS_AT = "startAt"; private static final String ATTRIBUTE_TITLE = "title"; private static final String ATTRIBUTE_TRANSITION = "transition"; private static final String ATTRIBUTE_TRANSITION_DURATION = "transitionDuration"; private static final String ATTRIBUTE_URI = "uri"; private static final String ATTRIBUTE_VALUE = "value"; private static final String ATTRIBUTE_VERSION = "version"; private static final String ATTRIBUTE_VIBRATE = "vibrate"; @Deprecated private static final String ELEMENT_COMIC = "comic"; private static final String ELEMENT_ACV = "acv"; private static final String ELEMENT_CONTENT = "content"; private static final String ELEMENT_DESCRIPTION = "description"; private static final String ELEMENT_FRAME = "frame"; @Deprecated private static final String ELEMENT_IMAGE = "image"; private static final String ELEMENT_IMAGES = "images"; private static final String ELEMENT_MESSAGE = "message"; private static final String ELEMENT_SCREEN = "screen"; private static final String ELEMENT_THUMBNAILS = "thumbnails"; @Deprecated private static final String VALUE_YES = "yes"; public static void parse(XmlPullParser xml, ACVComic comic) throws XmlPullParserException, IOException { int eventType = xml.getEventType(); boolean isParsingScreen = false; boolean isParsingFrame = false; boolean isParsingDescription = false; boolean isParsingContent = false; ACVScreen currentScreen = null; ACVFrame currentFrame = null; ACVContent currentContent = null; while (eventType != XmlPullParser.END_DOCUMENT) { if (eventType == XmlPullParser.START_TAG) { String elementName = xml.getName(); if (ELEMENT_COMIC.equals(elementName) || ELEMENT_ACV.equals(elementName)) { parseComic(xml, comic); } else if (ELEMENT_IMAGES.equals(elementName)) { parseImagePattern(xml, comic); } else if (ELEMENT_THUMBNAILS.equals(elementName)) { parseThumbnailPattern(xml, comic); } else if (ELEMENT_IMAGE.equals(elementName) || ELEMENT_SCREEN.equals(elementName)) { isParsingScreen = true; currentScreen = parseScreen(xml, comic); } else if (ELEMENT_MESSAGE.equals(elementName)) { Message message = ACVParser.parseMessage(xml); if (message != null) { ACVScreen screen = comic.getOrCreateACVScreen(message.index); screen.setMessage(message); } } else if (isParsingScreen && currentScreen != null && ELEMENT_FRAME.equals(elementName)) { isParsingFrame = true; currentFrame = parseFrame(xml, comic); currentScreen.addFrame(currentFrame); } else if (ELEMENT_DESCRIPTION.equalsIgnoreCase(elementName)) { isParsingDescription = true; final String description = xml.getText(); if (isParsingScreen) { currentScreen.setDescription(description); } else if (isParsingFrame) { currentFrame.setDescription(description); } else { // Comic description comic.setDescription(description); } } else if (ELEMENT_CONTENT.equalsIgnoreCase(elementName)) { isParsingContent = true; currentContent = parseContent(xml); } } else if (eventType == XmlPullParser.TEXT) { if (isParsingDescription) { final String description = xml.getText(); if (isParsingScreen) { currentScreen.setDescription(description); } } else if (isParsingContent) { currentContent.setContent(xml.getText()); } } else if (eventType == XmlPullParser.END_TAG) { String elementName = xml.getName(); if (ELEMENT_IMAGE.equals(elementName) || ELEMENT_SCREEN.equals(elementName)) { isParsingScreen = false; currentScreen = null; } else if (ELEMENT_FRAME.equalsIgnoreCase(elementName)) { isParsingFrame = false; currentFrame = null; } else if (ELEMENT_DESCRIPTION.equalsIgnoreCase(elementName)) { isParsingDescription = false; } else if (ELEMENT_CONTENT.equalsIgnoreCase(elementName)) { isParsingContent = false; if (isParsingFrame) { currentFrame.add(currentContent); } else if (isParsingScreen) { currentScreen.add(currentContent); } currentContent = null; } } eventType = xml.next(); } } private static ACVContent parseContent(XmlPullParser xml) { final ACVContent content = new ACVContent(); final String relativeAreaString = xml.getAttributeValue(null, ATTRIBUTE_RELATIVE_AREA); parseRelativeArea(relativeAreaString, content); final String source = xml.getAttributeValue(null, ATTRIBUTE_SOURCE); if (source != null) { content.setSource(source); } final String transitionDurationString = xml.getAttributeValue(null, ATTRIBUTE_TRANSITION_DURATION); if (transitionDurationString != null) { final long transitionDuration = (long) (Float.parseFloat(transitionDurationString) * 1000); content.setTransitionDuration(transitionDuration); } return content; } private static boolean parseBoolean(String value) { return VALUE_YES.equals(value.toLowerCase()) || Boolean.parseBoolean(value); } private static void parseComic(XmlPullParser xml, ACVComic comic) { final String bgcolorString = xml.getAttributeValue(null, ATTRIBUTE_BGCOLOR); if (bgcolorString != null) { comic.setBgcolorString(bgcolorString); } final String paidString = xml.getAttributeValue(null, ATTRIBUTE_PAID); if (paidString != null) { final boolean paid = parseBoolean(paidString); comic.setPaid(paid); } final String scaleMode = xml.getAttributeValue(null, ATTRIBUTE_SCALE_MODE); if (scaleMode != null) { comic.setScaleMode(scaleMode); } final String transition = xml.getAttributeValue(null, ATTRIBUTE_TRANSITION); if (transition != null) { comic.setTransition(transition); } final String specificationVersionString = xml.getAttributeValue(null, ATTRIBUTE_VERSION); if (specificationVersionString != null) { final int specificationVersion = Math.round(Float.parseFloat(specificationVersionString)); comic.setSpecificationVersion(specificationVersion); } final String minViewerVersionString = xml.getAttributeValue(null, ATTRIBUTE_MIN_VIEWER_VERSION); if (minViewerVersionString != null) { final int minViewerVersion = Integer.parseInt(minViewerVersionString); comic.setMinViewerVersion(minViewerVersion); } final String title = xml.getAttributeValue(null, ATTRIBUTE_TITLE); if (title != null) { comic.setTitle(title); } final String id = xml.getAttributeValue(null, ATTRIBUTE_ID); if (id != null) { comic.setId(id); } final String direction = xml.getAttributeValue(null, ATTRIBUTE_DIRECTION); if (direction != null) { comic.setDirection(direction); } final String orientationString = xml.getAttributeValue(null, ATTRIBUTE_ORIENTATION); if (orientationString != null) { final int orientation; if (ACVComic.VALUE_PORTRAIT.equalsIgnoreCase(orientationString)) { orientation = Configuration.ORIENTATION_PORTRAIT; } else if (ACVComic.VALUE_LANDSCAPE.equalsIgnoreCase(orientationString)) { orientation = Configuration.ORIENTATION_LANDSCAPE; } else { orientation = Integer.parseInt(orientationString); } comic.setOrientation(orientation); } final String lengthString = xml.getAttributeValue(null, ATTRIBUTE_LENGTH); if (lengthString != null) { final int length = Integer.parseInt(lengthString); comic.setLength(length); } { final String imageNamePattern = xml.getAttributeValue(null, ATTRIBUTE_IMAGE_NAME_PATTERN); if (imageNamePattern != null) { comic.setImageNamePattern(toRegex(imageNamePattern)); } } { final String thumbnailNamePattern = xml.getAttributeValue(null, ATTRIBUTE_THUMBNAIL_NAME_PATTERN); if (thumbnailNamePattern != null) { comic.setThumbnailNamePattern(toRegex(thumbnailNamePattern)); } } { final String originalNamePattern = xml.getAttributeValue(null, ATTRIBUTE_ORIGINAL_NAME_PATTERN); if (originalNamePattern != null) { comic.setOriginalNamePattern(toRegex(originalNamePattern)); } } } private static ACVFrame parseFrame(XmlPullParser xml, ACVComic comic) { ACVFrame frame = new ACVFrame(); String relativeAreaString = xml.getAttributeValue(null, ATTRIBUTE_RELATIVE_AREA); parseRelativeArea(relativeAreaString, frame); String autoplayString = xml.getAttributeValue(null, ATTRIBUTE_AUTOPLAY); if (autoplayString != null) { final boolean autoplay = parseBoolean(autoplayString); frame.setAutoplay(autoplay); } String transition = xml.getAttributeValue(null, ATTRIBUTE_TRANSITION); if (transition != null) { frame.setTransition(transition); } String transitionDurationString = xml.getAttributeValue(null, ACVParser.ATTRIBUTE_TRANSITION_DURATION); if (transitionDurationString != null) { final float transitionDuration = Float.parseFloat(transitionDurationString); frame.setTransitionDuration(transitionDuration); } String durationString = xml.getAttributeValue(null, ATTRIBUTE_DURATION); if (durationString != null) { final float duration = Float.parseFloat(durationString); frame.setDuration(duration); } String vibrateString = xml.getAttributeValue(null, ATTRIBUTE_VIBRATE); if (vibrateString != null) { final boolean vibrate = parseBoolean(vibrateString); frame.setVibrate(vibrate); } final String bgcolorString = xml.getAttributeValue(null, ATTRIBUTE_BGCOLOR); if (bgcolorString != null) { frame.setBgcolorString(bgcolorString); } final String sound = xml.getAttributeValue(null, ATTRIBUTE_SOUND); if (sound != null) { frame.setSound(sound); comic.registerSound(sound); } return frame; } private static void parseImagePattern(XmlPullParser xml, ACVComic comic) { final String lengthString = xml.getAttributeValue(null, ATTRIBUTE_LENGTH); if (lengthString != null) { final int length = Integer.parseInt(lengthString); comic.setLength(length); } final String startsAtString = xml.getAttributeValue(null, ATTRIBUTE_STARTS_AT); if (startsAtString != null) { final int starstAt = Integer.parseInt(startsAtString); comic.setImageStartsAt(starstAt); } } private static Message parseMessage(XmlPullParser xml) { String aux = xml.getAttributeValue(null, ATTRIBUTE_INDEX); if (aux != null) { int index = Integer.parseInt(aux); Message message = new Message(); message.index = index; message.text = xml.getAttributeValue(null, ATTRIBUTE_VALUE); message.uri = xml.getAttributeValue(null, ATTRIBUTE_URI); message.nonMarketUri = xml.getAttributeValue(null, "nonMarketUri"); return message; } return null; } private static void parseRelativeArea(String relativeAreaString, ACVRectangle r) { if (relativeAreaString != null) { final String[] relativeAreaArray = relativeAreaString.split(" "); if (relativeAreaArray.length == 4) { final float relativeX = Float.parseFloat(relativeAreaArray[0]); final float relativeY = Float.parseFloat(relativeAreaArray[1]); final float relativeWidth = Float.parseFloat(relativeAreaArray[2]); final float relativeHeight = Float.parseFloat(relativeAreaArray[3]); r.setArea(relativeX, relativeY, relativeWidth, relativeHeight); } } } private static ACVScreen parseScreen(XmlPullParser xml, ACVComic comic) { int index = -1; String aux = xml.getAttributeValue(null, ATTRIBUTE_INDEX); if (aux != null) index = Integer.parseInt(aux); if (index >= 0) { ACVScreen screen = comic.getOrCreateACVScreen(index); final String autoplayString = xml.getAttributeValue(null, ATTRIBUTE_AUTOPLAY); if (autoplayString != null) { final boolean autoplay = parseBoolean(autoplayString); screen.setAutoplay(autoplay); } final String transition = xml.getAttributeValue(null, ATTRIBUTE_TRANSITION); if (transition != null) { screen.setTransition(transition); } final String bgcolorString = xml.getAttributeValue(null, ATTRIBUTE_BGCOLOR); if (bgcolorString != null) { screen.setBgcolorString(bgcolorString); } final String vibrateString = xml.getAttributeValue(null, ATTRIBUTE_VIBRATE); if (vibrateString != null) { final boolean vibrate = parseBoolean(vibrateString); screen.setVibrate(vibrate); } final String transitionDurationString = xml .getAttributeValue(null, ACVParser.ATTRIBUTE_TRANSITION_DURATION); if (transitionDurationString != null) { final float transitionDuration = Float.parseFloat(transitionDurationString); screen.setTransitionDuration(transitionDuration); } final String durationString = xml.getAttributeValue(null, ATTRIBUTE_DURATION); if (durationString != null) { final float duration = Float.parseFloat(durationString); screen.setDuration(duration); } final String title = xml.getAttributeValue(null, ATTRIBUTE_TITLE); if (title != null) { screen.setTitle(title); } final String sound = xml.getAttributeValue(null, ATTRIBUTE_SOUND); if (sound != null) { screen.setSound(sound); comic.registerSound(sound); } return screen; } return null; } private static void parseThumbnailPattern(XmlPullParser xml, ACVComic comic) { final String startsAtString = xml.getAttributeValue(null, ATTRIBUTE_STARTS_AT); if (startsAtString != null) { final int startsAt = Integer.parseInt(startsAtString); comic.setThumbnailStartsAt(startsAt); } } /** * Converts a format string with a single decimal integer parameter (with zero-padding) into the corresponding regex. * @param format format string with a single decimal integer parameter (with zero-padding) * @return the corresponding regex */ private static String toRegex(String format) { final Pattern indexPattern = Pattern.compile("(.*)%0(\\d)d(.*)"); final Matcher m = indexPattern.matcher(format); if (m.find()) { StringBuffer regexBuffer = new StringBuffer(m.group(1)); final String digits = m.group(2); regexBuffer.append("\\d{").append(digits).append(",}+"); regexBuffer.append(m.group(3)); return regexBuffer.toString(); } return format; } }