1 21 package au.id.jericho.lib.html; 22 23 import java.util.*; 24 25 final class TagTypeRegister { 26 private TagTypeRegister parent=null; 27 private char ch=NULL_CHAR; 28 private TagTypeRegister[] children=null; private TagType[] tagTypes=null; 31 private static final char NULL_CHAR='\u0000'; 32 33 private static final TagType[] DEFAULT_TAG_TYPES={ 34 StartTagType.UNREGISTERED, 35 StartTagType.NORMAL, 36 StartTagType.COMMENT, 37 StartTagType.MARKUP_DECLARATION, 38 StartTagType.DOCTYPE_DECLARATION, 39 StartTagType.CDATA_SECTION, 40 StartTagType.XML_PROCESSING_INSTRUCTION, 41 StartTagType.XML_DECLARATION, 42 StartTagType.SERVER_COMMON, 43 EndTagType.UNREGISTERED, 44 EndTagType.NORMAL 45 }; 46 47 private static TagTypeRegister root=new TagTypeRegister(); 48 49 static { 50 add(DEFAULT_TAG_TYPES); 51 } 52 53 private TagTypeRegister() {} 54 55 private static synchronized void add(final TagType[] tagTypes) { 56 for (int i=0; i<tagTypes.length; i++) add(tagTypes[i]); 57 } 58 59 public static synchronized void add(final TagType tagType) { 60 TagTypeRegister cursor=root; 61 final String startDelimiter=tagType.getStartDelimiter(); 62 for (int i=0; i<startDelimiter.length(); i++) { 63 final char ch=startDelimiter.charAt(i); 64 TagTypeRegister child=cursor.getChild(ch); 65 if (child==null) { 66 child=new TagTypeRegister(); 67 child.parent=cursor; 68 child.ch=ch; 69 cursor.addChild(child); 70 } 71 cursor=child; 72 } 73 cursor.addTagType(tagType); 74 } 75 76 public static synchronized void remove(final TagType tagType) { 77 TagTypeRegister cursor=root; 78 final String startDelimiter=tagType.getStartDelimiter(); 79 for (int i=0; i<startDelimiter.length(); i++) { 80 final char ch=startDelimiter.charAt(i); 81 final TagTypeRegister child=cursor.getChild(ch); 82 if (child==null) return; 83 cursor=child; 84 } 85 cursor.removeTagType(tagType); 86 while (cursor!=root && cursor.tagTypes==null && cursor.children==null) { 88 cursor.parent.removeChild(cursor); 89 cursor=cursor.parent; 90 } 91 } 92 93 public static List getList() { 95 final ArrayList list=new ArrayList(); 96 root.addTagTypesToList(list); 97 return list; 98 } 99 100 private void addTagTypesToList(final List list) { 101 if (tagTypes!=null) 102 for (int i=tagTypes.length-1; i>=0; i--) list.add(tagTypes[i]); 103 if (children!=null) 104 for (int i=0; i<children.length; i++) children[i].addTagTypesToList(list); 105 } 106 107 public static final String getDebugInfo() { 108 return root.appendDebugInfo(new StringBuffer (),0).toString(); 109 } 110 111 static final class ProspectiveTagTypeIterator implements Iterator { 112 private TagTypeRegister cursor; 113 private int tagTypeIndex=0; 114 115 public ProspectiveTagTypeIterator(final Source source, final int pos) { 116 final ParseText parseText=source.getParseText(); 118 cursor=root; 119 int posIndex=0; 120 try { 121 while (true) { 123 final TagTypeRegister child=cursor.getChild(parseText.charAt(pos+(posIndex++))); 124 if (child==null) break; 125 cursor=child; 126 } 127 } catch (IndexOutOfBoundsException ex) {} 128 while (cursor.tagTypes==null) if ((cursor=cursor.parent)==null) break; 130 } 131 132 public boolean hasNext() { 133 return cursor!=null; 134 } 135 136 public TagType getNextTagType() { 137 final TagType[] tagTypes=cursor.tagTypes; 138 final TagType nextTagType=tagTypes[tagTypeIndex]; 139 if ((++tagTypeIndex)==tagTypes.length) { 140 tagTypeIndex=0; 141 do {cursor=cursor.parent;} while (cursor!=null && cursor.tagTypes==null); 142 } 143 return nextTagType; 144 } 145 146 public Object next() { 148 return getNextTagType(); 149 } 150 151 public void remove() { 152 throw new UnsupportedOperationException (); 153 } 154 } 155 156 public String toString() { 157 return appendDebugInfo(new StringBuffer (),0).toString(); 158 } 159 160 private StringBuffer appendDebugInfo(final StringBuffer sb, final int level) { 161 for (int i=0; i<level; i++) sb.append(" "); 162 if (ch!=NULL_CHAR) sb.append(ch).append(' '); 163 if (tagTypes!=null) { 164 sb.append('('); 165 for (int i=0; i<tagTypes.length; i++) { 166 sb.append(tagTypes[i].getDescription()).append(", "); 167 } 168 sb.setLength(sb.length()-2); 169 sb.append(')'); 170 } 171 sb.append('\n'); 172 if (children!=null) { 173 final int childLevel=level+1; 174 for (int i=0; i<children.length; i++) { 175 children[i].appendDebugInfo(sb,childLevel); 176 } 177 } 178 return sb; 179 } 180 181 private TagTypeRegister getChild(final char ch) { 182 if (children==null) return null; 183 if (children.length==1) return children[0].ch==ch ? children[0] : null; 184 int low=0; 186 int high=children.length-1; 187 while (low<=high) { 188 int mid=(low+high) >> 1; 189 final char midChar=children[mid].ch; 190 if (midChar<ch) 191 low=mid+1; 192 else if (midChar>ch) 193 high=mid-1; 194 else 195 return children[mid]; 196 } 197 return null; 198 } 199 200 private void addChild(final TagTypeRegister child) { 201 if (children==null) { 203 children=new TagTypeRegister[] {child}; 204 } else { 205 final TagTypeRegister[] newChildren=new TagTypeRegister[children.length+1]; 206 int i=0; 207 while (i<children.length && children[i].ch<=child.ch) { 208 newChildren[i]=children[i]; 209 i++; 210 } 211 newChildren[i++]=child; 212 while (i<newChildren.length) { 213 newChildren[i]=children[i-1]; 214 i++; 215 } 216 children=newChildren; 217 } 218 } 219 220 private void removeChild(final TagTypeRegister child) { 221 if (children.length==1) { 223 children=null; 224 return; 225 } 226 final TagTypeRegister[] newChildren=new TagTypeRegister[children.length-1]; 227 int offset=0; 228 for (int i=0; i<children.length; i++) { 229 if (children[i]==child) 230 offset=-1; 231 else 232 newChildren[i+offset]=children[i]; 233 } 234 children=newChildren; 235 } 236 237 private int indexOfTagType(final TagType tagType) { 238 if (tagTypes==null) return -1; 239 for (int i=0; i<tagTypes.length; i++) 240 if (tagTypes[i]==tagType) return i; 241 return -1; 242 } 243 244 private void addTagType(final TagType tagType) { 245 final int indexOfTagType=indexOfTagType(tagType); 246 if (indexOfTagType==-1) { 247 if (tagTypes==null) { 248 tagTypes=new TagType[] {tagType}; 249 } else { 250 final TagType[] newTagTypes=new TagType[tagTypes.length+1]; 251 newTagTypes[0]=tagType; 252 for (int i=0; i<tagTypes.length; i++) newTagTypes[i+1]=tagTypes[i]; 253 tagTypes=newTagTypes; 254 } 255 } else { 256 for (int i=indexOfTagType; i>0; i--) tagTypes[i]=tagTypes[i-1]; 258 tagTypes[0]=tagType; 259 } 260 } 261 262 private void removeTagType(final TagType tagType) { 263 final int indexOfTagType=indexOfTagType(tagType); 264 if (indexOfTagType==-1) return; 265 if (tagTypes.length==1) { 266 tagTypes=null; 267 return; 268 } 269 final TagType[] newTagTypes=new TagType[tagTypes.length-1]; 270 for (int i=0; i<indexOfTagType; i++) newTagTypes[i]=tagTypes[i]; 271 for (int i=indexOfTagType; i<newTagTypes.length; i++) newTagTypes[i]=tagTypes[i+1]; 272 tagTypes=newTagTypes; 273 } 274 } 275 276 | Popular Tags |