/******************************************************************************* * Copyright (C) 2009-2011 Amir Hassan <amir@viel-zu.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ******************************************************************************/ package org.wooden.html; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; import java.util.BitSet; import java.util.Enumeration; import java.util.HashMap; import java.util.Vector; import javax.swing.text.html.parser.AttributeList; import javax.swing.text.html.parser.ContentModel; import javax.swing.text.html.parser.DTD; import javax.swing.text.html.parser.Element; import javax.swing.text.html.parser.Entity; public class DTDTool { private class NamesMap extends HashMap { private int index; private NamesMap() { super(); } NamesMap(NamesMap namesmap) { this(); } public boolean addNameIndex(String name) { if (name == null) throw new IllegalArgumentException("The name can't be null"); if (!this.containsKey(name)) this.put(name, new Integer(this.index++)); else return false; return true; } public int getIndex() { return this.index; } public int getNameIndex(String name) { if (name == null) throw new IllegalArgumentException("The name can't be null"); if (this.containsKey(name)) return ((Integer) this.get(name)).intValue(); else throw new RuntimeException((new StringBuilder("Name index for: ")) .append(name).append(" not found").toString()); } public String[] getNamesSortedByIndex() { int maxIndex = this.getIndex(); String keys[] = (String[]) this.keySet().toArray(new String[0]); String names[] = new String[maxIndex]; for (int i = 0; i < maxIndex; i++) names[this.getNameIndex(keys[i])] = keys[i]; return names; } } private static PrintStream logger; public static void main(String args[]) { try { DTD dtd = DTD.getDTD("html32"); dtd.read(new DataInputStream(new FileInputStream( "D:/Programming/develop/VADV/html32.bdtd"))); (new DTDTool()).writeDTD(new DataOutputStream(new FileOutputStream( "D:/Programming/develop/VADV/htmlcustom.bdtd")), dtd); } catch (Exception ex) { ex.printStackTrace(); } } public DTDTool() throws IOException { logger = new PrintStream(new FileOutputStream("dtd.out")); } private int createFlag(boolean omitStart, boolean omitEnd) { int flag = 0; if (omitStart) flag |= 1; if (omitEnd) flag |= 2; return flag; } private NamesMap createNamesMap(Entity entities[], Element elements[]) { NamesMap namesHash = new NamesMap(null); for (Entity entitie : entities) namesHash.addNameIndex(entitie.getName()); for (Element element : elements) { namesHash.addNameIndex(element.getName()); AttributeList list = element.getAttributes(); if (list != null) do { namesHash.addNameIndex(list.getName()); String val = list.getValue(); if (val != null) namesHash.addNameIndex(val); Enumeration values; if ((values = list.getValues()) != null) for (; values.hasMoreElements(); namesHash.addNameIndex(values .nextElement().toString())) ; } while ((list = list.getNext()) != null); } return namesHash; } private void writeAttibuteList(DataOutputStream out, AttributeList list, NamesMap namesHash) throws IOException { Vector lists = new Vector(); int numLists; if (list != null) { do lists.add(list); while ((list = list.getNext()) != null); numLists = lists.size(); } else { numLists = 0; } logger.println((new StringBuilder("\t\tLists: ")).append(numLists) .toString()); out.writeByte(numLists); for (int i = 0; i < numLists; i++) { list = (AttributeList) lists.get(i); logger.println((new StringBuilder("\t\t")).append(list.getName()) .append('/').append(list.getType()).append('/') .append(list.getModifier()).toString()); out.writeShort(namesHash.getNameIndex(list.getName())); out.writeByte(list.getType()); out.writeByte(list.getModifier()); String val = list.getValue(); if (val == null) out.writeShort(-1); else out.writeShort(namesHash.getNameIndex(val)); Vector values = list.values; int numValues; if (values == null) numValues = 0; else numValues = values.size(); out.writeShort(numValues); if (numValues > 0) { for (int j = 0; j < numValues; j++) { logger.println((new StringBuilder("\t\t\t")).append( values.get(j).toString()).toString()); out.writeShort(namesHash.getNameIndex(values.get(j).toString())); } } } } private void writeContentModel(DataOutputStream out, ContentModel m, NamesMap namesHash) throws IOException { this.writeContentModel(out, m, namesHash, 0); } private void writeContentModel(DataOutputStream out, ContentModel m, NamesMap namesHash, int depth) throws IOException { String tabs = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; String t = tabs.substring(0, depth + 2); depth++; byte flag; if (m == null) flag = 0; else if (m.content instanceof ContentModel) flag = 1; else if (m.content instanceof Element) flag = 2; else throw new RuntimeException(); if (flag != 0) logger.print((new StringBuilder(String.valueOf(t))) .append("ContentModel: ").append(flag).append('/').append(m.type) .toString()); out.writeByte(flag); switch (flag) { case 1: // '\001' out.writeByte(m.type); this.writeContentModel(out, (ContentModel) m.content, namesHash, depth); this.writeContentModel(out, m.next, namesHash, depth); break; case 2: // '\002' logger.println((new StringBuilder("\r\n\t")).append(t) .append("Element: ").append(((Element) m.content).getName()) .toString()); out.writeByte(m.type); out.writeShort(namesHash.getNameIndex(((Element) m.content).getName())); this.writeContentModel(out, m.next, namesHash, depth); break; } } public void writeDTD(DataOutputStream out, DTD dtd) throws IOException { long start = System.currentTimeMillis(); final Entity entities[] = dtd.entityHash.values().toArray(new Entity[0]); final Element elements[] = dtd.elementHash.values().toArray(new Element[0]); final NamesMap namesHash = this.createNamesMap(entities, elements); ByteArrayOutputStream entityBuffer = new ByteArrayOutputStream(); ByteArrayOutputStream elementBuffer = new ByteArrayOutputStream(); final DataOutputStream outEntity = new DataOutputStream(entityBuffer); final DataOutputStream outElement = new DataOutputStream(elementBuffer); Thread entityWorker = new Thread() { @Override public void run() { try { DTDTool.this.writeEntities(outEntity, entities, namesHash); } catch (IOException ex) { ex.printStackTrace(); } } }; Thread elementWorker = new Thread() { @Override public void run() { try { DTDTool.this.writeElements(outElement, elements, namesHash); } catch (IOException ex) { ex.printStackTrace(); } } }; this.writeFileVersion(out, dtd); this.writeNames(out, namesHash.getNamesSortedByIndex()); try { entityWorker.start(); entityWorker.join(); elementWorker.start(); elementWorker.join(); } catch (InterruptedException interruptedexception) {} out.write(entityBuffer.toByteArray()); out.write(elementBuffer.toByteArray()); out.close(); System.err.println(System.currentTimeMillis() - start); } private void writeElements(DataOutputStream out, Element elements[], NamesMap namesHash) throws IOException { logger.println((new StringBuilder("Elements: ")).append(elements.length) .toString()); out.writeShort(elements.length); for (Element element : elements) { out.writeShort(namesHash.getNameIndex(element.getName())); logger.println((new StringBuilder(String.valueOf('\t'))) .append(element.getName()).append('/').append(element.getType()) .append('/') .append(this.createFlag(element.omitStart(), element.omitEnd())) .toString()); out.writeByte(element.getType()); out.writeByte(this.createFlag(element.omitStart(), element.omitEnd())); this.writeContentModel(out, element.content, namesHash); logger.println("\t\tExclusions: "); this.writeNameIndexArray(out, element.exclusions, namesHash); logger.println("\t\tInclusions: "); this.writeNameIndexArray(out, element.inclusions, namesHash); this.writeAttibuteList(out, element.atts, namesHash); } } private void writeEntities(DataOutputStream out, Entity entities[], NamesMap namesHash) throws IOException { logger.println((new StringBuilder("Entities: ")).append(entities.length) .toString()); out.writeShort(entities.length); for (Entity entitie : entities) { logger.println((new StringBuilder(String.valueOf('\t'))) .append(entitie.getName()).append('/').append(entitie.getType()) .append('/').append(entitie.getString()).toString()); out.writeShort(namesHash.getNameIndex(entitie.getName())); out.writeByte(entitie.getType()); out.writeUTF(entitie.getString()); } } private void writeFileVersion(DataOutputStream out, DTD dtd) throws IOException { out.writeInt(1); } private void writeNameIndexArray(DataOutputStream out, BitSet set, NamesMap namesHash) throws IOException { if (set != null) { Vector indeces = new Vector(); String names[] = namesHash.getNamesSortedByIndex(); for (int bitIndex = 0; (bitIndex = set.nextSetBit(bitIndex)) > 0; bitIndex++) indeces.add(new Integer(bitIndex)); int size = indeces.size(); out.writeShort(size); for (int i = 0; i < size; i++) { logger.println((new StringBuilder("\t\t")).append( names[((Integer) indeces.get(i)).shortValue()]).toString()); out.writeShort(((Integer) indeces.get(i)).shortValue()); } } else { out.writeShort(0); } } private void writeNames(DataOutputStream out, String names[]) throws IOException { out.writeShort(names.length); for (String name : names) { out.writeUTF(name); } } }