1 // 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html#License 3 /* 4 ****************************************************************************** 5 * Copyright (C) 2007-2010, International Business Machines Corporation and * 6 * others. All Rights Reserved. * 7 ****************************************************************************** 8 */ 9 10 package com.ibm.icu.impl.duration.impl; 11 12 import java.io.IOException; 13 import java.io.Reader; 14 import java.util.ArrayList; 15 import java.util.List; 16 17 import com.ibm.icu.lang.UCharacter; 18 19 public class XMLRecordReader implements RecordReader { 20 private Reader r; 21 22 private List<String> nameStack; 23 24 private boolean atTag; 25 26 private String tag; // cache 27 28 public XMLRecordReader(Reader r) { 29 this.r = r; 30 this.nameStack = new ArrayList<String>(); 31 32 // skip XML prologue 33 if (getTag().startsWith("?xml")) { 34 advance(); 35 } 36 37 // skip FIRST comment 38 if (getTag().startsWith("!--")) { 39 advance(); 40 } 41 } 42 43 @Override 44 public boolean open(String title) { 45 if (getTag().equals(title)) { 46 nameStack.add(title); 47 advance(); 48 return true; 49 } 50 return false; 51 } 52 53 @Override 54 public boolean close() { 55 int ix = nameStack.size() - 1; 56 String name = nameStack.get(ix); 57 if (getTag().equals("/" + name)) { 58 nameStack.remove(ix); 59 advance(); 60 return true; 61 } 62 return false; 63 } 64 65 @Override 66 public boolean bool(String name) { 67 String s = string(name); 68 if (s != null) { 69 return "true".equals(s); 70 } 71 return false; 72 } 73 74 @Override 75 public boolean[] boolArray(String name) { 76 String[] sa = stringArray(name); 77 if (sa != null) { 78 boolean[] result = new boolean[sa.length]; 79 for (int i = 0; i < sa.length; ++i) { 80 result[i] = "true".equals(sa[i]); 81 } 82 return result; 83 } 84 return null; 85 } 86 87 @Override 88 public char character(String name) { 89 String s = string(name); 90 if (s != null) { 91 return s.charAt(0); 92 } 93 return '\uffff'; 94 } 95 96 @Override 97 public char[] characterArray(String name) { 98 String[] sa = stringArray(name); 99 if (sa != null) { 100 char[] result = new char[sa.length]; 101 for (int i = 0; i < sa.length; ++i) { 102 result[i] = sa[i].charAt(0); 103 } 104 return result; 105 } 106 return null; 107 } 108 109 @Override 110 public byte namedIndex(String name, String[] names) { 111 String sa = string(name); 112 if (sa != null) { 113 for (int i = 0; i < names.length; ++i) { 114 if (sa.equals(names[i])) { 115 return (byte) i; 116 } 117 } 118 } 119 return (byte) -1; 120 } 121 122 @Override 123 public byte[] namedIndexArray(String name, String[] names) { 124 String[] sa = stringArray(name); 125 if (sa != null) { 126 byte[] result = new byte[sa.length]; 127 loop: for (int i = 0; i < sa.length; ++i) { 128 String s = sa[i]; 129 for (int j = 0; j < names.length; ++j) { 130 if (names[j].equals(s)) { 131 result[i] = (byte) j; 132 continue loop; 133 } 134 } 135 result[i] = (byte) -1; 136 } 137 return result; 138 } 139 return null; 140 } 141 142 @Override 143 public String string(String name) { 144 if (match(name)) { 145 String result = readData(); 146 if (match("/" + name)) { 147 return result; 148 } 149 } 150 return null; 151 } 152 153 @Override 154 public String[] stringArray(String name) { 155 if (match(name + "List")) { 156 List<String> list = new ArrayList<String>(); 157 String s; 158 while (null != (s = string(name))) { 159 if ("Null".equals(s)) { 160 s = null; 161 } 162 list.add(s); 163 } 164 if (match("/" + name + "List")) { 165 return list.toArray(new String[list.size()]); 166 } 167 } 168 return null; 169 } 170 171 @Override 172 public String[][] stringTable(String name) { 173 if (match(name + "Table")) { 174 List<String[]> list = new ArrayList<String[]>(); 175 String[] sa; 176 while (null != (sa = stringArray(name))) { 177 list.add(sa); 178 } 179 if (match("/" + name + "Table")) { 180 return list.toArray(new String[list.size()][]); 181 } 182 } 183 return null; 184 } 185 186 private boolean match(String target) { 187 if (getTag().equals(target)) { 188 // System.out.println("match '" + target + "'"); 189 advance(); 190 return true; 191 } 192 return false; 193 } 194 195 private String getTag() { 196 if (tag == null) { 197 tag = readNextTag(); 198 } 199 return tag; 200 } 201 202 private void advance() { 203 tag = null; 204 } 205 206 private String readData() { 207 StringBuilder sb = new StringBuilder(); 208 boolean inWhitespace = false; 209 // boolean inAmp = false; 210 while (true) { 211 int c = readChar(); 212 if (c == -1 || c == '<') { 213 atTag = c == '<'; 214 break; 215 } 216 if (c == '&') { 217 c = readChar(); 218 if (c == '#') { 219 StringBuilder numBuf = new StringBuilder(); 220 int radix = 10; 221 c = readChar(); 222 if (c == 'x') { 223 radix = 16; 224 c = readChar(); 225 } 226 while (c != ';' && c != -1) { 227 numBuf.append((char) c); 228 c = readChar(); 229 } 230 try { 231 int num = Integer.parseInt(numBuf.toString(), radix); 232 c = (char) num; 233 } catch (NumberFormatException ex) { 234 System.err.println("numbuf: " + numBuf.toString() 235 + " radix: " + radix); 236 throw ex; 237 } 238 } else { 239 StringBuilder charBuf = new StringBuilder(); 240 while (c != ';' && c != -1) { 241 charBuf.append((char) c); 242 c = readChar(); 243 } 244 String charName = charBuf.toString(); 245 if (charName.equals("lt")) { 246 c = '<'; 247 } else if (charName.equals("gt")) { 248 c = '>'; 249 } else if (charName.equals("quot")) { 250 c = '"'; 251 } else if (charName.equals("apos")) { 252 c = '\''; 253 } else if (charName.equals("amp")) { 254 c = '&'; 255 } else { 256 System.err.println("unrecognized character entity: '" 257 + charName + "'"); 258 continue; 259 } 260 } 261 } 262 263 if (UCharacter.isWhitespace(c)) { 264 if (inWhitespace) { 265 continue; 266 } 267 c = ' '; 268 inWhitespace = true; 269 } else { 270 inWhitespace = false; 271 } 272 sb.append((char) c); 273 } 274 //System.err.println("read data: '" + sb.toString() + "'"); 275 return sb.toString(); 276 } 277 278 private String readNextTag() { 279 int c = '\0'; 280 while (!atTag) { 281 c = readChar(); 282 if (c == '<' || c == -1) { 283 if (c == '<') { 284 atTag = true; 285 } 286 break; 287 } 288 if (!UCharacter.isWhitespace(c)) { 289 System.err.println("Unexpected non-whitespace character " 290 + Integer.toHexString(c)); 291 break; 292 } 293 } 294 295 if (atTag) { 296 atTag = false; 297 StringBuilder sb = new StringBuilder(); 298 while (true) { 299 c = readChar(); 300 if (c == '>' || c == -1) { 301 break; 302 } 303 sb.append((char) c); 304 } 305 // System.err.println("read tag: '" + sb.toString() + "'"); 306 return sb.toString(); 307 } 308 return null; 309 } 310 311 int readChar() { 312 try { 313 return r.read(); 314 } catch (IOException e) { 315 // assume end of input 316 } 317 return -1; 318 } 319 } 320