1/* 2 * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package build.tools.dtdbuilder; 27 28import javax.swing.text.html.parser.*; 29import java.io.DataOutputStream; 30import java.io.File; 31import java.io.FileInputStream; 32import java.io.IOException; 33import java.io.FileNotFoundException; 34import java.io.BufferedInputStream; 35import java.io.OutputStream; 36import java.util.Hashtable; 37import java.util.Vector; 38import java.util.BitSet; 39import java.util.StringTokenizer; 40import java.util.Enumeration; 41import java.util.Properties; 42import java.util.zip.DeflaterOutputStream; 43import java.util.zip.Deflater; 44import java.net.URL; 45 46/** 47 * The representation of an SGML DTD. This is produced by the DTDParser. 48 * The resulting DTD object describes a document syntax and is needed 49 * to parse HTML documents using the Parser. It contains a list of 50 * elements and their attributes as well as a list of entities defined 51 * in the DTD. 52 * 53 * @see Element 54 * @see AttributeList 55 * @see ContentModel 56 * @see DTDParser 57 * @see Parser 58 * @author Arthur van Hoff 59 */ 60public 61class DTDBuilder extends DTD { 62 63 static PublicMapping mapping = null; 64 65 // Hash from name to Integer 66 private Hashtable<String, Integer> namesHash = new Hashtable<>(); 67 // Vector of all names 68 private Vector<String> namesVector = new Vector<>(); 69 70 /** 71 * Create a new DTD. 72 */ 73 protected DTDBuilder(String name) { 74 super(name); 75 } 76 77 78 /** 79 * Save to a stream as a Java class. Instantiating this class will 80 * reproduce a (virtually) identical DTD. 81 */ 82 void save(DataOutputStream out, String className) throws IOException { 83 84 out.writeInt(DTD.FILE_VERSION); 85 86 buildNamesTable(); 87 int numNames = namesVector.size(); 88 out.writeShort((short) (namesVector.size())); 89 for (int i = 0; i < namesVector.size(); i++) { 90 String nm = namesVector.elementAt(i); 91 out.writeUTF(nm); 92 } 93 94 saveEntities(out); 95 96 out.writeShort((short) (elements.size())); 97 for (Enumeration<Element> e = elements.elements() ; e.hasMoreElements() ; ) { 98 saveElement(out, e.nextElement()); 99 } 100 101 if (namesVector.size() != numNames) { 102 System.err.println("!!! ERROR! Names were added to the list!"); 103 Thread.dumpStack(); 104 System.exit(1); 105 } 106 } 107 108 private void buildNamesTable() { 109 for (Enumeration<Entity> e = entityHash.elements() ; e.hasMoreElements() ; ) { 110 Entity ent = e.nextElement(); 111 // Do even if not isGeneral(). That way, exclusions and inclusions 112 // will definitely have their element. 113 getNameId(ent.getName()); 114 } 115 for (Enumeration<Element> e = elements.elements() ; e.hasMoreElements() ; ) { 116 Element el = e.nextElement(); 117 getNameId(el.getName()); 118 for (AttributeList atts = el.getAttributes() ; atts != null ; atts = atts.getNext()) { 119 getNameId(atts.getName()); 120 if (atts.getValue() != null) { 121 getNameId(atts.getValue()); 122 } 123 Enumeration<?> vals = atts.getValues(); 124 while (vals != null && vals.hasMoreElements()) { 125 String s = (String) vals.nextElement(); 126 getNameId(s); 127 } 128 } 129 } 130 } 131 132 // 133 // The the id of a name from the list of names 134 // 135 private short getNameId(String name) { 136 Integer o = namesHash.get(name); 137 if (o != null) { 138 return (short) o.intValue(); 139 } 140 int i = namesVector.size(); 141 namesVector.addElement(name); 142 namesHash.put(name, new Integer(i)); 143 return (short) i; 144 } 145 146 147 /** 148 * Save an entity to a stream. 149 */ 150 void saveEntities(DataOutputStream out) throws IOException { 151 int num = 0; 152 for (Enumeration<Entity> e = entityHash.elements() ; e.hasMoreElements() ; ) { 153 Entity ent = e.nextElement(); 154 if (ent.isGeneral()) { 155 num++; 156 } 157 } 158 159 out.writeShort((short) num); 160 for (Enumeration<Entity> e = entityHash.elements() ; e.hasMoreElements() ; ) { 161 Entity ent = e.nextElement(); 162 if (ent.isGeneral()) { 163 out.writeShort(getNameId(ent.getName())); 164 out.writeByte(ent.getType() & ~GENERAL); 165 out.writeUTF(ent.getString()); 166 } 167 } 168 } 169 170 171 /** 172 * Save an element to a stream. 173 */ 174 175 public void saveElement(DataOutputStream out, Element elem) throws IOException { 176 177 out.writeShort(getNameId(elem.getName())); 178 out.writeByte(elem.getType()); 179 180 byte flags = 0; 181 if (elem.omitStart()) { 182 flags |= 0x01; 183 } 184 if (elem.omitEnd()) { 185 flags |= 0x02; 186 } 187 out.writeByte(flags); 188 saveContentModel(out, elem.getContent()); 189 190 // Exclusions 191 if (elem.exclusions == null) { 192 out.writeShort(0); 193 } else { 194 short num = 0; 195 for (int i = 0 ; i < elem.exclusions.size() ; i++) { 196 if (elem.exclusions.get(i)) { 197 num++; 198 } 199 } 200 out.writeShort(num); 201 for (int i = 0 ; i < elem.exclusions.size() ; i++) { 202 if (elem.exclusions.get(i)) { 203 out.writeShort(getNameId(getElement(i).getName())); 204 } 205 } 206 } 207 208 // Inclusions 209 if (elem.inclusions == null) { 210 out.writeShort(0); 211 } else { 212 short num = 0; 213 for (int i = 0 ; i < elem.inclusions.size() ; i++) { 214 if (elem.inclusions.get(i)) { 215 num++; 216 } 217 } 218 out.writeShort(num); 219 for (int i = 0 ; i < elem.inclusions.size() ; i++) { 220 if (elem.inclusions.get(i)) { 221 out.writeShort(getNameId(getElement(i).getName())); 222 } 223 } 224 } 225 226 // Attributes 227 { 228 short numAtts = 0; 229 for (AttributeList atts = elem.getAttributes() ; atts != null ; atts = atts.getNext()) { 230 numAtts++; 231 } 232 out.writeByte(numAtts); 233 for (AttributeList atts = elem.getAttributes() ; atts != null ; atts = atts.getNext()) { 234 out.writeShort(getNameId(atts.getName())); 235 out.writeByte(atts.getType()); 236 out.writeByte(atts.getModifier()); 237 if (atts.getValue() == null) { 238 out.writeShort(-1); 239 } else { 240 out.writeShort(getNameId(atts.getValue())); 241 } 242 if (atts.values == null) { 243 out.writeShort(0); 244 } else { 245 out.writeShort((short) atts.values.size()); 246 for (int i = 0; i < atts.values.size(); i++) { 247 String s = (String) atts.values.elementAt(i); 248 out.writeShort(getNameId(s)); 249 } 250 } 251 } 252 } 253 } 254 255 256 /** 257 * Save a content model to a stream. This does a 258 * recursive decent of the entire model. 259 */ 260 public void saveContentModel(DataOutputStream out, ContentModel model) throws IOException { 261 if (model == null) { 262 out.writeByte(0); 263 } else if (model.content instanceof ContentModel) { 264 out.writeByte(1); 265 out.writeByte(model.type); 266 saveContentModel(out, (ContentModel)model.content); 267 268 saveContentModel(out, model.next); 269 } else if (model.content instanceof Element) { 270 out.writeByte(2); 271 out.writeByte(model.type); 272 out.writeShort(getNameId(((Element) model.content).getName())); 273 274 saveContentModel(out, model.next); 275 } 276 } 277 278 279 /** 280 * Generate a class representing this DTD. 281 */ 282 283 public static void main(String argv[]) { 284 285 String dtd_home = System.getProperty("dtd_home") + File.separator; 286 if (dtd_home == null) { 287 System.err.println("Must set property 'dtd_home'"); 288 return; 289 } 290 291 DTDBuilder dtd = null; 292 try { 293 dtd = new DTDBuilder(argv[0]); 294 mapping = new PublicMapping(dtd_home, "public.map"); 295 String path = mapping.get(argv[0]); 296 new DTDParser().parse(new FileInputStream(path), dtd); 297 298 } catch (IOException e) { 299 System.err.println("Could not open DTD file "+argv[0]); 300 e.printStackTrace(System.err); 301 System.exit(1); 302 } 303 try { 304 DataOutputStream str = new DataOutputStream(System.out); 305 dtd.save(str, argv[0]); 306 str.close(); 307 } catch (IOException ex) { 308 ex.printStackTrace(); 309 System.exit(1); 310 } 311 } 312 313} 314