1 /* //device/apps/Calendar/MonthView.java 2 ** 3 ** Copyright 2006, The Android Open Source Project 4 ** 5 ** Licensed under the Apache License, Version 2.0 (the "License"); 6 ** you may not use this file except in compliance with the License. 7 ** You may obtain a copy of the License at 8 ** 9 ** http://www.apache.org/licenses/LICENSE-2.0 10 ** 11 ** Unless required by applicable law or agreed to in writing, software 12 ** distributed under the License is distributed on an "AS IS" BASIS, 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 ** See the License for the specific language governing permissions and 15 ** limitations under the License. 16 */ 17 18 package com.android.providers.calendar; 19 20 import android.pim.DateException; 21 import android.text.format.DateUtils; 22 import android.util.Log; 23 24 import java.util.ArrayList; 25 import java.util.Calendar; 26 import java.util.GregorianCalendar; 27 import java.util.TimeZone; 28 import java.util.regex.Pattern; 29 30 public class VCal 31 { 32 public static final Pattern LINE = Pattern.compile( 33 "([^:;]+)([^:]*):(.*)"); 34 35 public ArrayList<Property> properties = new ArrayList<Property>(); 36 public String dtstart; 37 public String tzid; 38 public String duration; 39 public String rrule; 40 public boolean allDay; 41 dump()42 public void dump() 43 { 44 System.out.println("-----------------------"); 45 dump(properties, ""); 46 System.out.println("dtstart='" + this.dtstart + "'"); 47 System.out.println("tzid='" + this.tzid + "'"); 48 System.out.println("duration='" + this.duration + "'"); 49 System.out.println("rrule='" + this.rrule + "'"); 50 System.out.println("-----------------------"); 51 } 52 dump(ArrayList<Property> props, String prefix)53 public static void dump(ArrayList<Property> props, String prefix) 54 { 55 int count = props.size(); 56 for (int i=0; i<count; i++) { 57 Property prop = props.get(i); 58 System.out.println(prefix + prop.name); 59 if (prop instanceof Begin) { 60 Begin b = (Begin)prop; 61 dump(b.properties, prefix + " "); 62 } 63 } 64 } 65 66 public static class Parameter 67 { 68 public String name; 69 public String value; 70 } 71 72 public static class Property 73 { 74 public String name; 75 public Parameter[] parameters; 76 public String value; 77 public String[] values; 78 } 79 80 public static class Begin extends Property 81 { 82 public Begin parent; 83 public ArrayList<Property> properties = new ArrayList<Property>(); 84 } 85 86 make(String name)87 public static Property make(String name) 88 { 89 Property p; 90 if (name.equals("BEGIN")) { 91 p = new Begin(); 92 } 93 else { 94 p = new Property(); 95 } 96 p.name = name; 97 return p; 98 } 99 parse(String str)100 public static VCal parse(String str) 101 { 102 VCal vc = new VCal(); 103 104 int i, j, start; 105 int N, M; 106 107 // first we deal with line folding, by replacing all "\r\n " strings 108 // with nothing 109 str = str.replaceAll("\r\n ", ""); 110 111 // it's supposed to be \r\n, but not everyone does that 112 str = str.replaceAll("\r\n", "\n"); 113 str = str.replaceAll("\r", "\n"); 114 115 ArrayList<Parameter> params = new ArrayList<Parameter>(); 116 ArrayList<Property> props = vc.properties; 117 118 // then we split into lines 119 String[] lines = str.split("\n"); 120 121 Begin begin = null; 122 //System.out.println("lines.length=" + lines); 123 N = lines.length; 124 for (j=0; j<N; j++) { 125 //System.out.println("===[" + lines[j] + "]==="); 126 String line = lines[j]; 127 int len = line.length(); 128 if (len > 0) { 129 i = 0; 130 char c; 131 do { 132 c = line.charAt(i); 133 i++; 134 } while (c != ';' && c != ':'); 135 136 String n = line.substring(0, i-1); 137 Property prop = make(n); 138 props.add(prop); 139 if (n.equals("BEGIN")) { 140 Begin b = (Begin)prop; 141 b.parent = begin; 142 begin = b; 143 props = begin.properties; 144 } 145 else if (n.equals("END")) { 146 begin = begin.parent; 147 if (begin != null) { 148 props = begin.properties; 149 } else { 150 props = vc.properties; 151 } 152 } 153 154 //System.out.println("name=[" + prop.name + "]"); 155 params.clear(); 156 while (c == ';') { 157 Parameter param = new Parameter(); 158 start = i; 159 i++; 160 // param name 161 do { 162 c = line.charAt(i); 163 i++; 164 } while (c != '='); 165 param.name = line.substring(start, i-1); 166 //System.out.println(" param.name=[" + param.name + "]"); 167 start = i; 168 if (line.charAt(start) == '"') { 169 i++; 170 start++; 171 do { 172 c = line.charAt(i); 173 i++; 174 } while (c != '"'); 175 param.value = line.substring(start, i-1); 176 c = line.charAt(i); 177 i++; 178 //System.out.println(" param.valueA=[" + param.value 179 // + "]"); 180 } else { 181 do { 182 c = line.charAt(i); 183 i++; 184 } while (c != ';' && c != ':'); 185 param.value = line.substring(start, i-1); 186 //System.out.println(" param.valueB=[" 187 // + param.value + "]"); 188 } 189 params.add(param); 190 } 191 Object[] array = params.toArray(); 192 prop.parameters = new Parameter[array.length]; 193 System.arraycopy(array, 0, prop.parameters, 0, array.length); 194 if (c != ':') { 195 throw new RuntimeException("error finding ':' c=" + c); 196 } 197 prop.value = line.substring(i); 198 prop.values = line.split(","); 199 } 200 } 201 202 N = vc.properties.size(); 203 Calendar calStart = null; 204 for (i=0; i<N; i++) { 205 Property prop = vc.properties.get(i); 206 String n = prop.name; 207 if (n.equals("DTSTART")) { 208 try { 209 calStart = parseDateTime(prop, vc); 210 vc.dtstart = prop.value; 211 } catch (DateException de) { 212 Log.w("CalendarProvider", "Unable to parse DTSTART=" + n, de); 213 return null; 214 } 215 } else if (n.equals("DTEND")) { 216 // TODO: store the dtend, compute when expanding instances? 217 // will we ever need to deal with seeing the DTEND before the 218 // DTSTART? 219 try { 220 if (calStart == null) { 221 vc.duration = "+P0S"; 222 } else { 223 Calendar calEnd = 224 parseDateTime(prop, vc); 225 long durationMillis = 226 calEnd.getTimeInMillis() - 227 calStart.getTimeInMillis(); 228 long durationSeconds = (durationMillis / 1000); 229 vc.duration = "+P" + durationSeconds + "S"; 230 } 231 } catch (DateException de) { 232 Log.w("CalendarProvider", "Unable to parse DTEND=" + n, de); 233 return null; 234 } 235 } else if (n.equals("DURATION")) { 236 vc.duration = prop.value; 237 } else if (n.equals("RRULE")) { 238 vc.rrule = prop.value; 239 } 240 } 241 return vc; 242 } 243 parseDateTime(Property prop, VCal vc)244 private static Calendar parseDateTime(Property prop, VCal vc) throws DateException { 245 int M; 246 int j; 247 String dt = prop.value; 248 M = prop.parameters.length; 249 for (j=0; j<M; j++) { 250 Parameter param = prop.parameters[j]; 251 if (param.name.equals("TZID")) { 252 vc.tzid = param.value; 253 } 254 } 255 256 TimeZone tz = TimeZone.getTimeZone(vc.tzid); 257 if (tz == null) { 258 tz = TimeZone.getTimeZone("UTC"); 259 } 260 GregorianCalendar somewhere = new GregorianCalendar(tz); 261 DateUtils.parseDateTime(dt, somewhere); 262 if (dt.length() == 8) { 263 // this seems to work. 264 vc.allDay = true; 265 } 266 return somewhere; 267 /*GregorianCalendar zulu = new GregorianCalendar( 268 TimeZone.getTimeZone("GMT")); 269 zulu.setTimeInMillis(somewhere.getTimeInMillis()); 270 return zulu;*/ 271 // System.out.println("DTSTART=" + dtstart 272 // + " somewhere=" + somewhere 273 // + " vc.dtstart=" + vc.dtstart); 274 } 275 } 276