KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > jsp > JspParser


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.jsp;
31
32 import com.caucho.java.LineMap;
33 import com.caucho.jsp.java.JspNode;
34 import com.caucho.log.Log;
35 import com.caucho.util.CharBuffer;
36 import com.caucho.util.L10N;
37 import com.caucho.util.LineCompileException;
38 import com.caucho.vfs.Path;
39 import com.caucho.vfs.ReadStream;
40 import com.caucho.xml.QName;
41 import com.caucho.xml.XmlChar;
42
43 import java.io.IOException JavaDoc;
44 import java.util.ArrayList JavaDoc;
45 import java.util.HashSet JavaDoc;
46 import java.util.logging.Level JavaDoc;
47 import java.util.logging.Logger JavaDoc;
48
49 /**
50  * Parses the JSP page. Both the XML and JSP tags are understood. However,
51  * escaping is always done using JSP rules.
52  */

53 public class JspParser {
54   static L10N L = new L10N(JspParser.class);
55   static final Logger JavaDoc log = Log.open(JspParser.class);
56   
57   public static final String JavaDoc JSP_NS = "http://java.sun.com/JSP/Page";
58   public static final String JavaDoc JSTL_CORE_URI = "http://java.sun.com/jsp/jstl/core";
59   public static final String JavaDoc JSTL_FMT_URI = "http://java.sun.com/jsp/jstl/fmt";
60
61   public static final QName PREFIX = new QName("prefix");
62   public static final QName TAGLIB = new QName("taglib");
63   public static final QName TAGDIR = new QName("tagdir");
64   public static final QName URI = new QName("uri");
65   
66   public static final QName JSP_DECLARATION =
67     new QName("jsp", "declaration", JSP_NS);
68   
69   public static final QName JSP_SCRIPTLET =
70     new QName("jsp", "scriptlet", JSP_NS);
71   
72   public static final QName JSP_EXPRESSION =
73     new QName("jsp", "expression", JSP_NS);
74   
75   public static final QName JSP_DIRECTIVE_PAGE =
76     new QName("jsp", "directive.page", JSP_NS);
77   
78   public static final QName JSP_DIRECTIVE_INCLUDE =
79     new QName("jsp", "directive.include", JSP_NS);
80   
81   public static final QName JSP_DIRECTIVE_CACHE =
82     new QName("jsp", "directive.cache", JSP_NS);
83   
84   public static final QName JSP_DIRECTIVE_TAGLIB =
85     new QName("jsp", "directive.taglib", JSP_NS);
86   
87   public static final QName JSP_DIRECTIVE_ATTRIBUTE =
88     new QName("jsp", "directive.attribute", JSP_NS);
89   
90   public static final QName JSP_DIRECTIVE_VARIABLE =
91     new QName("jsp", "directive.variable", JSP_NS);
92   
93   public static final QName JSP_DIRECTIVE_TAG =
94     new QName("jsp", "directive.tag", JSP_NS);
95   
96   public static final QName JSTL_CORE_OUT =
97     new QName("resin-c", "out", "urn:jsptld:" + JSTL_CORE_URI);
98   
99   public static final QName JSTL_CORE_CHOOSE =
100     new QName("resin-c", "choose", "urn:jsptld:" + JSTL_CORE_URI);
101   
102   public static final QName JSTL_CORE_WHEN =
103     new QName("resin-c", "when", "urn:jsptld:" + JSTL_CORE_URI);
104   
105   public static final QName JSTL_CORE_OTHERWISE =
106     new QName("resin-c", "otherwise", "urn:jsptld:" + JSTL_CORE_URI);
107   
108   public static final QName JSTL_CORE_FOREACH =
109     new QName("resin-c", "forEach", "urn:jsptld:" + JSTL_CORE_URI);
110
111   private static final int TAG_UNKNOWN = 0;
112   private static final int TAG_JSP = 1;
113   private static final int TAG_RAW = 2;
114   
115   private ParseState _parseState;
116   private JspBuilder _jspBuilder;
117   private ParseTagManager _tagManager;
118
119   private LineMap _lineMap;
120
121   private ArrayList JavaDoc<String JavaDoc> _preludeList = new ArrayList JavaDoc<String JavaDoc>();
122   private ArrayList JavaDoc<String JavaDoc> _codaList = new ArrayList JavaDoc<String JavaDoc>();
123   
124   private ArrayList JavaDoc<Include> _includes = new ArrayList JavaDoc<Include>();
125
126   private HashSet JavaDoc<String JavaDoc> _prefixes = new HashSet JavaDoc<String JavaDoc>();
127   
128   private Path _jspPath;
129   private ReadStream _stream;
130   private String JavaDoc _uriPwd;
131
132   private String JavaDoc _contextPath = "";
133   private String JavaDoc _filename = "";
134   private int _line;
135   private int _lineStart;
136   
137   private int _charCount;
138   private int _startText;
139
140   private int _peek = -1;
141   private boolean _seenCr = false;
142
143   private Namespace _namespaces;
144   
145   private boolean _isXml;
146   private boolean _isTop = true;
147   
148   private CharBuffer _tag = new CharBuffer();
149   private CharBuffer _value = new CharBuffer();
150
151   private CharBuffer _text = new CharBuffer();
152
153   /**
154    * Sets the JSP builder, which receives the SAX-like events from
155    * JSP parser.
156    */

157   void setJspBuilder(JspBuilder builder)
158   {
159     _jspBuilder = builder;
160   }
161
162   /**
163    * Sets the context path for error messages.
164    */

165   void setContextPath(String JavaDoc contextPath)
166   {
167     _contextPath = contextPath;
168   }
169
170   /**
171    * Sets the parse state, which stores state information for the parsing.
172    */

173   void setParseState(ParseState parseState)
174   {
175     _parseState = parseState;
176   }
177
178   /**
179    * Sets the parse state, which stores state information for the parsing.
180    */

181   ParseState getParseState()
182   {
183     return _parseState;
184   }
185
186   /**
187    * Sets the tag manager
188    */

189   void setTagManager(ParseTagManager manager)
190   {
191     _tagManager = manager;
192   }
193
194   /**
195    * Returns true if JSP EL expressions are enabled.
196    */

197   private boolean isELIgnored()
198   {
199     return _parseState.isELIgnored();
200   }
201
202   /**
203    * Returns true if JSP EL expressions are enabled.
204    */

205   private boolean isDeferredSyntaxAllowedAsLiteral()
206   {
207     return _parseState.isDeferredSyntaxAllowedAsLiteral();
208   }
209
210   /**
211    * Adds a prelude.
212    */

213   public void addPrelude(String JavaDoc prelude)
214   {
215     _preludeList.add(prelude);
216   }
217
218   /**
219    * Adds a coda.
220    */

221   public void addCoda(String JavaDoc coda)
222   {
223     _codaList.add(coda);
224   }
225
226   /**
227    * Starts parsing the JSP page.
228    *
229    * @param path the JSP source file
230    * @param uri the URI for the JSP source file.
231    */

232   void parse(Path path, String JavaDoc uri)
233     throws Exception JavaDoc
234   {
235     _namespaces = new Namespace(null, "jsp", JSP_NS);
236     _parseState.pushNamespace("jsp", JSP_NS);
237
238     _isXml = _parseState.isXml();
239
240     _filename = _contextPath + uri;
241  
242     if (uri != null) {
243       int p = uri.lastIndexOf('/');
244       _uriPwd = p <= 0 ? "/" : uri.substring(0, p + 1);
245     }
246     else {
247       _uriPwd = "/";
248     }
249     _parseState.setUriPwd(_uriPwd);
250
251     ReadStream is = path.openRead();
252     path.setUserPath(uri);
253
254     try {
255       parseJsp(is);
256     } finally {
257       is.close();
258       for (int i = 0; i < _includes.size(); i++) {
259         Include inc = _includes.get(i);
260         inc._stream.close();
261       }
262     }
263   }
264
265   /**
266    * Starts parsing the JSP page as a tag.
267    *
268    * @param path the JSP source file
269    * @param uri the URI for the JSP source file.
270    */

271   void parseTag(Path path, String JavaDoc uri)
272     throws Exception JavaDoc
273   {
274     _parseState.setTag(true);
275     
276     parse(path, uri);
277   }
278
279   /**
280    * Top-level JSP parser.
281    *
282    * @param stream the read stream containing the JSP file
283    *
284    * @return an XML DOM containing the JSP.
285    */

286   private void parseJsp(ReadStream stream)
287     throws Exception JavaDoc
288   {
289     _text.clear();
290     _includes.clear();
291
292     String JavaDoc uriPwd = _uriPwd;
293     
294     for (int i = _codaList.size() - 1; i >= 0; i--)
295       pushInclude(_codaList.get(i), true);
296     
297     addInclude(stream, uriPwd);
298     
299     for (int i = _preludeList.size() - 1; i >= 0; i--)
300       pushInclude(_preludeList.get(i), true);
301
302     setLocation();
303     _jspBuilder.startDocument();
304
305     String JavaDoc pageEncoding = _parseState.getPageEncoding();
306
307     int ch;
308
309     if (pageEncoding != null) {
310       _parseState.setPageEncoding(pageEncoding);
311       
312       stream.setEncoding(pageEncoding);
313     }
314
315     switch ((ch = stream.read())) {
316     case 0xfe:
317       if ((ch = stream.read()) != 0xff) {
318     throw error(L.l("Expected 0xff in UTF-16 header. UTF-16 pages with the initial byte 0xfe expect 0xff immediately following. The 0xfe 0xff sequence is used by some application to suggest UTF-16 encoding without a directive."));
319       }
320       else {
321     _parseState.setContentType("text/html; charset=UTF-16BE");
322     _parseState.setPageEncoding("UTF-16BE");
323     stream.setEncoding("UTF-16BE");
324       }
325       break;
326       
327     case 0xff:
328       if ((ch = stream.read()) != 0xfe) {
329     throw error(L.l("Expected 0xfe in UTF-16 header. UTF-16 pages with the initial byte 0xff expect 0xfe immediately following. The 0xff 0xfe sequence is used by some application to suggest UTF-16 encoding without a directive."));
330       }
331       else {
332     _parseState.setContentType("text/html; charset=UTF-16LE");
333     _parseState.setPageEncoding("UTF-16LE");
334     stream.setEncoding("UTF-16LE");
335       }
336       break;
337       
338     case 0xef:
339       if ((ch = stream.read()) != 0xbb) {
340     stream.unread();
341     stream.unread();
342       }
343       else if ((ch = stream.read()) != 0xbf) {
344     throw error(L.l("Expected 0xbf in UTF-8 header. UTF-8 pages with the initial byte 0xbb expect 0xbf immediately following. The 0xbb 0xbf sequence is used by some application to suggest UTF-8 encoding without a directive."));
345       }
346       else {
347     _parseState.setContentType("text/html; charset=UTF-8");
348     _parseState.setPageEncoding("UTF-8");
349     stream.setEncoding("UTF-8");
350       }
351       break;
352       
353     default:
354       stream.unread();
355     }
356
357     ch = read();
358
359     ch = parseXmlDeclaration(ch);
360     
361     try {
362       parseNode(ch);
363     } finally {
364       for (int i = 0; i < _includes.size(); i++) {
365     Include inc = _includes.get(i);
366     inc._stream.close();
367       }
368     }
369
370     setLocation();
371     _jspBuilder.endDocument();
372   }
373
374   private int parseXmlDeclaration(int ch)
375     throws IOException JavaDoc, JspParseException
376   {
377     if (ch != '<')
378       return ch;
379     else if ((ch = read()) != '?') {
380       unread(ch);
381       return '<';
382     }
383     else if ((ch = read()) != 'x') {
384       addText("<?");
385       return ch;
386     }
387     else if ((ch = read()) != 'm') {
388       addText("<?x");
389       return ch;
390     }
391     else if ((ch = read()) != 'l') {
392       addText("<?xm");
393       return ch;
394     }
395     else if (! XmlChar.isWhitespace((ch = read()))) {
396       addText("<?xml");
397       return ch;
398     }
399
400     String JavaDoc encoding = null;
401     
402     addText("<?xml ");
403     ch = skipWhitespace(ch);
404     while (XmlChar.isNameStart(ch)) {
405       ch = readName(ch);
406       String JavaDoc name = _tag.toString();
407
408       addText(name);
409       if (XmlChar.isWhitespace(ch))
410         addText(' ');
411
412       ch = skipWhitespace(ch);
413       if (ch != '=')
414         return ch;
415
416       readValue(name, ch, true);
417       String JavaDoc value = _value.toString();
418
419       addText("=\"");
420       addText(value);
421       addText("\"");
422
423       if (name.equals("encoding"))
424     encoding = value;
425
426       ch = read();
427       if (XmlChar.isWhitespace(ch))
428         addText(' ');
429       ch = skipWhitespace(ch);
430     }
431
432     if (ch != '?')
433       return ch;
434     else if ((ch = read()) != '>') {
435       addText('?');
436       return ch;
437     }
438     else {
439       addText("?>");
440
441       if (encoding != null) {
442     _stream.setEncoding(encoding);
443     _parseState.setPageEncoding(encoding);
444       }
445       
446       return read();
447     }
448   }
449     
450   private void parseNode(int ch)
451     throws IOException JavaDoc, JspParseException
452   {
453     while (ch != -1) {
454       switch (ch) {
455       case '<':
456     {
457       switch ((ch = read())) {
458       case '%':
459         if (_isXml)
460           throw error(L.l("'<%' syntax is not allowed in JSP/XML syntax."));
461         
462         parseScriptlet();
463         _startText = _charCount;
464
465             // escape '\\' after scriptlet at end of line
466
if ((ch = read()) == '\\') {
467               if ((ch = read()) == '\n') {
468                 ch = read();
469               }
470               else if (ch == '\r') {
471                 if ((ch = read()) == '\n')
472                   ch = read();
473               }
474               else
475                 addText('\\');
476             }
477         break;
478
479       case '/':
480         ch = parseCloseTag();
481         break;
482
483       case '\\':
484         if ((ch = read()) == '%') {
485           addText("<%");
486           ch = read();
487         }
488             else
489           addText("<\\");
490         break;
491
492           case '!':
493             if (! _isXml)
494               addText("<!");
495             else if ((ch = read()) == '[')
496               parseCdata();
497             else if (ch == '-' && (ch = read()) == '-')
498               parseXmlComment();
499             else
500               throw error(L.l("'{0}' was not expected after '<!'. In the XML syntax, only <!-- ... --> and <![CDATA[ ... ]> are legal. You can use '&amp;!' to escape '<!'.",
501                               badChar(ch)));
502
503             ch = read();
504             break;
505
506       default:
507         if (! XmlChar.isNameStart(ch)) {
508           addText('<');
509           break;
510         }
511
512         ch = readName(ch);
513         String JavaDoc name = _tag.toString();
514             int tagCode = getTag(name);
515         if (! _isXml && tagCode == TAG_UNKNOWN) {
516           addText("<");
517           addText(name);
518           break;
519         }
520
521         if (_isTop && name.equals("jsp:root")) {
522           if (_parseState.isForbidXml())
523         throw error(L.l("jsp:root must be in a JSP (XML) document, not a plain JSP."));
524           
525               _text.clear();
526               _isXml = true;
527           _parseState.setELIgnoredDefault(false);
528           _parseState.setXml(true);
529
530             }
531             _isTop = false;
532         parseOpenTag(name, ch, tagCode == TAG_UNKNOWN);
533
534             ch = read();
535             
536             // escape '\\' after scriptlet at end of line
537
if (! _isXml && ch == '\\') {
538               if ((ch = read()) == '\n') {
539                 ch = read();
540               }
541               else if (ch == '\r') {
542                 if ((ch = read()) == '\n')
543                   ch = read();
544               }
545             }
546       }
547       break;
548     }
549
550       case '&':
551         if (! _isXml)
552           addText((char) ch);
553         else {
554           addText((char) parseEntity());
555     }
556         ch = read();
557         break;
558
559       case '$':
560         ch = read();
561
562         if (ch == '{' && ! isELIgnored())
563           ch = parseJspExpression();
564         else
565           addText('$');
566         break;
567
568       case '#':
569         ch = read();
570
571     if (ch != '{' || isELIgnored()) {
572           addText('#');
573     }
574         else if (isDeferredSyntaxAllowedAsLiteral()) {
575           addText('#');
576     }
577         else
578       throw error(L.l("Deferred syntax ('#{...}') not allowed as literal."));
579         break;
580
581       case '\\':
582         switch (ch = read()) {
583         case '$':
584           if (! isELIgnored()) {
585             addText('$');
586             ch = read();
587           }
588           else
589             addText('\\');
590           break;
591       
592         case '#':
593           if (! isELIgnored()) {
594             addText('#');
595             ch = read();
596           }
597           else
598             addText('\\');
599           break;
600
601         case '\\':
602           addText('\\');
603           break;
604
605         default:
606           addText('\\');
607           break;
608         }
609         break;
610
611       default:
612     addText((char) ch);
613     ch = read();
614         break;
615       }
616     }
617     
618     addText();
619
620     /* XXX: end document
621     if (! _activeNode.getNodeName().equals("jsp:root"))
622       throw error(L.l("'</{0}>' expected at end of file. For XML, the top-level tag must have a matching closing tag.",
623                       activeNode.getNodeName()));
624     */

625   }
626
627   /**
628    * JSTL-style expressions. Currently understood:
629    *
630    * <code><pre>
631    * ${a * b} - any arbitrary expression
632    * </pre></code>
633    */

634   private int parseJspExpression()
635     throws IOException JavaDoc, JspParseException
636   {
637     addText();
638
639     Path jspPath = _jspPath;
640     String JavaDoc filename = _filename;
641     int line = _line;
642
643     CharBuffer cb = CharBuffer.allocate();
644     int ch;
645     cb.append("${");
646     for (ch = read(); ch >= 0 && ch != '}'; ch = read())
647       cb.append((char) ch);
648     cb.append("}");
649
650     ch = read();
651
652     processTaglib("resin-c", JSTL_CORE_URI);
653     
654     setLocation(jspPath, filename, line);
655     _jspBuilder.startElement(JSTL_CORE_OUT);
656     _jspBuilder.attribute(new QName("value"), cb.close());
657     _jspBuilder.attribute(new QName("escapeXml"), "false");
658     _jspBuilder.endAttributes();
659     _jspBuilder.endElement(JSTL_CORE_OUT.getName());
660
661     return ch;
662   }
663
664   /**
665    * Parses a &lt;![CDATA[ block. All text in the CDATA is uninterpreted.
666    */

667   private void parseCdata()
668     throws IOException JavaDoc, JspParseException
669   {
670     int ch;
671
672     ch = readName(read());
673
674     String JavaDoc name = _tag.toString();
675
676     if (! name.equals("CDATA"))
677       throw error(L.l("Expected <![CDATA[ at <!['{0}'.", name,
678                       "XML only recognizes the <![CDATA directive."));
679
680     if (ch != '[')
681       throw error(L.l("Expected '[' at '{0}'. The XML CDATA syntax is <![CDATA[...]]>.",
682                       String.valueOf(ch)));
683
684     String JavaDoc filename = _filename;
685     int line = _line;
686                   
687     while ((ch = read()) >= 0) {
688       while (ch == ']') {
689         if ((ch = read()) != ']')
690           addText(']');
691         else if ((ch = read()) != '>')
692           addText("]]");
693         else
694           return;
695       }
696
697       addText((char) ch);
698     }
699
700     throw error(L.l("Expected closing ]]> at end of file to match <![[CDATA at {0}.", filename + ":" + line));
701   }
702
703   /**
704    * Parses an XML name for elements and attribute names. The parsed name
705    * is stored in the 'tag' class variable.
706    *
707    * @param ch the next character
708    *
709    * @return the character following the name
710    */

711   private int readName(int ch)
712     throws IOException JavaDoc, JspParseException
713   {
714     _tag.clear();
715
716     for (; XmlChar.isNameChar((char) ch); ch = read())
717       _tag.append((char) ch);
718
719     return ch;
720   }
721
722   private void parsePageDirective(String JavaDoc name, String JavaDoc value)
723     throws IOException JavaDoc, JspParseException
724   {
725     if ("isELIgnored".equals(name)) {
726       if ("true".equals(value))
727         _parseState.setELIgnored(true);
728     }
729   }
730
731   /**
732    * Parses a special JSP syntax.
733    */

734   private void parseScriptlet()
735     throws IOException JavaDoc, JspParseException
736   {
737     addText();
738
739     _lineStart = _line;
740
741     int ch = read();
742
743     // probably should be a qname
744
QName eltName = null;
745
746     switch (ch) {
747     case '=':
748       eltName = JSP_EXPRESSION;
749       ch = read();
750       break;
751
752     case '!':
753       eltName = JSP_DECLARATION;
754       ch = read();
755       break;
756
757     case '@':
758       parseDirective();
759       return;
760
761     case '-':
762       if ((ch = read()) == '-') {
763     parseComment();
764     return;
765       }
766       else {
767         eltName = JSP_SCRIPTLET;
768     addText('-');
769       }
770       break;
771
772     default:
773       eltName = JSP_SCRIPTLET;
774       break;
775     }
776
777     setLocation(_jspPath, _filename, _lineStart);
778     _jspBuilder.startElement(eltName);
779     _jspBuilder.endAttributes();
780
781     while (ch >= 0) {
782       switch (ch) {
783       case '\\':
784     addText('\\');
785     ch = read();
786     if (ch >= 0)
787       addText((char) ch);
788     ch = read();
789     break;
790
791       case '%':
792     ch = read();
793     if (ch == '>') {
794           createText();
795           setLocation();
796           _jspBuilder.endElement(eltName.getName());
797       return;
798     }
799     else if (ch == '\\') {
800       ch = read();
801       if (ch == '>') {
802         addText("%");
803       }
804       else
805         addText("%\\");
806     }
807     else
808       addText('%');
809     break;
810
811       default:
812     addText((char) ch);
813     ch = read();
814     break;
815       }
816     }
817
818     createText();
819     setLocation();
820     _jspBuilder.endElement(eltName.getName());
821   }
822
823   /**
824    * Parses the JSP directive syntax.
825    */

826   private void parseDirective()
827     throws IOException JavaDoc, JspParseException
828   {
829     String JavaDoc language = null;
830
831     int ch = skipWhitespace(read());
832     String JavaDoc directive = "";
833     if (XmlChar.isNameStart(ch)) {
834       ch = readName(ch);
835       directive = _tag.toString();
836     }
837     else
838       throw error(L.l("Expected jsp directive name at '{0}'. JSP directive syntax is <%@ name attr1='value1' ... %>",
839                       badChar(ch)));
840
841     QName qname;
842
843     if (directive.equals("page"))
844       qname = JSP_DIRECTIVE_PAGE;
845     else if (directive.equals("include"))
846       qname = JSP_DIRECTIVE_INCLUDE;
847     else if (directive.equals("taglib"))
848       qname = JSP_DIRECTIVE_TAGLIB;
849     else if (directive.equals("cache"))
850       qname = JSP_DIRECTIVE_CACHE;
851     else if (directive.equals("attribute"))
852       qname = JSP_DIRECTIVE_ATTRIBUTE;
853     else if (directive.equals("variable"))
854       qname = JSP_DIRECTIVE_VARIABLE;
855     else if (directive.equals("tag"))
856       qname = JSP_DIRECTIVE_TAG;
857     else
858       throw error(L.l("'{0}' is an unknown jsp directive. Only <%@ page ... %>, <%@ include ... %>, <%@ taglib ... %>, and <%@ cache ... %> are known.", directive));
859
860     unread(ch);
861     
862     ArrayList JavaDoc<QName> keys = new ArrayList JavaDoc<QName>();
863     ArrayList JavaDoc<String JavaDoc> values = new ArrayList JavaDoc<String JavaDoc>();
864
865     parseAttributes(keys, values);
866
867     ch = skipWhitespace(read());
868
869     if (ch != '%' || (ch = read()) != '>') {
870       throw error(L.l("expected '%>' at {0}. JSP directive syntax is '<%@ name attr1='value1' ... %>'. (Started at line {1})",
871                       badChar(ch), _lineStart));
872     }
873
874     setLocation(_jspPath, _filename, _lineStart);
875     _lineStart = _line;
876     _jspBuilder.startElement(qname);
877
878     for (int i = 0; i < keys.size(); i++) {
879       _jspBuilder.attribute(keys.get(i), values.get(i));
880     }
881     _jspBuilder.endAttributes();
882   
883     if (qname.equals(JSP_DIRECTIVE_TAGLIB))
884       processTaglibDirective(keys, values);
885
886     setLocation();
887     _jspBuilder.endElement(qname.getName());
888
889     if (qname.equals(JSP_DIRECTIVE_PAGE)) {
890       String JavaDoc contentEncoding = _parseState.getPageEncoding();
891       if (contentEncoding == null)
892         contentEncoding = _parseState.getCharEncoding();
893
894       if (contentEncoding != null) {
895         try {
896           _stream.setEncoding(contentEncoding);
897         } catch (Exception JavaDoc e) {
898       log.log(Level.FINER, e.toString(), e);
899       
900           throw error(L.l("unknown content encoding '{0}'", contentEncoding),
901               e);
902         }
903       }
904     }
905     /*
906     if (directive.equals("include"))
907       parseIncludeDirective(elt);
908     else if (directive.equals("taglib"))
909       parseTaglibDirective(elt);
910     */

911   }
912
913   /**
914    * Parses an XML comment.
915    */

916   private void parseComment()
917     throws IOException JavaDoc, JspParseException
918   {
919     int ch = read();
920
921     while (ch >= 0) {
922       if (ch == '-') {
923     ch = read();
924     while (ch == '-') {
925       if ((ch = read()) == '-')
926         continue;
927       else if (ch == '%' && (ch = read()) == '>')
928         return;
929       else if (ch == '-')
930         ch = read();
931     }
932       }
933       else
934     ch = read();
935     }
936   }
937   
938   private void parseXmlComment()
939     throws IOException JavaDoc, JspParseException
940   {
941     int ch;
942     
943     while ((ch = read()) >= 0) {
944       while (ch == '-') {
945         if ((ch = read()) == '-' && (ch = read()) == '>')
946           return;
947       }
948     }
949   }
950
951   /**
952    * Parses the open tag.
953    */

954   private void parseOpenTag(String JavaDoc name, int ch, boolean isXml)
955     throws IOException JavaDoc, JspParseException
956   {
957     addText();
958
959     ch = skipWhitespace(ch);
960
961     ArrayList JavaDoc<QName> keys = new ArrayList JavaDoc<QName>();
962     ArrayList JavaDoc<String JavaDoc> values = new ArrayList JavaDoc<String JavaDoc>();
963
964     unread(ch);
965
966     parseAttributes(keys, values);
967
968     QName qname = getElementQName(name);
969
970     setLocation(_jspPath, _filename, _lineStart);
971     _lineStart = _line;
972
973     _jspBuilder.startElement(qname);
974
975     for (int i = 0; i < keys.size(); i++) {
976       QName key = keys.get(i);
977       String JavaDoc value = values.get(i);
978       
979       _jspBuilder.attribute(key, value);
980     }
981
982     _jspBuilder.endAttributes();
983     
984     if (qname.equals(JSP_DIRECTIVE_TAGLIB))
985       processTaglibDirective(keys, values);
986     
987     ch = skipWhitespace(read());
988
989     JspNode node = _jspBuilder.getCurrentNode();
990
991     if (ch == '/') {
992       if ((ch = read()) != '>')
993     throw error(L.l("expected '/>' at '{0}' (for tag '<{1}>' at line {2}). The XML empty tag syntax is: <tag attr1='value1'/>",
994                         badChar(ch), name, String.valueOf(_lineStart)));
995       
996       setLocation();
997       _jspBuilder.endElement(qname.getName());
998     }
999     else if (ch != '>')
1000      throw error(L.l("expected '>' at '{0}' (for tag '<{1}>' at line {2}). The XML tag syntax is: <tag attr1='value1'>",
1001                      badChar(ch), name, String.valueOf(_lineStart)));
1002    // If tagdependent and not XML mode, then read the raw text.
1003
else if ("tagdependent".equals(node.getBodyContent()) && ! _isXml) {
1004      String JavaDoc tail = "</" + name + ">";
1005      for (ch = read(); ch >= 0; ch = read()) {
1006    _text.append((char) ch);
1007    if (_text.endsWith(tail)) {
1008      _text.setLength(_text.length() - tail.length());
1009      addText();
1010          _jspBuilder.endElement(qname.getName());
1011      return;
1012        }
1013      }
1014      throw error(L.l("expected '{0}' at end of file (for tag <{1}> at line {2}). Tags with 'tagdependent' content need close tags.",
1015                      tail, String.valueOf(_lineStart)));
1016    }
1017  }
1018
1019  /**
1020   * Returns the full QName for the JSP page's name.
1021   */

1022  private QName getElementQName(String JavaDoc name)
1023  {
1024    int p = name.lastIndexOf(':');
1025
1026    if (p > 0) {
1027      String JavaDoc prefix = name.substring(0, p);
1028      String JavaDoc url = Namespace.find(_namespaces, prefix);
1029
1030      _prefixes.add(prefix);
1031
1032      if (url != null)
1033        return new QName(prefix, name.substring(p + 1), url);
1034      else
1035        return new QName("", name, "");
1036    }
1037    else {
1038      String JavaDoc url = Namespace.find(_namespaces, "");
1039
1040      if (url != null)
1041        return new QName("", name, url);
1042      else
1043        return new QName("", name, "");
1044    }
1045  }
1046
1047  /**
1048   * Returns the full QName for the JSP page's name.
1049   */

1050  private QName getAttributeQName(String JavaDoc name)
1051  {
1052    int p = name.lastIndexOf(':');
1053
1054    if (p > 0) {
1055      String JavaDoc prefix = name.substring(0, p);
1056      String JavaDoc url = Namespace.find(_namespaces, prefix);
1057
1058      if (url != null)
1059        return new QName(prefix, name.substring(p + 1), url);
1060      else
1061        return new QName("", name, "");
1062    }
1063    else
1064      return new QName("", name, "");
1065  }
1066
1067  /**
1068   * Parses the attributes of an element.
1069   */

1070  private void parseAttributes(ArrayList JavaDoc<QName> names,
1071                               ArrayList JavaDoc<String JavaDoc> values)
1072    throws IOException JavaDoc, JspParseException
1073  {
1074    names.clear();
1075    values.clear();
1076
1077    int ch = skipWhitespace(read());
1078
1079    while (XmlChar.isNameStart(ch)) {
1080      ch = readName(ch);
1081      String JavaDoc key = _tag.toString();
1082
1083      readValue(key, ch, _isXml);
1084      String JavaDoc value = _value.toString();
1085
1086      if (key.startsWith("xmlns:")) {
1087        String JavaDoc prefix = key.substring(6);
1088
1089    _jspBuilder.startPrefixMapping(prefix, value);
1090    //_parseState.pushNamespace(prefix, value);
1091
_namespaces = new Namespace(_namespaces, prefix, value);
1092      }
1093      else if (key.equals("xmlns")) {
1094    _jspBuilder.startPrefixMapping("", value);
1095    //_parseState.pushNamespace(prefix, value);
1096
//_parseState.pushNamespace("", value);
1097
_namespaces = new Namespace(_namespaces, "", value);
1098      }
1099      else {
1100        names.add(getAttributeQName(key));
1101        values.add(value);
1102      }
1103      
1104      ch = skipWhitespace(read());
1105    }
1106
1107    unread(ch);
1108  }
1109  
1110  /**
1111   * Reads an attribute value.
1112   */

1113  private void readValue(String JavaDoc attribute, int ch, boolean isXml)
1114    throws IOException JavaDoc, JspParseException
1115  {
1116    boolean isRuntimeAttribute = false;
1117    
1118    _value.clear();
1119
1120    ch = skipWhitespace(ch);
1121
1122    if (ch != '=') {
1123      unread(ch);
1124      return;
1125    }
1126
1127    ch = skipWhitespace(read());
1128
1129    if (ch != '\'' && ch != '"') {
1130      if (XmlChar.isNameChar(ch)) {
1131        ch = readName(ch);
1132
1133        throw error(L.l("'{0}' attribute value must be quoted at '{1}'. JSP attribute syntax is either attr=\"value\" or attr='value'.",
1134                        attribute, _tag));
1135      }
1136      else
1137        throw error(L.l("'{0}' attribute value must be quoted at '{1}'. JSP attribute syntax is either attr=\"value\" or attr='value'.",
1138                        attribute, badChar(ch)));
1139    }
1140
1141    int end = ch;
1142    int lastCh = 0;
1143
1144    ch = read();
1145    if (ch != '<') {
1146    }
1147    else if ((ch = read()) != '%')
1148      _value.append('<');
1149    else if ((ch = read()) != '=')
1150      _value.append("<%");
1151    else {
1152      _value.append("<%");
1153      isRuntimeAttribute = true;
1154    }
1155
1156    while (ch != -1 && (ch != end || isRuntimeAttribute)) {
1157      if (ch == '\\') {
1158        switch ((ch = read())) {
1159        case '\\':
1160        case '\'':
1161        case '\"':
1162      // jsp/1505 vs jsp/184s
1163
// _value.append('\\');
1164
_value.append((char) ch);
1165          ch = read();
1166          break;
1167
1168        case '>':
1169          if (lastCh == '%') {
1170            _value.append('>');
1171            ch = read();
1172          }
1173          else
1174            _value.append('\\');
1175          break;
1176
1177        case '%':
1178          if (lastCh == '<') {
1179            _value.append('%');
1180            ch = read();
1181          }
1182          else
1183            _value.append('\\');
1184          break;
1185
1186        default:
1187          _value.append('\\');
1188          break;
1189        }
1190      }
1191      else if (ch == '%' && isRuntimeAttribute) {
1192        _value.append('%');
1193        ch = read();
1194        if (ch == '>')
1195          isRuntimeAttribute = false;
1196      }
1197      else if (ch == '&' && isXml) {
1198        lastCh = -1;
1199        _value.append((char) parseEntity());
1200        ch = read();
1201      }
1202      else if (ch == '&') {
1203        if ((ch = read()) == 'a') {
1204          if ((ch = read()) != 'p')
1205            _value.append("&a");
1206          else if ((ch = read()) != 'o')
1207            _value.append("&ap");
1208          else if ((ch = read()) != 's')
1209            _value.append("&apo");
1210          else if ((ch = read()) != ';')
1211            _value.append("&apos");
1212          else {
1213            _value.append('\'');
1214            ch = read();
1215          }
1216        }
1217        else if (ch == 'q') {
1218          if ((ch = read()) != 'u')
1219            _value.append("&q");
1220          else if ((ch = read()) != 'o')
1221            _value.append("&qu");
1222          else if ((ch = read()) != 't')
1223            _value.append("&quo");
1224          else if ((ch = read()) != ';')
1225            _value.append("&quot");
1226          else {
1227            _value.append('"');
1228            ch = read();
1229          }
1230        }
1231        else
1232          _value.append('&');
1233      }
1234      else {
1235        _value.append((char) ch);
1236        lastCh = ch;
1237        ch = read();
1238      }
1239    }
1240  }
1241
1242  /**
1243   * Parses an XML entity.
1244   */

1245  int parseEntity()
1246    throws IOException JavaDoc, JspParseException
1247  {
1248    int ch = read();
1249
1250    if (_isXml && ch == '#') {
1251      int value = 0;
1252
1253      for (ch = read(); ch >= '0' && ch <= '9'; ch = read())
1254        value = 10 * value + ch - '0';
1255
1256      if (ch != ';')
1257        throw error(L.l("expected ';' at '{0}' in character entity. The XML character entities syntax is &#nn;",
1258                        badChar(ch)));
1259
1260      return (char) value;
1261    }
1262
1263    CharBuffer cb = CharBuffer.allocate();
1264    for (; ch >= 'a' && ch <= 'z'; ch = read())
1265      cb.append((char) ch);
1266
1267    if (ch != ';') {
1268      
1269      log.warning(L.l("expected ';' at '{0}' in entity '&{1}'. The XML entity syntax is &name;",
1270                      badChar(ch), cb));
1271    }
1272
1273    String JavaDoc entity = cb.close();
1274    if (entity.equals("lt"))
1275      return '<';
1276    else if (entity.equals("gt"))
1277      return '>';
1278    else if (entity.equals("amp"))
1279      return '&';
1280    else if (entity.equals("apos"))
1281      return '\'';
1282    else if (entity.equals("quot"))
1283      return '"';
1284    else
1285      throw error(L.l("unknown entity '&{0};'. XML only recognizes the special entities &lt;, &gt;, &amp;, &apos; and &quot;", entity));
1286  }
1287
1288  private int parseCloseTag()
1289    throws IOException JavaDoc, JspParseException
1290  {
1291    int ch;
1292
1293    if (! XmlChar.isNameStart(ch = read())) {
1294      addText("</");
1295      return ch;
1296    }
1297    
1298    ch = readName(ch);
1299    String JavaDoc name = _tag.toString();
1300    if (! _isXml && getTag(name) == TAG_UNKNOWN) {
1301      addText("</");
1302      addText(name);
1303      return ch;
1304    }
1305
1306    ch = skipWhitespace(ch);
1307    if (ch != '>')
1308      throw error(L.l("expected '>' at {0}. The XML close tag syntax is </name>.", badChar(ch)));
1309
1310    JspNode node = _jspBuilder.getCurrentNode();
1311    String JavaDoc nodeName = node.getTagName();
1312    if (nodeName.equals(name)) {
1313    }
1314    else if (nodeName.equals("resin-c:when")) {
1315      throw error(L.l("#if expects closing #end before </{0}> (#if at {1}). #if statements require #end before the enclosing tag closes.",
1316                      name, String.valueOf(node.getStartLine())));
1317    }
1318    else if (nodeName.equals("resin-c:otherwise")) {
1319      throw error(L.l("#else expects closing #end before </{0}> (#else at {1}). #if statements require #end before the enclosing tag closes.",
1320                      name, String.valueOf(node.getStartLine())));
1321    }
1322    else {
1323      throw error(L.l("expected </{0}> at </{1}>. Closing tags must match opened tags.",
1324                      nodeName, name));
1325    }
1326
1327    addText();
1328
1329    setLocation();
1330    _jspBuilder.endElement(name);
1331
1332    return read();
1333  }
1334
1335  private void processTaglibDirective(ArrayList JavaDoc<QName> keys,
1336                                      ArrayList JavaDoc<String JavaDoc> values)
1337    throws IOException JavaDoc, JspParseException
1338  {
1339    int p = keys.indexOf(PREFIX);
1340    if (p < 0)
1341      throw error(L.l("The taglib directive requires a 'prefix' attribute. 'prefix' is the XML prefix for all tags in the taglib."));
1342    String JavaDoc prefix = values.get(p);
1343
1344    if (_prefixes.contains(prefix))
1345      throw error(L.l("The taglib prefix '{0}' must be defined before any matching prefixes are used.",
1346              prefix));
1347
1348    String JavaDoc uri = null;
1349    p = keys.indexOf(URI);
1350    if (p >= 0)
1351      uri = values.get(p);
1352    
1353    String JavaDoc tagdir = null;
1354    p = keys.indexOf(TAGDIR);
1355    if (p >= 0)
1356      tagdir = values.get(p);
1357    
1358    if (uri != null)
1359      processTaglib(prefix, uri);
1360    else if (tagdir != null)
1361      processTaglibDir(prefix, tagdir);
1362  }
1363
1364  /**
1365   * Adds a new known taglib prefix to the current namespace.
1366   */

1367  private void processTaglib(String JavaDoc prefix, String JavaDoc uri)
1368    throws JspParseException
1369  {
1370    Taglib taglib = null;
1371    
1372    int colon = uri.indexOf(':');
1373    int slash = uri.indexOf('/');
1374
1375    String JavaDoc location = null;
1376
1377    if (colon > 0 && colon < slash)
1378      location = uri;
1379    else if (slash == 0)
1380      location = uri;
1381    else
1382      location = _uriPwd + uri;
1383
1384    try {
1385      taglib = _tagManager.addTaglib(prefix, uri, location);
1386      String JavaDoc tldURI = "urn:jsptld:" + uri;
1387
1388      _parseState.pushNamespace(prefix, tldURI);
1389      _namespaces = new Namespace(_namespaces, prefix, tldURI);
1390      return;
1391    } catch (JspParseException e) {
1392      throw error(e);
1393    } catch (Exception JavaDoc e) {
1394      log.log(Level.WARNING, e.toString(), e);
1395    }
1396
1397    if (colon > 0 && colon < slash)
1398      throw error(L.l("Unknown taglib '{0}'. Taglibs specified with an absolute URI must either be:\n1) specified in the web.xml\n2) defined in a jar's .tld in META-INF\n3) defined in a .tld in WEB-INF\n4) predefined by Resin",
1399                      uri));
1400  }
1401
1402  /**
1403   * Adds a new known tag dir to the current namespace.
1404   */

1405  private void processTaglibDir(String JavaDoc prefix, String JavaDoc tagDir)
1406    throws JspParseException
1407  {
1408    Taglib taglib = null;
1409    
1410    try {
1411      taglib = _tagManager.addTaglibDir(prefix, tagDir);
1412      String JavaDoc tagURI = "urn:jsptagdir:" + tagDir;
1413      _parseState.pushNamespace(prefix, tagURI);
1414      _namespaces = new Namespace(_namespaces, prefix, tagURI);
1415      return;
1416    } catch (JspParseException e) {
1417      throw error(e);
1418    } catch (Exception JavaDoc e) {
1419      log.log(Level.WARNING, e.toString(), e);
1420    }
1421  }
1422
1423  private void processIncludeDirective(ArrayList JavaDoc keys, ArrayList JavaDoc values)
1424    throws IOException JavaDoc, JspParseException
1425  {
1426    int p = keys.indexOf("file");
1427    if (p < 0)
1428      throw error(L.l("The include directive requires a 'file' attribute."));
1429    String JavaDoc file = (String JavaDoc) values.get(p);
1430
1431    pushInclude(file);
1432  }
1433
1434  public void pushInclude(String JavaDoc value)
1435    throws IOException JavaDoc, JspParseException
1436  {
1437    pushInclude(value, false);
1438  }
1439  
1440  public void pushInclude(String JavaDoc value, boolean allowDuplicate)
1441    throws IOException JavaDoc, JspParseException
1442  {
1443    if (value.equals(""))
1444      throw error("include directive needs 'file' attribute. Use either <%@ include file='myfile.jsp' %> or <jsp:directive.include file='myfile.jsp'/>");
1445
1446    Path include;
1447    if (value.length() > 0 && value.charAt(0) == '/')
1448      include = _parseState.resolvePath(value);
1449    else
1450      include = _parseState.resolvePath(_uriPwd + value);
1451
1452    String JavaDoc newUrl = _uriPwd;
1453
1454    if (value.startsWith("/"))
1455      newUrl = value;
1456    else
1457      newUrl = _uriPwd + value;
1458    
1459    include.setUserPath(newUrl);
1460
1461    String JavaDoc newUrlPwd;
1462    int p = newUrl.lastIndexOf('/');
1463    newUrlPwd = newUrl.substring(0, p + 1);
1464    
1465    if (_jspPath != null && _jspPath.equals(include) && ! allowDuplicate)
1466      throw error(L.l("circular include of '{0}' forbidden. A JSP file may not include itself.", include));
1467    for (int i = 0; i < _includes.size(); i++) {
1468      Include inc = _includes.get(i);
1469      if (inc._stream.getPath().equals(include) && ! allowDuplicate)
1470    throw error(L.l("circular include of '{0}'. A JSP file may not include itself.", include));
1471    }
1472
1473    try {
1474      addInclude(include.openRead(), newUrlPwd);
1475    } catch (IOException JavaDoc e) {
1476      log.log(Level.WARNING, e.toString(), e);
1477
1478      if (include.exists())
1479        throw error(L.l("can't open include of '{0}'. '{1}' exists but it's not readable.",
1480                        value, include.getNativePath()));
1481      else
1482        throw error(L.l("can't open include of '{0}'. '{1}' does not exist.",
1483                        value, include.getNativePath()));
1484    }
1485  }
1486
1487  private void addInclude(ReadStream stream, String JavaDoc newUrlPwd)
1488    throws IOException JavaDoc, JspParseException
1489  {
1490    addText();
1491
1492    readLf();
1493
1494    Include inc = null;
1495
1496    if (_stream != null) {
1497      inc = new Include(_stream, _line, _uriPwd);
1498    
1499      _includes.add(inc);
1500    }
1501
1502    _parseState.addDepend(stream.getPath());
1503
1504    try {
1505      String JavaDoc encoding = _stream.getEncoding();
1506      if (encoding != null)
1507    stream.setEncoding(encoding);
1508    } catch (Exception JavaDoc e) {
1509    }
1510    _stream = stream;
1511
1512    _filename = stream.getUserPath();
1513    _jspPath = stream.getPath();
1514    _line = 1;
1515    _lineStart = _line;
1516    _uriPwd = newUrlPwd;
1517    _parseState.setUriPwd(_uriPwd);
1518  }
1519
1520  /**
1521   * Skips whitespace characters.
1522   *
1523   * @param ch the current character
1524   *
1525   * @return the first non-whitespace character
1526   */

1527  private int skipWhitespace(int ch)
1528    throws IOException JavaDoc, JspParseException
1529  {
1530    for (; XmlChar.isWhitespace(ch); ch = read()) {
1531    }
1532    
1533    return ch;
1534  }
1535
1536  /**
1537   * Skips whitespace to end of line
1538   *
1539   * @param ch the current character
1540   *
1541   * @return the first non-whitespace character
1542   */

1543  private int skipWhitespaceToEndOfLine(int ch)
1544    throws IOException JavaDoc, JspParseException
1545  {
1546    for (; XmlChar.isWhitespace(ch); ch = read()) {
1547      if (ch == '\n')
1548        return read();
1549      else if (ch == '\r') {
1550        ch = read();
1551        if (ch == '\n')
1552          return read();
1553        else
1554          return ch;
1555      }
1556    }
1557    
1558    return ch;
1559  }
1560
1561  private void addText(char ch)
1562  {
1563    _text.append(ch);
1564  }
1565
1566  private void addText(String JavaDoc s)
1567  {
1568    _text.append(s);
1569  }
1570
1571  private void addText()
1572    throws JspParseException
1573  {
1574    if (_text.length() > 0)
1575      createText();
1576    
1577    _startText = _charCount;
1578    _lineStart = _line;
1579  }
1580
1581  private void createText()
1582    throws JspParseException
1583  {
1584    String JavaDoc string = _text.toString();
1585
1586    setLocation(_jspPath, _filename, _lineStart);
1587
1588    if (_parseState.isTrimWhitespace() && isWhitespace(string)) {
1589    }
1590    else
1591      _jspBuilder.text(string, _filename, _lineStart, _line);
1592    
1593    _lineStart = _line;
1594    _text.clear();
1595    _startText = _charCount;
1596  }
1597
1598  private boolean isWhitespace(String JavaDoc s)
1599  {
1600    int length = s.length();
1601
1602    for (int i = 0; i < length; i++) {
1603      if (! Character.isWhitespace(s.charAt(i)))
1604    return false;
1605    }
1606
1607    return true;
1608  }
1609  
1610
1611  /**
1612   * Checks to see if the element name represents a tag.
1613   */

1614  private int getTag(String JavaDoc name)
1615    throws JspParseException
1616  {
1617    int p = name.indexOf(':');
1618    if (p < 0)
1619      return TAG_UNKNOWN;
1620
1621    String JavaDoc prefix = name.substring(0, p);
1622    String JavaDoc local = name.substring(p + 1);
1623    
1624    _prefixes.add(prefix);
1625
1626    String JavaDoc url = Namespace.find(_namespaces, prefix);
1627
1628    if (url != null)
1629      return TAG_JSP;
1630    else
1631      return TAG_UNKNOWN;
1632
1633    /*
1634    QName qname;
1635
1636    if (url != null)
1637      qname = new QName(prefix, local, url);
1638    else
1639      qname = new QName(prefix, local, null);
1640
1641    TagInfo tag = _tagManager.getTag(qname);
1642
1643    if (tag != null)
1644      return TAG_JSP;
1645    else
1646      return TAG_UNKNOWN;
1647    */

1648  }
1649
1650  private void unread(int ch)
1651  {
1652    _peek = ch;
1653  }
1654  
1655  /**
1656   * Reads the next character we're in the middle of cr/lf.
1657   */

1658  private void readLf() throws IOException JavaDoc, JspParseException
1659  {
1660    if (_seenCr) {
1661      int ch = read();
1662
1663      if (ch != '\n')
1664    _peek = ch;
1665    }
1666  }
1667  
1668  /**
1669   * Reads the next character.
1670   */

1671  private int read() throws IOException JavaDoc, JspParseException
1672  {
1673    int ch;
1674
1675    if (_peek >= 0) {
1676      ch = _peek;
1677      _peek = -1;
1678      return ch;
1679    }
1680
1681    try {
1682      if ((ch = _stream.readChar()) >= 0) {
1683        _charCount++;
1684        
1685        if (ch == '\r') {
1686          _line++;
1687          _charCount = 0;
1688          _seenCr = true;
1689        }
1690        else if (ch == '\n' && _seenCr) {
1691          _seenCr = false;
1692          _charCount = 0;
1693    }
1694        else if (ch == '\n') {
1695          _line++;
1696          _charCount = 0;
1697        }
1698        else {
1699          _seenCr = false;
1700    }
1701
1702        return ch;
1703      }
1704    } catch (IOException JavaDoc e) {
1705      throw error(e.toString());
1706    }
1707
1708    _stream.close();
1709    _seenCr = false;
1710    
1711    if (_includes.size() > 0) {
1712      setLocation(_jspPath, _filename, _line);
1713      
1714      Include include = _includes.get(_includes.size() - 1);
1715      _includes.remove(_includes.size() - 1);
1716
1717      _stream = include._stream;
1718      _filename = _stream.getUserPath();
1719      _jspPath = _stream.getPath();
1720      _line = include._line;
1721      _lineStart = _line;
1722      _uriPwd = include._uriPwd;
1723      _parseState.setUriPwd(_uriPwd);
1724
1725      setLocation(_jspPath, _filename, _line);
1726      
1727      return read();
1728    }
1729
1730    return -1;
1731  }
1732
1733  void clear(Path appDir, String JavaDoc errorPage)
1734  {
1735  }
1736
1737  /**
1738   * Creates an error message adding the filename and line.
1739   *
1740   * @param message the error message
1741   */

1742  public JspParseException error(Exception JavaDoc e)
1743  {
1744    String JavaDoc message = e.getMessage();
1745
1746    if (e instanceof JspParseException) {
1747      log.log(Level.FINE, e.toString(), e);
1748    }
1749
1750    if (e instanceof JspLineParseException)
1751      return (JspLineParseException) e;
1752    else if (e instanceof LineCompileException)
1753      return new JspLineParseException(e);
1754
1755    if (_lineMap == null)
1756      return new JspLineParseException(_filename + ":" + _line + ": " + message,
1757                       e);
1758    else {
1759      LineMap.Line line = _lineMap.getLine(_line);
1760      
1761      return new JspLineParseException(line.getSourceFilename() + ":" +
1762                       line.getSourceLine(_line) + ": " +
1763                       message,
1764                       e);
1765    }
1766  }
1767
1768  /**
1769   * Creates an error message adding the filename and line.
1770   *
1771   * @param message the error message
1772   */

1773  public JspParseException error(String JavaDoc message)
1774  {
1775    JspGenerator gen = _jspBuilder.getGenerator();
1776    
1777    if (_lineMap == null) {
1778      if (gen != null)
1779    return new JspLineParseException(_filename + ":" + _line + ": " + message + gen.getSourceLines(_jspPath, _line));
1780      else
1781    return new JspLineParseException(_filename + ":" + _line + ": " + message);
1782    }
1783    else {
1784      LineMap.Line line = _lineMap.getLine(_line);
1785      
1786      return new JspLineParseException(line.getSourceFilename() + ":" +
1787                       line.getSourceLine(_line) + ": " +
1788                       message);
1789    }
1790  }
1791
1792  /**
1793   * Creates an error message adding the filename and line.
1794   *
1795   * @param message the error message
1796   */

1797  public JspParseException error(String JavaDoc message, Throwable JavaDoc e)
1798  {
1799    if (_lineMap == null)
1800      return new JspLineParseException(_filename + ":" + _line + ": " + message, e);
1801    else {
1802      LineMap.Line line = _lineMap.getLine(_line);
1803      
1804      return new JspLineParseException(line.getSourceFilename() + ":" +
1805                       line.getSourceLine(_line) + ": " +
1806                       message,
1807                       e);
1808    }
1809  }
1810
1811  /**
1812   * Sets the current location in the original file
1813   */

1814  private void setLocation()
1815  {
1816    setLocation(_jspPath, _filename, _line);
1817  }
1818
1819  /**
1820   * Sets the current location in the original file
1821   *
1822   * @param filename the filename
1823   * @param line the line in the source file
1824   */

1825  private void setLocation(Path jspPath, String JavaDoc filename, int line)
1826  {
1827    if (_lineMap == null) {
1828      _jspBuilder.setLocation(jspPath, filename, line);
1829    }
1830    else {
1831      LineMap.Line srcLine = _lineMap.getLine(line);
1832
1833      if (srcLine != null) {
1834        _jspBuilder.setLocation(jspPath,
1835                srcLine.getSourceFilename(),
1836                                srcLine.getSourceLine(line));
1837      }
1838    }
1839  }
1840
1841  private String JavaDoc badChar(int ch)
1842  {
1843    if (ch < 0)
1844      return "end of file";
1845    else if (ch == '\n' || ch == '\r')
1846      return "end of line";
1847    else if (ch >= 0x20 && ch <= 0x7f)
1848      return "'" + (char) ch + "'";
1849    else
1850      return "'" + (char) ch + "' (\\u" + hex(ch) + ")";
1851  }
1852
1853  private String JavaDoc hex(int value)
1854  {
1855    CharBuffer cb = new CharBuffer();
1856
1857    for (int b = 3; b >= 0; b--) {
1858      int v = (value >> (4 * b)) & 0xf;
1859      if (v < 10)
1860    cb.append((char) (v + '0'));
1861      else
1862    cb.append((char) (v - 10 + 'a'));
1863    }
1864
1865    return cb.toString();
1866  }
1867
1868  class Include {
1869    ReadStream _stream;
1870    int _line;
1871    String JavaDoc _uriPwd;
1872
1873    Include(ReadStream stream, int line, String JavaDoc uriPwd)
1874    {
1875      _stream = stream;
1876      _line = line;
1877      _uriPwd = uriPwd;
1878    }
1879  }
1880}
1881
Popular Tags