129 /** 130 * The element corresponding to p. 131 */ 132 public final Element p = getElement("p"); 133 134 /** 135 * The element corresponding to title. 136 */ 137 public final Element title = getElement("title"); 138 final Element style = getElement("style"); 139 final Element link = getElement("link"); 140 final Element script = getElement("script"); 141 142 /** 143 * The version of a file 144 */ 145 public static final int FILE_VERSION = 1; 146 147 /** 148 * Creates a new DTD with the specified name. 149 * @param name the name, as a <code>String</code> of the new DTD 150 */ 151 protected DTD(String name) { 152 this.name = name; 153 defEntity("#RE", GENERAL, '\r'); 154 defEntity("#RS", GENERAL, '\n'); 155 defEntity("#SPACE", GENERAL, ' '); 156 defineElement("unknown", EMPTY, false, true, null, null, null, null); 157 } 158 159 /** 160 * Gets the name of the DTD. 161 * @return the name of the DTD 162 */ 163 public String getName() { 164 return name; 165 } 166 167 /** 168 * Gets an entity by name. 169 * @param name the entity name 170 * @return the <code>Entity</code> corresponding to the 171 * <code>name</code> <code>String</code> 172 */ 173 public Entity getEntity(String name) { 174 return entityHash.get(name); 175 } 176 177 /** 178 * Gets a character entity. 179 * @param ch the character 180 * @return the <code>Entity</code> corresponding to the 181 * <code>ch</code> character 182 */ 183 public Entity getEntity(int ch) { 184 return entityHash.get(Integer.valueOf(ch)); 185 } 186 187 /** 188 * Returns <code>true</code> if the element is part of the DTD, 189 * otherwise returns <code>false</code>. 190 * 191 * @param name the requested <code>String</code> 192 * @return <code>true</code> if <code>name</code> exists as 193 * part of the DTD, otherwise returns <code>false</code> 194 */ 195 boolean elementExists(String name) { 196 return !"unknown".equals(name) && (elementHash.get(name) != null); 197 } 198 199 /** 200 * Gets an element by name. A new element is 201 * created if the element doesn't exist. 202 * 203 * @param name the requested <code>String</code> 204 * @return the <code>Element</code> corresponding to 205 * <code>name</code>, which may be newly created 206 */ 207 public Element getElement(String name) { 208 Element e = elementHash.get(name); 209 if (e == null) { 210 e = new Element(name, elements.size()); 211 elements.addElement(e); 212 elementHash.put(name, e); 213 } 214 return e; 215 } 216 217 /** 218 * Gets an element by index. 219 * 220 * @param index the requested index 221 * @return the <code>Element</code> corresponding to 222 * <code>index</code> 223 */ 224 public Element getElement(int index) { 225 return elements.elementAt(index); 226 } 227 228 /** 229 * Defines an entity. If the <code>Entity</code> specified 230 * by <code>name</code>, <code>type</code>, and <code>data</code> 231 * exists, it is returned; otherwise a new <code>Entity</code> 232 * is created and is returned. 233 * 234 * @param name the name of the <code>Entity</code> as a <code>String</code> 235 * @param type the type of the <code>Entity</code> 236 * @param data the <code>Entity</code>'s data 237 * @return the <code>Entity</code> requested or a new <code>Entity</code> 238 * if not found 239 */ 240 public Entity defineEntity(String name, int type, char data[]) { 241 Entity ent = entityHash.get(name); 242 if (ent == null) { 243 ent = new Entity(name, type, data); 244 entityHash.put(name, ent); 245 if (((type & GENERAL) != 0) && (data.length == 1)) { 246 switch (type & ~GENERAL) { 247 case CDATA: 248 case SDATA: 249 entityHash.put(Integer.valueOf(data[0]), ent); 250 break; 251 } 252 } 253 } 254 return ent; 255 } 256 257 /** 258 * Returns the <code>Element</code> which matches the 259 * specified parameters. If one doesn't exist, a new 260 * one is created and returned. 261 * 262 * @param name the name of the <code>Element</code> 263 * @param type the type of the <code>Element</code> 264 * @param omitStart <code>true</code> if start should be omitted 265 * @param omitEnd <code>true</code> if end should be omitted 266 * @param content the <code>ContentModel</code> 267 * @param exclusions the set of elements that must not occur inside the element 268 * @param inclusions the set of elements that can occur inside the element 269 * @param atts the <code>AttributeList</code> specifying the 270 * <code>Element</code> 271 * @return the <code>Element</code> specified 272 */ 273 public Element defineElement(String name, int type, 274 boolean omitStart, boolean omitEnd, ContentModel content, 275 BitSet exclusions, BitSet inclusions, AttributeList atts) { 276 Element e = getElement(name); 277 e.type = type; 278 e.oStart = omitStart; 279 e.oEnd = omitEnd; 280 e.content = content; 281 e.exclusions = exclusions; 282 e.inclusions = inclusions; 283 e.atts = atts; 284 return e; 285 } 286 287 /** 288 * Defines attributes for an {@code Element}. 289 * 290 * @param name the name of the <code>Element</code> 291 * @param atts the <code>AttributeList</code> specifying the 292 * <code>Element</code> 293 */ 294 public void defineAttributes(String name, AttributeList atts) { 295 Element e = getElement(name); 296 e.atts = atts; 297 } 298 299 /** 300 * Creates and returns a character <code>Entity</code>. 301 * @param name the entity's name 302 * @param type the entity's type 303 * @param ch the entity's value (character) 304 * @return the new character <code>Entity</code> 305 */ 306 public Entity defEntity(String name, int type, int ch) { 307 char data[] = {(char)ch}; 308 return defineEntity(name, type, data); 309 } 310 311 /** 312 * Creates and returns an <code>Entity</code>. 313 * @param name the entity's name 314 * @param type the entity's type 315 * @param str the entity's data section 316 * @return the new <code>Entity</code> 317 */ 318 protected Entity defEntity(String name, int type, String str) { 319 int len = str.length(); 320 char data[] = new char[len]; 321 str.getChars(0, len, data, 0); 322 return defineEntity(name, type, data); 323 } 324 325 /** 326 * Creates and returns an <code>Element</code>. 327 * @param name the element's name 328 * @param type the element's type 329 * @param omitStart {@code true} if the element needs no starting tag 330 * @param omitEnd {@code true} if the element needs no closing tag 331 * @param content the element's content 332 * @param exclusions the elements that must be excluded from the content of the element 333 * @param inclusions the elements that can be included as the content of the element 334 * @param atts the attributes of the element 335 * @return the new <code>Element</code> 336 */ 337 protected Element defElement(String name, int type, 338 boolean omitStart, boolean omitEnd, ContentModel content, 339 String[] exclusions, String[] inclusions, AttributeList atts) { 340 BitSet excl = null; 341 if (exclusions != null && exclusions.length > 0) { 342 excl = new BitSet(); 343 for (String str : exclusions) { 344 if (str.length() > 0) { 345 excl.set(getElement(str).getIndex()); 346 } 347 } 348 } 349 BitSet incl = null; 350 if (inclusions != null && inclusions.length > 0) { 351 incl = new BitSet(); 352 for (String str : inclusions) { 353 if (str.length() > 0) { 354 incl.set(getElement(str).getIndex()); 355 } 356 } 357 } 358 return defineElement(name, type, omitStart, omitEnd, content, excl, incl, atts); 359 } 360 361 /** 362 * Creates and returns an <code>AttributeList</code> responding to a new attribute. 363 * @param name the attribute's name 364 * @param type the attribute's type 365 * @param modifier the attribute's modifier 366 * @param value the default value of the attribute 367 * @param values the allowed values for the attribute (multiple values could be separated by '|') 368 * @param atts the previous attribute of the element; to be placed to {@code AttributeList.next}, 369 * creating a linked list 370 * @return the new <code>AttributeList</code> 371 */ 372 protected AttributeList defAttributeList(String name, int type, int modifier, 373 String value, String values, AttributeList atts) { 374 Vector<String> vals = null; 375 if (values != null) { 376 vals = new Vector<String>(); 377 for (StringTokenizer s = new StringTokenizer(values, "|") ; s.hasMoreTokens() ;) { 378 String str = s.nextToken(); 379 if (str.length() > 0) { 380 vals.addElement(str); 381 } 382 } 383 } 384 return new AttributeList(name, type, modifier, value, vals, atts); 385 } 386 387 /** 388 * Creates and returns a new content model. 389 * @param type the type of the new content model 390 * @param obj the content of the content model 391 * @param next pointer to the next content model 392 * @return the new <code>ContentModel</code> 393 */ 394 protected ContentModel defContentModel(int type, Object obj, ContentModel next) { 395 return new ContentModel(type, obj, next); 396 } 397 398 /** 399 * Returns a string representation of this DTD. 400 * @return the string representation of this DTD 401 */ 402 public String toString() { 403 return name; 404 } 405 406 /** 407 * The hashtable key of DTDs in AppContext. 408 */ 409 private static final Object DTD_HASH_KEY = new Object(); 410 411 /** 412 * Put a name and appropriate DTD to hashtable. 413 * 414 * @param name the name of the DTD 415 * @param dtd the DTD 416 */ 417 public static void putDTDHash(String name, DTD dtd) { 418 getDtdHash().put(name, dtd); 419 } 420 421 /** 422 * Returns a DTD with the specified <code>name</code>. If 423 * a DTD with that name doesn't exist, one is created 424 * and returned. Any uppercase characters in the name 425 * are converted to lowercase. 426 * 427 * @param name the name of the DTD 428 * @return the DTD which corresponds to <code>name</code> 429 * @throws IOException if an I/O error occurs 430 */ 431 public static DTD getDTD(String name) throws IOException { 432 name = name.toLowerCase(); 433 DTD dtd = getDtdHash().get(name); 434 if (dtd == null) 435 dtd = new DTD(name); 436 437 return dtd; 438 } 439 440 private static Hashtable<String, DTD> getDtdHash() { 441 AppContext appContext = AppContext.getAppContext(); 442 443 @SuppressWarnings("unchecked") 444 Hashtable<String, DTD> result = (Hashtable<String, DTD>) appContext.get(DTD_HASH_KEY); 445 446 if (result == null) { 447 result = new Hashtable<String, DTD>(); 448 449 appContext.put(DTD_HASH_KEY, result); 450 } 451 452 return result; 453 } 454 455 /** 456 * Recreates a DTD from an archived format. 457 * @param in the <code>DataInputStream</code> to read from 458 * @throws IOException if an I/O error occurs 459 */ 460 public void read(DataInputStream in) throws IOException { 461 if (in.readInt() != FILE_VERSION) { 462 } 463 464 // 465 // Read the list of names 466 // 467 String[] names = new String[in.readShort()]; 468 for (int i = 0; i < names.length; i++) { 469 names[i] = in.readUTF(); 470 } 471 472 473 // 474 // Read the entities 475 // 476 int num = in.readShort(); 477 for (int i = 0; i < num; i++) { | 129 /** 130 * The element corresponding to p. 131 */ 132 public final Element p = getElement("p"); 133 134 /** 135 * The element corresponding to title. 136 */ 137 public final Element title = getElement("title"); 138 final Element style = getElement("style"); 139 final Element link = getElement("link"); 140 final Element script = getElement("script"); 141 142 /** 143 * The version of a file 144 */ 145 public static final int FILE_VERSION = 1; 146 147 /** 148 * Creates a new DTD with the specified name. 149 * @param name the name, as a {@code String} of the new DTD 150 */ 151 protected DTD(String name) { 152 this.name = name; 153 defEntity("#RE", GENERAL, '\r'); 154 defEntity("#RS", GENERAL, '\n'); 155 defEntity("#SPACE", GENERAL, ' '); 156 defineElement("unknown", EMPTY, false, true, null, null, null, null); 157 } 158 159 /** 160 * Gets the name of the DTD. 161 * @return the name of the DTD 162 */ 163 public String getName() { 164 return name; 165 } 166 167 /** 168 * Gets an entity by name. 169 * @param name the entity name 170 * @return the {@code Entity} corresponding to the 171 * {@code name String} 172 */ 173 public Entity getEntity(String name) { 174 return entityHash.get(name); 175 } 176 177 /** 178 * Gets a character entity. 179 * @param ch the character 180 * @return the {@code Entity} corresponding to the 181 * {@code ch} character 182 */ 183 public Entity getEntity(int ch) { 184 return entityHash.get(Integer.valueOf(ch)); 185 } 186 187 /** 188 * Returns {@code true} if the element is part of the DTD, 189 * otherwise returns {@code false}. 190 * 191 * @param name the requested {@code String} 192 * @return {@code true} if {@code name} exists as 193 * part of the DTD, otherwise returns {@code false} 194 */ 195 boolean elementExists(String name) { 196 return !"unknown".equals(name) && (elementHash.get(name) != null); 197 } 198 199 /** 200 * Gets an element by name. A new element is 201 * created if the element doesn't exist. 202 * 203 * @param name the requested {@code String} 204 * @return the {@code Element} corresponding to 205 * {@code name}, which may be newly created 206 */ 207 public Element getElement(String name) { 208 Element e = elementHash.get(name); 209 if (e == null) { 210 e = new Element(name, elements.size()); 211 elements.addElement(e); 212 elementHash.put(name, e); 213 } 214 return e; 215 } 216 217 /** 218 * Gets an element by index. 219 * 220 * @param index the requested index 221 * @return the {@code Element} corresponding to 222 * {@code index} 223 */ 224 public Element getElement(int index) { 225 return elements.elementAt(index); 226 } 227 228 /** 229 * Defines an entity. If the {@code Entity} specified 230 * by {@code name}, {@code type}, and {@code data} 231 * exists, it is returned; otherwise a new {@code Entity} 232 * is created and is returned. 233 * 234 * @param name the name of the {@code Entity} as a {@code String} 235 * @param type the type of the {@code Entity} 236 * @param data the {@code Entity}'s data 237 * @return the {@code Entity} requested or a new {@code Entity} 238 * if not found 239 */ 240 public Entity defineEntity(String name, int type, char data[]) { 241 Entity ent = entityHash.get(name); 242 if (ent == null) { 243 ent = new Entity(name, type, data); 244 entityHash.put(name, ent); 245 if (((type & GENERAL) != 0) && (data.length == 1)) { 246 switch (type & ~GENERAL) { 247 case CDATA: 248 case SDATA: 249 entityHash.put(Integer.valueOf(data[0]), ent); 250 break; 251 } 252 } 253 } 254 return ent; 255 } 256 257 /** 258 * Returns the {@code Element} which matches the 259 * specified parameters. If one doesn't exist, a new 260 * one is created and returned. 261 * 262 * @param name the name of the {@code Element} 263 * @param type the type of the {@code Element} 264 * @param omitStart {@code true} if start should be omitted 265 * @param omitEnd {@code true} if end should be omitted 266 * @param content the {@code ContentModel} 267 * @param exclusions the set of elements that must not occur inside the element 268 * @param inclusions the set of elements that can occur inside the element 269 * @param atts the {@code AttributeList} specifying the 270 * {@code Element} 271 * @return the {@code Element} specified 272 */ 273 public Element defineElement(String name, int type, 274 boolean omitStart, boolean omitEnd, ContentModel content, 275 BitSet exclusions, BitSet inclusions, AttributeList atts) { 276 Element e = getElement(name); 277 e.type = type; 278 e.oStart = omitStart; 279 e.oEnd = omitEnd; 280 e.content = content; 281 e.exclusions = exclusions; 282 e.inclusions = inclusions; 283 e.atts = atts; 284 return e; 285 } 286 287 /** 288 * Defines attributes for an {@code Element}. 289 * 290 * @param name the name of the {@code Element} 291 * @param atts the {@code AttributeList} specifying the 292 * {@code Element} 293 */ 294 public void defineAttributes(String name, AttributeList atts) { 295 Element e = getElement(name); 296 e.atts = atts; 297 } 298 299 /** 300 * Creates and returns a character {@code Entity}. 301 * @param name the entity's name 302 * @param type the entity's type 303 * @param ch the entity's value (character) 304 * @return the new character {@code Entity} 305 */ 306 public Entity defEntity(String name, int type, int ch) { 307 char data[] = {(char)ch}; 308 return defineEntity(name, type, data); 309 } 310 311 /** 312 * Creates and returns an {@code Entity}. 313 * @param name the entity's name 314 * @param type the entity's type 315 * @param str the entity's data section 316 * @return the new {@code Entity} 317 */ 318 protected Entity defEntity(String name, int type, String str) { 319 int len = str.length(); 320 char data[] = new char[len]; 321 str.getChars(0, len, data, 0); 322 return defineEntity(name, type, data); 323 } 324 325 /** 326 * Creates and returns an {@code Element}. 327 * @param name the element's name 328 * @param type the element's type 329 * @param omitStart {@code true} if the element needs no starting tag 330 * @param omitEnd {@code true} if the element needs no closing tag 331 * @param content the element's content 332 * @param exclusions the elements that must be excluded from the content of the element 333 * @param inclusions the elements that can be included as the content of the element 334 * @param atts the attributes of the element 335 * @return the new {@code Element} 336 */ 337 protected Element defElement(String name, int type, 338 boolean omitStart, boolean omitEnd, ContentModel content, 339 String[] exclusions, String[] inclusions, AttributeList atts) { 340 BitSet excl = null; 341 if (exclusions != null && exclusions.length > 0) { 342 excl = new BitSet(); 343 for (String str : exclusions) { 344 if (str.length() > 0) { 345 excl.set(getElement(str).getIndex()); 346 } 347 } 348 } 349 BitSet incl = null; 350 if (inclusions != null && inclusions.length > 0) { 351 incl = new BitSet(); 352 for (String str : inclusions) { 353 if (str.length() > 0) { 354 incl.set(getElement(str).getIndex()); 355 } 356 } 357 } 358 return defineElement(name, type, omitStart, omitEnd, content, excl, incl, atts); 359 } 360 361 /** 362 * Creates and returns an {@code AttributeList} responding to a new attribute. 363 * @param name the attribute's name 364 * @param type the attribute's type 365 * @param modifier the attribute's modifier 366 * @param value the default value of the attribute 367 * @param values the allowed values for the attribute (multiple values could be separated by '|') 368 * @param atts the previous attribute of the element; to be placed to {@code AttributeList.next}, 369 * creating a linked list 370 * @return the new {@code AttributeList} 371 */ 372 protected AttributeList defAttributeList(String name, int type, int modifier, 373 String value, String values, AttributeList atts) { 374 Vector<String> vals = null; 375 if (values != null) { 376 vals = new Vector<String>(); 377 for (StringTokenizer s = new StringTokenizer(values, "|") ; s.hasMoreTokens() ;) { 378 String str = s.nextToken(); 379 if (str.length() > 0) { 380 vals.addElement(str); 381 } 382 } 383 } 384 return new AttributeList(name, type, modifier, value, vals, atts); 385 } 386 387 /** 388 * Creates and returns a new content model. 389 * @param type the type of the new content model 390 * @param obj the content of the content model 391 * @param next pointer to the next content model 392 * @return the new {@code ContentModel} 393 */ 394 protected ContentModel defContentModel(int type, Object obj, ContentModel next) { 395 return new ContentModel(type, obj, next); 396 } 397 398 /** 399 * Returns a string representation of this DTD. 400 * @return the string representation of this DTD 401 */ 402 public String toString() { 403 return name; 404 } 405 406 /** 407 * The hashtable key of DTDs in AppContext. 408 */ 409 private static final Object DTD_HASH_KEY = new Object(); 410 411 /** 412 * Put a name and appropriate DTD to hashtable. 413 * 414 * @param name the name of the DTD 415 * @param dtd the DTD 416 */ 417 public static void putDTDHash(String name, DTD dtd) { 418 getDtdHash().put(name, dtd); 419 } 420 421 /** 422 * Returns a DTD with the specified {@code name}. If 423 * a DTD with that name doesn't exist, one is created 424 * and returned. Any uppercase characters in the name 425 * are converted to lowercase. 426 * 427 * @param name the name of the DTD 428 * @return the DTD which corresponds to {@code name} 429 * @throws IOException if an I/O error occurs 430 */ 431 public static DTD getDTD(String name) throws IOException { 432 name = name.toLowerCase(); 433 DTD dtd = getDtdHash().get(name); 434 if (dtd == null) 435 dtd = new DTD(name); 436 437 return dtd; 438 } 439 440 private static Hashtable<String, DTD> getDtdHash() { 441 AppContext appContext = AppContext.getAppContext(); 442 443 @SuppressWarnings("unchecked") 444 Hashtable<String, DTD> result = (Hashtable<String, DTD>) appContext.get(DTD_HASH_KEY); 445 446 if (result == null) { 447 result = new Hashtable<String, DTD>(); 448 449 appContext.put(DTD_HASH_KEY, result); 450 } 451 452 return result; 453 } 454 455 /** 456 * Recreates a DTD from an archived format. 457 * @param in the {@code DataInputStream} to read from 458 * @throws IOException if an I/O error occurs 459 */ 460 public void read(DataInputStream in) throws IOException { 461 if (in.readInt() != FILE_VERSION) { 462 } 463 464 // 465 // Read the list of names 466 // 467 String[] names = new String[in.readShort()]; 468 for (int i = 0; i < names.length; i++) { 469 names[i] = in.readUTF(); 470 } 471 472 473 // 474 // Read the entities 475 // 476 int num = in.readShort(); 477 for (int i = 0; i < num; i++) { |