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