1 /*************************************************************************** 2 * Copyright (C) 2001-2008 by Jesus Arias Fisteus * 3 * jaf@it.uc3m.es * 4 * * 5 * This program is free software; you can redistribute it and/or modify * 6 * it under the terms of the GNU General Public License as published by * 7 * the Free Software Foundation; either version 2 of the License, or * 8 * (at your option) any later version. * 9 * * 10 * This program is distributed in the hope that it will be useful, * 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 * GNU General Public License for more details. * 14 * * 15 * You should have received a copy of the GNU General Public License * 16 * along with this program; if not, write to the * 17 * Free Software Foundation, Inc., * 18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 19 ***************************************************************************/ 20 21 /* 22 * DTDDeclHandler.java 23 * 24 * Receives events from the DTD parser and stores data locally. At the end 25 * generates the C source files with the gathered data. 26 * 27 */ 28 29 import java.io.FileOutputStream; 30 import java.io.PrintWriter; 31 import java.text.SimpleDateFormat; 32 import java.util.Date; 33 import java.util.StringTokenizer; 34 import java.util.Vector; 35 36 import org.xml.sax.SAXException; 37 import org.xml.sax.ext.DeclHandler; 38 39 40 /** 41 * StringTokenizer with some auxiliarly methods 42 * for processing again the last token. 43 * 44 */ 45 class MyStringTokenizer extends StringTokenizer { 46 47 private static String last= null; 48 49 /** 50 * @see StringTokenizer#StringTokenizer(String,String,boolean) 51 * 52 */ MyStringTokenizer(String str, String delim, boolean type)53 public MyStringTokenizer(String str, String delim, boolean type) { 54 super(str, delim, type); 55 } 56 nextToken()57 public String nextToken() { 58 String token; 59 60 if (last!= null) { 61 token = last; 62 last = null; 63 } else token = super.nextToken(); 64 65 return token; 66 } 67 hasMoreTokens()68 public boolean hasMoreTokens() { 69 if (last != null) return true; 70 else return super.hasMoreTokens(); 71 } 72 getLast(String v)73 public void getLast(String v) { 74 last = v; 75 } 76 77 } 78 79 /** 80 * Internal class representing an attribute 81 * 82 */ 83 class AttDecl { 84 85 /* attribute types */ 86 public static final int ATTTYPE_CDATA = -2; 87 public static final int ATTTYPE_ID = -3; 88 public static final int ATTTYPE_IDREF = -4; 89 public static final int ATTTYPE_IDREFS = -5; 90 public static final int ATTTYPE_ENTITY = -6; 91 public static final int ATTTYPE_ENTITIES = -7; 92 public static final int ATTTYPE_NMTOKEN = -8; 93 public static final int ATTTYPE_NMTOKENS = -9; 94 public static final int ATTTYPE_ENUMERATED = -10; 95 public static final int ATTTYPE_NOTATION = -11; 96 97 /* default-value types */ 98 public static final int DEFDECL_DEFAULT = 0; 99 public static final int DEFDECL_REQUIRED = 1; 100 public static final int DEFDECL_IMPLIED = 2; 101 public static final int DEFDECL_FIXED = 3; 102 103 public String name; 104 public int type; 105 public int required; 106 public int defaultId = -1; 107 public int dtd; /* DTD mask */ 108 public int id; 109 public String stringType = null; 110 public String defaultString; 111 112 /** 113 * Insert a new attribute in the attribute list and return 114 * its identifier. If the attribute already exists, just returns 115 * its identifier. 116 * 117 */ AttDecl(String name, String type, String required, String defaultString, int dtd)118 public AttDecl(String name, String type, String required, 119 String defaultString, int dtd) throws Exception { 120 121 this.name= name; 122 123 /* set the attribute type */ 124 if (type.compareTo("CDATA")==0) 125 this.type= ATTTYPE_CDATA; 126 else if (type.compareTo("ID")==0) 127 this.type= ATTTYPE_ID; 128 else if (type.compareTo("IDREF")==0) 129 this.type= ATTTYPE_IDREF; 130 else if (type.compareTo("IDREFS")==0) 131 this.type= ATTTYPE_IDREFS; 132 else if (type.compareTo("ENTITY")==0) 133 this.type= ATTTYPE_ENTITY; 134 else if (type.compareTo("ENTITIES")==0) 135 this.type= ATTTYPE_ENTITIES; 136 else if (type.compareTo("NMTOKEN")==0) 137 this.type= ATTTYPE_NMTOKEN; 138 else if (type.compareTo("NMTOKENS")==0) 139 this.type= ATTTYPE_NMTOKENS; 140 else if (type.compareTo("NOTATION")==0) 141 throw new Exception("tipo de atributo NOTATION no soportado"); 142 else { 143 this.type= ATTTYPE_ENUMERATED; 144 this.stringType= type; 145 } 146 147 /* set attribute default-value type */ 148 if (required==null) 149 this.required= DEFDECL_DEFAULT; 150 else if (required.compareTo("#REQUIRED")==0) 151 this.required= DEFDECL_REQUIRED; 152 else if (required.compareTo("#IMPLIED")==0) 153 this.required= DEFDECL_IMPLIED; 154 else if (required.compareTo("#FIXED")==0) 155 this.required= DEFDECL_FIXED; 156 else 157 throw new Exception("unsupported default-value type: " 158 + type); 159 160 this.dtd= (1<<dtd); 161 if ((this.required== DEFDECL_DEFAULT) 162 || (this.required== DEFDECL_FIXED)) { 163 this.defaultString= defaultString; 164 } 165 } 166 167 168 169 /** 170 * Look for an attribute in the given vector. 171 * 172 */ searchAtt(Vector<AttDecl> list, AttDecl key)173 public static AttDecl searchAtt(Vector<AttDecl> list, AttDecl key) { 174 175 for (int i = 0; i < list.size(); i++) { 176 if (list.get(i).name.compareTo(key.name) == 0) { 177 AttDecl att = list.get(i); 178 179 if ((key.type == att.type) 180 && (key.required == att.required) 181 && (((key.defaultString == null) && (att.defaultString == null)) 182 ||(key.defaultString.compareTo(att.defaultString) == 0)) 183 && (((key.stringType == null)&&(att.stringType == null)) || 184 (key.stringType.compareTo(att.stringType) == 0))) 185 return att; 186 } 187 } 188 189 /* not found */ 190 return null; 191 } 192 193 194 /** 195 * Look for attributes with the given name. Returns all the 196 * attributes with that name. 197 * 198 */ searchAttByName(Vector<AttDecl> list, String name)199 public static Vector<AttDecl> searchAttByName(Vector<AttDecl> list, String name) { 200 Vector<AttDecl> atts = new Vector<AttDecl>(); 201 202 for (int i = 0; i < list.size(); i++) 203 if (list.elementAt(i).name.compareTo(name) == 0) { 204 atts.add(list.elementAt(i)); 205 } 206 207 return atts; 208 } 209 } 210 211 212 /** 213 * Store data regarding an element declaration. 214 * 215 */ 216 class ElmDecl { 217 218 public static final int CONTENT_NOTHING = 0; 219 public static final int CONTENT_EMPTY = 1; 220 public static final int CONTENT_ANY = 2; 221 public static final int CONTENT_MIXED = 3; 222 public static final int CONTENT_CHILDREN = 4; 223 224 225 /** 226 * Constants for encoding element content specifications. 227 * 228 */ 229 private static final int CSPEC_PAR_O = 1; 230 private static final int CSPEC_PAR_C = 2; 231 private static final int CSPEC_CHOICE = 0x10; 232 private static final int CSPEC_AST = 0x04; 233 private static final int CSPEC_MAS = 0x08; 234 private static final int CSPEC_INT = 0x0C; 235 236 237 public String name; 238 public int[] contentType; 239 public String[] content; 240 public Vector<Integer>[] attList; 241 public int[] contentPtr; 242 public int dtd; 243 public int id; 244 245 static private ElmDecl last = null; 246 static public String elmBuffer = ""; 247 ElmDecl(String name, int numDtds)248 public ElmDecl(String name, int numDtds) { 249 this.name = name; 250 dtd = 0; 251 252 contentType = new int[numDtds]; 253 for (int i = 0; i < numDtds; i++) 254 contentType[i]= 0; 255 256 content = new String[numDtds]; 257 for (int i = 0; i < numDtds; i++) 258 content[i]= null; 259 260 contentPtr = new int[numDtds]; 261 for (int i = 0; i < numDtds; i++) 262 contentPtr[i]= -1; 263 264 attList = new Vector[numDtds]; 265 for (int i = 0; i < numDtds; i++) 266 attList[i] = new Vector<Integer>(); 267 } 268 setData(int dtd, String content)269 public void setData(int dtd, String content) 270 throws SAXException { 271 272 this.dtd= this.dtd | (1 << dtd); 273 274 /* decide content type */ 275 try { 276 if (content.substring(0,3).compareTo("ANY") == 0) { 277 contentType[dtd] = CONTENT_ANY; 278 this.content[dtd] = null; 279 return; 280 } 281 } catch (StringIndexOutOfBoundsException ex) { 282 // nothing 283 } 284 285 try { 286 if (content.substring(0,5).compareTo("EMPTY") == 0) { 287 contentType[dtd] = CONTENT_EMPTY; 288 this.content[dtd] = null; 289 return; 290 } 291 } catch (StringIndexOutOfBoundsException ex) { 292 293 } 294 295 // children or mixed? NOTE: spaces are already filtered 296 if (content.charAt(0) != '(') 297 throw new SAXException("Incorrect content"); 298 299 try { 300 if (content.substring(1, 8).compareTo("#PCDATA") == 0) 301 contentType[dtd] = CONTENT_MIXED; 302 else contentType[dtd] = CONTENT_CHILDREN; 303 } catch (StringIndexOutOfBoundsException ex) { 304 contentType[dtd] = CONTENT_CHILDREN; 305 } 306 307 this.content[dtd] = content; 308 } 309 310 311 /** 312 * Look in the vector for an element with a given name 313 * Returns the element, or null if not found 314 * 315 */ searchElm(String name, Vector<ElmDecl> list)316 public static ElmDecl searchElm(String name, Vector<ElmDecl> list) { 317 318 if ((last != null) && (last.name.compareTo(name) == 0)) 319 return last; 320 321 for (int i = 0; i < list.size(); i++) { 322 if (list.elementAt(i).name.compareTo(name) == 0) { 323 last = list.elementAt(i); 324 return last; 325 } 326 } 327 328 /* not found */ 329 return null; 330 } 331 332 333 /** 334 * Encode the element's content and store it in the buffer 335 * 336 * Returns a pointer to its position in the buffer 337 * 338 */ encodeContent(Vector<ElmDecl> elements, int type, String content)339 public static int encodeContent(Vector<ElmDecl> elements, int type, String content) { 340 String encoded = encodeContentInternal(elements, type, content); 341 int pos; 342 343 if ((pos = elmBuffer.indexOf(encoded)) == -1) { 344 pos = elmBuffer.length(); 345 elmBuffer = elmBuffer.concat(encoded); 346 } 347 348 return pos; 349 } 350 encodeContentInternal(Vector<ElmDecl> elements, int type, String content)351 private static String encodeContentInternal(Vector<ElmDecl> elements, int type, 352 String content) { 353 char[] chars = new char[1024]; 354 int ptr = 0; 355 356 if (type == CONTENT_MIXED) { 357 // begins with "(#PCDATA"?: reed it 358 MyStringTokenizer tokenizer= 359 new MyStringTokenizer(content, "()|*", false); 360 361 if (tokenizer.nextToken().compareTo("#PCDATA") != 0) 362 System.err.println("WARNING: error in MIXED content"); 363 364 while (tokenizer.hasMoreTokens()) { 365 String nombreElm= tokenizer.nextToken(); 366 ElmDecl elm = ElmDecl.searchElm(nombreElm,elements); 367 if (elm == null) 368 System.err.println("WARNING: " + nombreElm 369 +", element not found"); 370 else { 371 chars[ptr++] = (char)(128 + elm.id); 372 } 373 } 374 } else { 375 // type children: call another function to encode it 376 MyStringTokenizer tokenizer= 377 new MyStringTokenizer(content, "()|,", true); 378 379 try { 380 ptr = encodeChildrenContent(tokenizer, chars, ptr, elements); 381 } catch (Exception ex){ 382 System.err.println("ERROR (encodeChildrenContent): " 383 + ex.getMessage()); 384 ex.printStackTrace(); 385 System.exit(1); 386 } 387 } 388 389 // finish it with a 0 390 chars[ptr++] = 0; 391 392 return new String(chars, 0, ptr); 393 } 394 395 /** 396 * recursive function that encodes children content rules 397 * 398 */ encodeChildrenContent(MyStringTokenizer tok, char[] buffer, int ptr, Vector<ElmDecl> elements)399 private static int encodeChildrenContent(MyStringTokenizer tok, 400 char[] buffer, int ptr, 401 Vector<ElmDecl> elements) 402 throws Exception { 403 404 boolean close; 405 int posIni = ptr; 406 String v; 407 408 // '(' first 409 if (tok.nextToken().compareTo("(") != 0) 410 throw new Exception("ERROR: '(' expected"); 411 buffer[ptr++] = CSPEC_PAR_O; 412 413 // reads content 414 while (true) { 415 v = tok.nextToken(); 416 417 if (v.compareTo(")") == 0 ) { 418 break; // end recursion 419 } else if (v.compareTo("(") == 0) {// new recursive call 420 tok.getLast(v); 421 ptr = encodeChildrenContent(tok, buffer, ptr, elements); 422 } else if (v.compareTo(",")==0) { 423 //new element: do nothing 424 } else if (v.compareTo("|") == 0) { 425 // new element in choice 426 // mark and continue reading 427 buffer[posIni] |= CSPEC_CHOICE; 428 } else { //element: encode it 429 switch (v.charAt(v.length() - 1)) { 430 case '*': 431 buffer[ptr++] = CSPEC_PAR_O | CSPEC_AST; 432 v = v.substring(0, v.length() - 1); 433 close = true; 434 break; 435 case '+': 436 buffer[ptr++] = CSPEC_PAR_O | CSPEC_MAS; 437 v = v.substring(0, v.length() - 1); 438 close = true; 439 break; 440 case '?': 441 buffer[ptr++] = CSPEC_PAR_O | CSPEC_INT; 442 v = v.substring(0, v.length() - 1); 443 close = true; 444 break; 445 default: 446 close = false; 447 } 448 449 ElmDecl elm = ElmDecl.searchElm(v, elements); 450 if (elm == null) 451 throw new Exception(v + ": element not found"); 452 453 buffer[ptr++]= (char)(128 + elm.id); 454 if (close) 455 buffer[ptr++] = CSPEC_PAR_C; 456 } 457 } //while(1) 458 459 // encode closing 460 buffer[ptr++] = CSPEC_PAR_C; 461 462 if (tok.hasMoreTokens()) { 463 v = tok.nextToken(); 464 if (v.compareTo("*") == 0) buffer[posIni] |= CSPEC_AST; 465 else if (v.compareTo("+") == 0) buffer[posIni] |= CSPEC_MAS; 466 else if (v.compareTo("?") == 0) buffer[posIni] |= CSPEC_INT; 467 else tok.getLast(v); 468 } 469 470 return ptr; 471 } 472 } 473 474 475 /** 476 * Handler for DTD declarations 477 * 478 */ 479 class DTDDeclHandler implements DeclHandler { 480 481 private Vector<String> entities = new Vector<String>(); 482 private Vector<ElmDecl> elements = new Vector<ElmDecl>(); 483 private Vector<AttDecl> attributes = new Vector<AttDecl>(); 484 private int dtd = 0; 485 private int numDtds; 486 487 private int entMaxLen; 488 private int attMaxLen; 489 private int elmMaxLen; 490 private int elmMaxAttNum; 491 492 private String attBuffer = null; 493 494 495 /** list of key elements to be dumped in a macro in dtd.h */ 496 private String[] listKeyElms = new String [] { 497 "html", "head", "body", "frameset", "style", "script", "meta", "p", 498 "title", "pre", "frame", "applet", "a", "form", "iframe", "img", "map", 499 "ul", "ol", "li", "table", "tr", "th", "td", "thead", "tbody", "object", 500 "big", "small", "sub", "sup", "input", "select", "textarea", "label", 501 "button", "fieldset", "isindex", "center", "u", "s", "strike", 502 "ins", "del", "area", "font", "basefont", "dir", "menu", 503 "ruby", "rb", "rbc", "rp", "rt", "rtc", "bdo", "div", "span", 504 "dl", "hr", "caption", "base"}; 505 506 /** list of key attributes to be dumped in a macro in dtd.h */ 507 private String[] listKeyAtts = new String [] { 508 "xml:space", "http-equiv", "content", "xmlns"}; 509 DTDDeclHandler(int numDtds)510 public DTDDeclHandler(int numDtds) { 511 512 this.numDtds = numDtds; 513 } 514 elementDecl(String name, String model)515 public void elementDecl(String name, String model) 516 throws SAXException 517 { 518 // System.err.println("elementDecl: "); 519 // System.err.println(" "+name); 520 // System.err.println(" "+model); 521 522 ElmDecl elm = ElmDecl.searchElm(name, elements); 523 524 if (elm == null) { 525 elm = new ElmDecl(name, numDtds); 526 elm.id = elements.size(); 527 elements.add(elm); 528 } 529 elm.setData(dtd, model); 530 } 531 532 attributeDecl(String eName, String aName, String type, String valueDefault, String value)533 public void attributeDecl(String eName, String aName, 534 String type, String valueDefault, 535 String value) 536 throws SAXException 537 { 538 539 // System.err.println("attributeDecl: "); 540 // System.err.println(" "+eName); 541 // System.err.println(" "+aName); 542 // System.err.println(" "+type); 543 // System.err.println(" "+valueDefault); 544 // System.err.println(" "+value); 545 546 /* create and link the attribute */ 547 AttDecl key; 548 549 try { 550 key = new AttDecl(aName, type, valueDefault, value, dtd); 551 } catch (Exception ex) { 552 throw new SAXException("attributeDecl: " + ex.getMessage()); 553 } 554 555 AttDecl att = AttDecl.searchAtt(attributes, key); 556 if (att == null) { 557 key.id = attributes.size(); 558 attributes.add(key); 559 att = key; 560 } else { 561 att.dtd = att.dtd | (1 << dtd); 562 } 563 564 /* link the attribute to the element */ 565 ElmDecl elm = ElmDecl.searchElm(eName, elements); 566 if (elm == null) { 567 /* Sometimes ATTLIST appears before than ELEMENT (xhtml 1.1) */ 568 elm = new ElmDecl(eName, numDtds); 569 elm.id = elements.size(); 570 elements.add(elm); 571 } 572 573 elm.attList[dtd].add(new Integer(att.id)); 574 } 575 internalEntityDecl(String name, String value)576 public void internalEntityDecl(String name, String value) 577 throws SAXException 578 { 579 // System.err.println("internalEntityDecl: "); 580 // System.err.println(" "+name+": "+value+" ["+"]"); 581 582 /* store only the name of the entity */ 583 if (name.charAt(0) != '%') 584 if (entities.indexOf(name) == -1) 585 entities.add(name); 586 } 587 externalEntityDecl(String name, String publicId, String systemId)588 public void externalEntityDecl(String name, String publicId, 589 String systemId) 590 throws SAXException 591 { 592 // System.err.println("externalEntityDecl: "); 593 // System.err.println(" "+name); 594 // System.err.println(" "+publicId); 595 // System.err.println(" "+systemId); 596 } 597 598 /** set DTD id for the following invocations */ setDtd(int num)599 protected void setDtd(int num) { 600 dtd = num; 601 } 602 603 /** write dtd.c and dtd.h */ writeFiles(String outputPath)604 protected void writeFiles(String outputPath) { 605 finishAtts(attributes); 606 finishElms(elements); 607 608 try { 609 // print dtd.c 610 FileOutputStream outStr = new FileOutputStream(outputPath + "/dtd.c"); 611 PrintWriter out= new PrintWriter(outStr); 612 System.out.println("Writing " + outputPath + "/dtd.c"); 613 printHeader(out); 614 printEntities(out); 615 printAtts(out); 616 printElms(out); 617 out.close(); 618 619 // print dtd.h 620 outStr = new FileOutputStream(outputPath + "/dtd.h"); 621 out = new PrintWriter(outStr); 622 System.out.println("Writing " + outputPath + "/dtd.h"); 623 writeDtdH(out); 624 out.close(); 625 } catch (java.io.FileNotFoundException ex) { 626 System.err.println(ex.getMessage()); 627 } 628 } 629 630 /** 631 * create the buffer for attributes 632 * 633 */ finishAtts(Vector<AttDecl> attributes)634 private void finishAtts(Vector<AttDecl> attributes) { 635 attBuffer = ""; 636 int maxLen = 0; 637 638 for (int i=0; i < attributes.size(); i++) { 639 AttDecl att = attributes.get(i); 640 641 if (att.name.length() > maxLen) maxLen = att.name.length(); 642 643 if (att.type == AttDecl.ATTTYPE_ENUMERATED) { 644 // insert enumerated type into the buffer 645 att.type = attBuffer.length(); 646 attBuffer = attBuffer + att.stringType + '\0'; 647 } 648 649 if ((att.required == AttDecl.DEFDECL_DEFAULT) 650 || (att.required == AttDecl.DEFDECL_FIXED)) { 651 att.defaultId = attBuffer.length(); 652 attBuffer = attBuffer + att.defaultString + '\0'; 653 } 654 } 655 656 attMaxLen = maxLen + 1; 657 } 658 659 /** 660 * creates the buffer for elements 661 * 662 */ finishElms(Vector<ElmDecl> elements)663 private void finishElms(Vector<ElmDecl> elements) { 664 int elmNum = elements.size(); 665 int maxAttNum = 0; 666 int maxLen = 0; 667 668 for (int i = 0; i < elmNum; i++) { 669 ElmDecl elm = elements.elementAt(i); 670 for (int nDtd = 0; nDtd < numDtds; nDtd++) { 671 if ((elm.contentType[nDtd] == ElmDecl.CONTENT_MIXED) 672 ||(elm.contentType[nDtd] == ElmDecl.CONTENT_CHILDREN)) { 673 674 elm.contentPtr[nDtd]= 675 ElmDecl.encodeContent(elements, elm.contentType[nDtd], 676 elm.content[nDtd]); 677 } 678 679 // number of attributes 680 if (elm.attList[nDtd].size() > maxAttNum) 681 maxAttNum = elm.attList[nDtd].size(); 682 } // for nDtd 683 684 // name length 685 if (elm.name.length() > maxLen) maxLen = elm.name.length(); 686 } // for i 687 688 elmMaxLen = maxLen + 1; 689 elmMaxAttNum = maxAttNum + 1; 690 } 691 692 693 /** 694 * write the header of dtd.c: comments & includes 695 * 696 */ printHeader(PrintWriter out)697 private void printHeader(PrintWriter out) { 698 DTDCoder.writeFileHeader(out); 699 out.println("#include \"dtd.h\""); 700 out.println(""); 701 } 702 printEntities(PrintWriter out)703 private void printEntities(PrintWriter out) { 704 705 /* look for the longest name to set the array length */ 706 int max= 0; 707 for (int i = 0; i < entities.size(); i++) 708 if (entities.elementAt(i).length() > max) 709 max = entities.elementAt(i).length(); 710 711 out.println("char ent_list[" + entities.size() + "][" + (max + 1) + "]= {"); 712 713 /* compute the hash value for each entity */ 714 int[] hashValue = new int[entities.size()]; 715 716 for (int i = 0; i < entities.size(); i++) { 717 int hash = entities.get(i).hashCode() % 256; 718 if (hash >= 0) hashValue[i] = hash; 719 else hashValue[i] = hash + 256; 720 } 721 722 boolean comma = false; 723 int[] hashTable = new int[256]; 724 725 for (int k = 0, pos = 0; k < 256; k++) { 726 hashTable[k] = pos; 727 for (int i = 0; i < entities.size(); i++) { 728 if (hashValue[i] == k) { 729 if (comma) out.println(","); 730 else out.println(""); 731 comma = true; 732 pos++; 733 out.print (" \"" + entities.elementAt(i) + "\" /*" + 734 hashValue[i] + '*' + "/"); 735 } 736 } 737 } 738 out.println(""); 739 out.println("};"); 740 741 // print the hash table 742 out.println("/* hash table for entities */"); 743 out.print("int ent_hash[257]= {"); 744 745 for (int i=0; i < 256; i++) { 746 if ((i & 0xf) == 0) out.println(""); 747 String ns = String.valueOf(hashTable[i]); 748 while (ns.length() < 3) ns = " " + ns; 749 750 if (i == 0) out.print( " " + ns); 751 else out.print("," + ns); 752 } 753 out.println("\n," + entities.size() + "};\n"); 754 entMaxLen = max + 1; 755 } 756 printElms(PrintWriter out)757 private void printElms(PrintWriter out) { 758 out.println("\n/* elements */"); 759 out.println("elm_data_t elm_list[" + elements.size() + "]= {"); 760 761 boolean first= true; 762 for (int i = 0; i < elements.size(); i++) { 763 ElmDecl elm = elements.get(i); 764 765 if (!first) out.println(","); 766 else first = false; 767 768 out.print(" {\"" + elm.name + "\",{" + elm.contentType[0]); 769 for (int k = 1; k < numDtds; k++) 770 out.print("," + elm.contentType[k]); 771 772 out.print("},{" + elm.contentPtr[0]); 773 for (int k = 1; k < numDtds; k++) 774 out.print("," + elm.contentPtr[k]); 775 776 out.println("},"); 777 out.print(" {\n"); 778 779 // print the attribute list 780 for (int k = 0; k < numDtds; k++) { 781 int l; 782 out.print(" {"); 783 for (l = 0; l < elm.attList[k].size(); l++) { 784 out.print(elm.attList[k].elementAt(l) + ","); 785 if ((l == 15) || (l == 31)) out.print("\n "); 786 } 787 for ( ; l < (elmMaxAttNum - 1); l++) { 788 out.print("-1,"); 789 if ((l == 15) || (l == 31)) out.print("\n "); 790 } 791 out.print("-1}"); 792 if (k < numDtds - 1) out.println(","); 793 else out.print("\n },"); 794 } 795 out.println(" " + elm.dtd + "}"); 796 } // for i 797 798 out.println("};\n"); 799 800 // content buffer 801 out.println("/* buffer for element content specs */"); 802 out.print("\nunsigned char elm_buffer[" + ElmDecl.elmBuffer.length() + 803 "]= {"); 804 805 char[] chars= ElmDecl.elmBuffer.toCharArray(); 806 807 for (int i = 0; i < chars.length; i++) { 808 if ((i & 0xf) == 0) out.println(""); 809 int num = chars[i]; 810 String ns = String.valueOf(num); 811 while (ns.length() < 3) ns = " " + ns; 812 813 if (i == 0) out.print(" " + ns); 814 else out.print("," + ns); 815 } 816 out.println("\n};"); 817 } 818 printAtts(PrintWriter out)819 private void printAtts(PrintWriter out) { 820 out.println("\n/* atributos */"); 821 out.println("att_data_t att_list[" + attributes.size() + "]= {"); 822 823 int num = attributes.size(); 824 for (int i = 0; i < num; i++) { 825 AttDecl att = attributes.elementAt(i); 826 827 out.print(" {\"" + att.name + "\"," + att.type + "," 828 + att.required + 829 "," + att.defaultId + "," + att.dtd + "}"); 830 if ((i+1) == num) out.println(""); 831 else out.println(","); 832 } // for i 833 834 out.println("};\n"); 835 out.println("/* data buffer for attribute specs */"); 836 out.print("\nunsigned char att_buffer[" + attBuffer.length() + "]= {"); 837 838 char[] chars= attBuffer.toCharArray(); 839 for (int i = 0; i < chars.length; i++) { 840 if ((i & 0xf) == 0) out.println(""); 841 num = chars[i]; 842 String ns = String.valueOf(num); 843 while (ns.length() < 3) ns = " " + ns; 844 845 if (i==0) out.print(" " + ns); 846 else out.print("," + ns); 847 } 848 out.println("\n};"); 849 } 850 writeDtdH(PrintWriter out)851 private void writeDtdH(PrintWriter out) { 852 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ"); 853 String date = sdf.format(new Date()).toString(); 854 855 DTDCoder.writeFileHeader(out); 856 857 out.println("#ifndef DTD_H\n#define DTD_H\n"); 858 out.println("#define DTD_NUM " + numDtds + "\n"); 859 out.println("#define ATT_NAME_LEN " + attMaxLen); 860 out.println("#define ELM_NAME_LEN " + elmMaxLen); 861 out.println("#define ENT_NAME_LEN " + entMaxLen + "\n"); 862 out.println("#define ELM_ATTLIST_LEN " + elmMaxAttNum + "\n"); 863 864 out.println("/* files that declare types and other macros */"); 865 out.println("#include \"dtd_types.h\""); 866 out.println("#include \"dtd_names.h\"\n"); 867 868 out.println("#define DTD_SNAPSHOT_DATE \"" + date + "\"\n"); 869 870 out.println("#define elm_data_num " + elements.size()); 871 out.println("#define att_data_num " + attributes.size()); 872 out.println("#define ent_data_num " + entities.size()); 873 out.println("#define elm_buffer_num " + ElmDecl.elmBuffer.length()); 874 out.println("#define att_buffer_num " + attBuffer.length()); 875 876 out.println("\n/* variables declared in dtd.c */"); 877 out.println("extern elm_data_t elm_list[];"); 878 out.println("extern unsigned char elm_buffer[];"); 879 out.println("extern att_data_t att_list[];"); 880 out.println("extern unsigned char att_buffer[];\n"); 881 882 out.println("extern int ent_hash[257];"); 883 out.println("extern char ent_list[][" + entMaxLen + "];\n"); 884 885 /* key elements and attributes */ 886 for (int i = 0; i < listKeyElms.length; i++) 887 keyElm(listKeyElms[i], out); 888 for (int i = 0; i < listKeyAtts.length; i++) 889 keyAtt(listKeyAtts[i], out); 890 891 out.println("#endif /* DTD_H */"); 892 } 893 894 keyElm(String name, PrintWriter out)895 private void keyElm(String name, PrintWriter out) { 896 ElmDecl elm = ElmDecl.searchElm(name, elements); 897 898 if (elm != null) 899 out.println("#define ELMID_" + name.toUpperCase() + " " + elm.id); 900 } 901 keyAtt(String name, PrintWriter out)902 private void keyAtt(String name, PrintWriter out) { 903 904 Vector<AttDecl> atts = AttDecl.searchAttByName(attributes, name); 905 if (atts.size() == 1) { 906 AttDecl att = atts.elementAt(0); 907 out.println("#define ATTID_" + name.toUpperCase().replace(':','_') 908 .replace('-','_') + " " + att.id); 909 } else if (atts.size() > 1) { 910 AttDecl att; 911 for (int i=0; i < atts.size(); i++) { 912 att = atts.elementAt(i); 913 out.println("#define ATTID_" + name.toUpperCase().replace(':','_') 914 .replace('-','_') + "_" + i + " " + att.id); 915 } 916 } 917 } 918 } 919