1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.cooliris.picasa; 18 19 import org.xml.sax.Attributes; 20 import org.xml.sax.ContentHandler; 21 import org.xml.sax.Locator; 22 import org.xml.sax.SAXException; 23 import org.xml.sax.helpers.AttributesImpl; 24 25 import android.text.format.Time; 26 27 public final class GDataParser implements ContentHandler { 28 public static final String APP_NAMESPACE = "http://www.w3.org/2007/app"; 29 public static final String ATOM_NAMESPACE = "http://www.w3.org/2005/Atom"; 30 public static final String GD_NAMESPACE = "http://schemas.google.com/g/2005"; 31 public static final String GPHOTO_NAMESPACE = "http://schemas.google.com/photos/2007"; 32 public static final String MEDIA_RSS_NAMESPACE = "http://search.yahoo.com/mrss/"; 33 public static final String GML_NAMESPACE = "http://www.opengis.net/gml"; 34 private static final String FEED_ELEMENT = "feed"; 35 private static final String ENTRY_ELEMENT = "entry"; 36 37 private static final int STATE_DOCUMENT = 0; 38 private static final int STATE_FEED = 1; 39 private static final int STATE_ENTRY = 2; 40 41 private static final int NUM_LEVELS = 5; 42 43 private Entry mEntry = null; 44 private EntryHandler mHandler = null; 45 private int mState = STATE_DOCUMENT; 46 private int mLevel = 0; 47 private String[] mUri = new String[NUM_LEVELS]; 48 private String[] mName = new String[NUM_LEVELS]; 49 private AttributesImpl[] mAttributes = new AttributesImpl[NUM_LEVELS]; 50 private final StringBuilder mValue = new StringBuilder(128); 51 52 public interface EntryHandler { 53 void handleEntry(Entry entry); 54 } 55 56 public GDataParser() { 57 AttributesImpl[] attributes = mAttributes; 58 for (int i = 0; i != NUM_LEVELS; ++i) { 59 attributes[i] = new AttributesImpl(); 60 } 61 } 62 63 public void setEntry(Entry entry) { 64 mEntry = entry; 65 } 66 67 public void setHandler(EntryHandler handler) { 68 mHandler = handler; 69 } 70 71 public static long parseAtomTimestamp(String timestamp) { 72 Time time = new Time(); 73 time.parse3339(timestamp); 74 return time.toMillis(true); 75 } 76 77 public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException { 78 switch (mState) { 79 case STATE_DOCUMENT: 80 // Expect an atom:feed element. 81 if (uri.equals(ATOM_NAMESPACE) && localName.equals(FEED_ELEMENT)) { 82 mState = STATE_FEED; 83 } else { 84 throw new SAXException(); 85 } 86 break; 87 case STATE_FEED: 88 // Expect a feed property element or an atom:entry element. 89 if (uri.equals(ATOM_NAMESPACE) && localName.equals(ENTRY_ELEMENT)) { 90 mState = STATE_ENTRY; 91 mEntry.clear(); 92 } else { 93 startProperty(uri, localName, attrs); 94 } 95 break; 96 case STATE_ENTRY: 97 startProperty(uri, localName, attrs); 98 break; 99 } 100 } 101 102 public void endElement(String uri, String localName, String qName) throws SAXException { 103 if (mLevel > 0) { 104 // Handle property exit. 105 endProperty(); 106 } else { 107 // Handle state exit. 108 switch (mState) { 109 case STATE_DOCUMENT: 110 throw new SAXException(); 111 case STATE_FEED: 112 mState = STATE_DOCUMENT; 113 break; 114 case STATE_ENTRY: 115 mState = STATE_FEED; 116 mHandler.handleEntry(mEntry); 117 break; 118 } 119 } 120 } 121 122 private void startProperty(String uri, String localName, Attributes attrs) { 123 // Push element information onto the property stack. 124 int level = mLevel + 1; 125 mLevel = level; 126 mValue.setLength(0); 127 mUri[level] = uri; 128 mName[level] = localName; 129 mAttributes[level].setAttributes(attrs); 130 } 131 132 private void endProperty() { 133 // Apply property to the entry, then pop the stack. 134 int level = mLevel; 135 mEntry.setPropertyFromXml(mUri[level], mName[level], mAttributes[level], mValue.toString()); 136 mLevel = level - 1; 137 } 138 139 public void characters(char[] ch, int start, int length) throws SAXException { 140 mValue.append(ch, start, length); 141 } 142 143 public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { 144 // Ignored. 145 } 146 147 public void processingInstruction(String target, String data) throws SAXException { 148 // Ignored. 149 } 150 151 public void setDocumentLocator(Locator locator) { 152 // Ignored. 153 } 154 155 public void skippedEntity(String name) throws SAXException { 156 // Ignored. 157 } 158 159 public void startDocument() throws SAXException { 160 // Ignored. 161 } 162 163 public void endDocument() throws SAXException { 164 // Ignored. 165 } 166 167 public void startPrefixMapping(String prefix, String uri) throws SAXException { 168 // Ignored. 169 } 170 171 public void endPrefixMapping(String prefix) throws SAXException { 172 // Ignored. 173 } 174 } 175