1
17 package org.apache.jasper.compiler;
18
19 import java.io.BufferedInputStream;
20 import java.io.FileNotFoundException;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.InputStreamReader;
24 import java.io.UnsupportedEncodingException;
25 import java.util.ArrayList;
26
27 import org.apache.jasper.Constants;
28 import org.apache.jasper.JasperException;
29 import org.apache.jasper.JspCompilationContext;
30 import org.apache.tomcat.Jar;
31 import org.apache.tomcat.util.security.Escape;
32 import org.xml.sax.Attributes;
33 import org.xml.sax.InputSource;
34
35
46 public class JspUtil {
47
48 private static final String WEB_INF_TAGS = "/WEB-INF/tags/";
49 private static final String META_INF_TAGS = "/META-INF/tags/";
50
51
52 private static final String OPEN_EXPR = "<%=";
53 private static final String CLOSE_EXPR = "%>";
54
55 private static final String javaKeywords[] = { "abstract", "assert",
56 "boolean", "break", "byte", "case", "catch", "char", "class",
57 "const", "continue", "default", "do", "double", "else", "enum",
58 "extends", "final", "finally", "float", "for", "goto", "if",
59 "implements", "import", "instanceof", "int", "interface", "long",
60 "native", "new", "package", "private", "protected", "public",
61 "return", "short", "static", "strictfp", "super", "switch",
62 "synchronized", "this", "throw", "throws", "transient", "try",
63 "void", "volatile", "while" };
64
65 static final int JSP_INPUT_STREAM_BUFFER_SIZE = 1024;
66
67 public static final int CHUNKSIZE = 1024;
68
69
74 public static String getExprInXml(String expression) {
75 String returnString;
76 int length = expression.length();
77
78 if (expression.startsWith(OPEN_EXPR) &&
79 expression.endsWith(CLOSE_EXPR)) {
80 returnString = expression.substring(1, length - 1);
81 } else {
82 returnString = expression;
83 }
84
85 return Escape.xml(returnString);
86 }
87
88
104 public static void checkScope(String scope, Node n, ErrorDispatcher err)
105 throws JasperException {
106 if (scope != null && !scope.equals("page") && !scope.equals("request")
107 && !scope.equals("session") && !scope.equals("application")) {
108 err.jspError(n, "jsp.error.invalid.scope", scope);
109 }
110 }
111
112
123 public static void checkAttributes(String typeOfTag, Node n,
124 ValidAttribute[] validAttributes, ErrorDispatcher err)
125 throws JasperException {
126 Attributes attrs = n.getAttributes();
127 Mark start = n.getStart();
128 boolean valid = true;
129
130
131 int tempLength = (attrs == null) ? 0 : attrs.getLength();
132 ArrayList<String> temp = new ArrayList<>(tempLength);
133 for (int i = 0; i < tempLength; i++) {
134 @SuppressWarnings("null")
135 String qName = attrs.getQName(i);
136 if ((!qName.equals("xmlns")) && (!qName.startsWith("xmlns:"))) {
137 temp.add(qName);
138 }
139 }
140
141
142 Node.Nodes tagBody = n.getBody();
143 if (tagBody != null) {
144 int numSubElements = tagBody.size();
145 for (int i = 0; i < numSubElements; i++) {
146 Node node = tagBody.getNode(i);
147 if (node instanceof Node.NamedAttribute) {
148 String attrName = node.getAttributeValue("name");
149 temp.add(attrName);
150
151 if (n.getAttributeValue(attrName) != null) {
152 err.jspError(n,
153 "jsp.error.duplicate.name.jspattribute",
154 attrName);
155 }
156 } else {
157
158
159 break;
160 }
161 }
162 }
163
164
169 String missingAttribute = null;
170
171 for (int i = 0; i < validAttributes.length; i++) {
172 int attrPos;
173 if (validAttributes[i].mandatory) {
174 attrPos = temp.indexOf(validAttributes[i].name);
175 if (attrPos != -1) {
176 temp.remove(attrPos);
177 valid = true;
178 } else {
179 valid = false;
180 missingAttribute = validAttributes[i].name;
181 break;
182 }
183 }
184 }
185
186
187 if (!valid) {
188 err.jspError(start, "jsp.error.mandatory.attribute", typeOfTag,
189 missingAttribute);
190 }
191
192
193 int attrLeftLength = temp.size();
194 if (attrLeftLength == 0) {
195 return;
196 }
197
198
199 for(String attribute : temp) {
200 valid = false;
201 for (int i = 0; i < validAttributes.length; i++) {
202 if (attribute.equals(validAttributes[i].name)) {
203 valid = true;
204 break;
205 }
206 }
207 if (!valid) {
208 err.jspError(start, "jsp.error.invalid.attribute", typeOfTag,
209 attribute);
210 }
211 }
212
213 }
214
215 public static class ValidAttribute {
216
217 private final String name;
218 private final boolean mandatory;
219
220 public ValidAttribute(String name, boolean mandatory) {
221 this.name = name;
222 this.mandatory = mandatory;
223 }
224
225 public ValidAttribute(String name) {
226 this(name, false);
227 }
228 }
229
230
239 public static boolean booleanValue(String s) {
240 boolean b = false;
241 if (s != null) {
242 if (s.equalsIgnoreCase("yes")) {
243 b = true;
244 } else {
245 b = Boolean.parseBoolean(s);
246 }
247 }
248 return b;
249 }
250
251
266 public static Class<?> toClass(String type, ClassLoader loader)
267 throws ClassNotFoundException {
268
269 Class<?> c = null;
270 int i0 = type.indexOf('[');
271 int dims = 0;
272 if (i0 > 0) {
273
274 for (int i = 0; i < type.length(); i++) {
275 if (type.charAt(i) == '[') {
276 dims++;
277 }
278 }
279 type = type.substring(0, i0);
280 }
281
282 if ("boolean".equals(type)) {
283 c = boolean.class;
284 } else if ("char".equals(type)) {
285 c = char.class;
286 } else if ("byte".equals(type)) {
287 c = byte.class;
288 } else if ("short".equals(type)) {
289 c = short.class;
290 } else if ("int".equals(type)) {
291 c = int.class;
292 } else if ("long".equals(type)) {
293 c = long.class;
294 } else if ("float".equals(type)) {
295 c = float.class;
296 } else if ("double".equals(type)) {
297 c = double.class;
298 } else if ("void".equals(type)) {
299 c = void.class;
300 } else {
301 c = loader.loadClass(type);
302 }
303
304 if (dims == 0) {
305 return c;
306 }
307
308 if (dims == 1) {
309 return java.lang.reflect.Array.newInstance(c, 1).getClass();
310 }
311
312
313 return java.lang.reflect.Array.newInstance(c, new int[dims]).getClass();
314 }
315
316
329 public static String interpreterCall(boolean isTagFile, String expression,
330 Class<?> expectedType, String fnmapvar) {
331
334 String jspCtxt = null;
335 if (isTagFile) {
336 jspCtxt = "this.getJspContext()";
337 } else {
338 jspCtxt = "_jspx_page_context";
339 }
340
341
345 String returnType = expectedType.getCanonicalName();
346 String targetType = returnType;
347 String primitiveConverterMethod = null;
348 if (expectedType.isPrimitive()) {
349 if (expectedType.equals(Boolean.TYPE)) {
350 returnType = Boolean.class.getName();
351 primitiveConverterMethod = "booleanValue";
352 } else if (expectedType.equals(Byte.TYPE)) {
353 returnType = Byte.class.getName();
354 primitiveConverterMethod = "byteValue";
355 } else if (expectedType.equals(Character.TYPE)) {
356 returnType = Character.class.getName();
357 primitiveConverterMethod = "charValue";
358 } else if (expectedType.equals(Short.TYPE)) {
359 returnType = Short.class.getName();
360 primitiveConverterMethod = "shortValue";
361 } else if (expectedType.equals(Integer.TYPE)) {
362 returnType = Integer.class.getName();
363 primitiveConverterMethod = "intValue";
364 } else if (expectedType.equals(Long.TYPE)) {
365 returnType = Long.class.getName();
366 primitiveConverterMethod = "longValue";
367 } else if (expectedType.equals(Float.TYPE)) {
368 returnType = Float.class.getName();
369 primitiveConverterMethod = "floatValue";
370 } else if (expectedType.equals(Double.TYPE)) {
371 returnType = Double.class.getName();
372 primitiveConverterMethod = "doubleValue";
373 }
374 }
375
376
379
380
381
382
383
384
385
386
387
388
389
390 targetType = toJavaSourceType(targetType);
391 StringBuilder call = new StringBuilder(
392 "("
393 + returnType
394 + ") "
395 + "org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate"
396 + "(" + Generator.quote(expression) + ", " + targetType
397 + ".class, " + "(javax.servlet.jsp.PageContext)" + jspCtxt + ", "
398 + fnmapvar + ")");
399
400
403 if (primitiveConverterMethod != null) {
404 call.insert(0, "(");
405 call.append(")." + primitiveConverterMethod + "()");
406 }
407
408 return call.toString();
409 }
410
411 public static String coerceToPrimitiveBoolean(String s,
412 boolean isNamedAttribute) {
413 if (isNamedAttribute) {
414 return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToBoolean("
415 + s + ")";
416 } else {
417 if (s == null || s.length() == 0) {
418 return "false";
419 } else {
420 return Boolean.valueOf(s).toString();
421 }
422 }
423 }
424
425 public static String coerceToBoolean(String s, boolean isNamedAttribute) {
426 if (isNamedAttribute) {
427 return "(java.lang.Boolean) org.apache.jasper.runtime.JspRuntimeLibrary.coerce("
428 + s + ", java.lang.Boolean.class)";
429 } else {
430 if (s == null || s.length() == 0) {
431 return "new java.lang.Boolean(false)";
432 } else {
433
434 return "new java.lang.Boolean(" + Boolean.valueOf(s).toString() + ")";
435 }
436 }
437 }
438
439 public static String coerceToPrimitiveByte(String s,
440 boolean isNamedAttribute) {
441 if (isNamedAttribute) {
442 return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToByte("
443 + s + ")";
444 } else {
445 if (s == null || s.length() == 0) {
446 return "(byte) 0";
447 } else {
448 return "((byte)" + Byte.valueOf(s).toString() + ")";
449 }
450 }
451 }
452
453 public static String coerceToByte(String s, boolean isNamedAttribute) {
454 if (isNamedAttribute) {
455 return "(java.lang.Byte) org.apache.jasper.runtime.JspRuntimeLibrary.coerce("
456 + s + ", java.lang.Byte.class)";
457 } else {
458 if (s == null || s.length() == 0) {
459 return "new java.lang.Byte((byte) 0)";
460 } else {
461
462 return "new java.lang.Byte((byte)" + Byte.valueOf(s).toString() + ")";
463 }
464 }
465 }
466
467 public static String coerceToChar(String s, boolean isNamedAttribute) {
468 if (isNamedAttribute) {
469 return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToChar("
470 + s + ")";
471 } else {
472 if (s == null || s.length() == 0) {
473 return "(char) 0";
474 } else {
475 char ch = s.charAt(0);
476
477 return "((char) " + (int) ch + ")";
478 }
479 }
480 }
481
482 public static String coerceToCharacter(String s, boolean isNamedAttribute) {
483 if (isNamedAttribute) {
484 return "(java.lang.Character) org.apache.jasper.runtime.JspRuntimeLibrary.coerce("
485 + s + ", java.lang.Character.class)";
486 } else {
487 if (s == null || s.length() == 0) {
488 return "new java.lang.Character((char) 0)";
489 } else {
490 char ch = s.charAt(0);
491
492 return "new java.lang.Character((char) " + (int) ch + ")";
493 }
494 }
495 }
496
497 public static String coerceToPrimitiveDouble(String s,
498 boolean isNamedAttribute) {
499 if (isNamedAttribute) {
500 return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToDouble("
501 + s + ")";
502 } else {
503 if (s == null || s.length() == 0) {
504 return "(double) 0";
505 } else {
506 return Double.valueOf(s).toString();
507 }
508 }
509 }
510
511 public static String coerceToDouble(String s, boolean isNamedAttribute) {
512 if (isNamedAttribute) {
513 return "(java.lang.Double) org.apache.jasper.runtime.JspRuntimeLibrary.coerce("
514 + s + ", Double.class)";
515 } else {
516 if (s == null || s.length() == 0) {
517 return "new java.lang.Double(0)";
518 } else {
519
520 return "new java.lang.Double(" + Double.valueOf(s).toString() + ")";
521 }
522 }
523 }
524
525 public static String coerceToPrimitiveFloat(String s,
526 boolean isNamedAttribute) {
527 if (isNamedAttribute) {
528 return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToFloat("
529 + s + ")";
530 } else {
531 if (s == null || s.length() == 0) {
532 return "(float) 0";
533 } else {
534 return Float.valueOf(s).toString() + "f";
535 }
536 }
537 }
538
539 public static String coerceToFloat(String s, boolean isNamedAttribute) {
540 if (isNamedAttribute) {
541 return "(java.lang.Float) org.apache.jasper.runtime.JspRuntimeLibrary.coerce("
542 + s + ", java.lang.Float.class)";
543 } else {
544 if (s == null || s.length() == 0) {
545 return "new java.lang.Float(0)";
546 } else {
547
548 return "new java.lang.Float(" + Float.valueOf(s).toString() + "f)";
549 }
550 }
551 }
552
553 public static String coerceToInt(String s, boolean isNamedAttribute) {
554 if (isNamedAttribute) {
555 return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToInt("
556 + s + ")";
557 } else {
558 if (s == null || s.length() == 0) {
559 return "0";
560 } else {
561 return Integer.valueOf(s).toString();
562 }
563 }
564 }
565
566 public static String coerceToInteger(String s, boolean isNamedAttribute) {
567 if (isNamedAttribute) {
568 return "(java.lang.Integer) org.apache.jasper.runtime.JspRuntimeLibrary.coerce("
569 + s + ", java.lang.Integer.class)";
570 } else {
571 if (s == null || s.length() == 0) {
572 return "new java.lang.Integer(0)";
573 } else {
574
575 return "new java.lang.Integer(" + Integer.valueOf(s).toString() + ")";
576 }
577 }
578 }
579
580 public static String coerceToPrimitiveShort(String s,
581 boolean isNamedAttribute) {
582 if (isNamedAttribute) {
583 return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToShort("
584 + s + ")";
585 } else {
586 if (s == null || s.length() == 0) {
587 return "(short) 0";
588 } else {
589 return "((short) " + Short.valueOf(s).toString() + ")";
590 }
591 }
592 }
593
594 public static String coerceToShort(String s, boolean isNamedAttribute) {
595 if (isNamedAttribute) {
596 return "(java.lang.Short) org.apache.jasper.runtime.JspRuntimeLibrary.coerce("
597 + s + ", java.lang.Short.class)";
598 } else {
599 if (s == null || s.length() == 0) {
600 return "new java.lang.Short((short) 0)";
601 } else {
602
603 return "new java.lang.Short(\"" + Short.valueOf(s).toString() + "\")";
604 }
605 }
606 }
607
608 public static String coerceToPrimitiveLong(String s,
609 boolean isNamedAttribute) {
610 if (isNamedAttribute) {
611 return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToLong("
612 + s + ")";
613 } else {
614 if (s == null || s.length() == 0) {
615 return "(long) 0";
616 } else {
617 return Long.valueOf(s).toString() + "l";
618 }
619 }
620 }
621
622 public static String coerceToLong(String s, boolean isNamedAttribute) {
623 if (isNamedAttribute) {
624 return "(java.lang.Long) org.apache.jasper.runtime.JspRuntimeLibrary.coerce("
625 + s + ", java.lang.Long.class)";
626 } else {
627 if (s == null || s.length() == 0) {
628 return "new java.lang.Long(0)";
629 } else {
630
631 return "new java.lang.Long(" + Long.valueOf(s).toString() + "l)";
632 }
633 }
634 }
635
636 public static BufferedInputStream getInputStream(String fname, Jar jar,
637 JspCompilationContext ctxt) throws IOException {
638
639 InputStream in = null;
640
641 if (jar != null) {
642 String jarEntryName = fname.substring(1, fname.length());
643 in = jar.getInputStream(jarEntryName);
644 } else {
645 in = ctxt.getResourceAsStream(fname);
646 }
647
648 if (in == null) {
649 throw new FileNotFoundException(Localizer.getMessage(
650 "jsp.error.file.not.found", fname));
651 }
652
653 return new BufferedInputStream(in, JspUtil.JSP_INPUT_STREAM_BUFFER_SIZE);
654 }
655
656 public static InputSource getInputSource(String fname, Jar jar, JspCompilationContext ctxt)
657 throws IOException {
658 InputSource source;
659 if (jar != null) {
660 String jarEntryName = fname.substring(1, fname.length());
661 source = new InputSource(jar.getInputStream(jarEntryName));
662 source.setSystemId(jar.getURL(jarEntryName));
663 } else {
664 source = new InputSource(ctxt.getResourceAsStream(fname));
665 source.setSystemId(ctxt.getResource(fname).toExternalForm());
666 }
667 return source;
668 }
669
670
682 public static String getTagHandlerClassName(String path, String urn,
683 ErrorDispatcher err) throws JasperException {
684
685
686 String className = null;
687 int begin = 0;
688 int index;
689
690 index = path.lastIndexOf(".tag");
691 if (index == -1) {
692 err.jspError("jsp.error.tagfile.badSuffix", path);
693 }
694
695
696
697
698
699
700
701
702
703
704
705 index = path.indexOf(WEB_INF_TAGS);
706 if (index != -1) {
707 className = Constants.TAG_FILE_PACKAGE_NAME + ".web.";
708 begin = index + WEB_INF_TAGS.length();
709 } else {
710 index = path.indexOf(META_INF_TAGS);
711 if (index != -1) {
712 className = getClassNameBase(urn);
713 begin = index + META_INF_TAGS.length();
714 } else {
715 err.jspError("jsp.error.tagfile.illegalPath", path);
716 }
717 }
718
719 className += makeJavaPackage(path.substring(begin));
720
721 return className;
722 }
723
724 private static String getClassNameBase(String urn) {
725 StringBuilder base =
726 new StringBuilder(Constants.TAG_FILE_PACKAGE_NAME + ".meta.");
727 if (urn != null) {
728 base.append(makeJavaPackage(urn));
729 base.append('.');
730 }
731 return base.toString();
732 }
733
734
742 public static final String makeJavaPackage(String path) {
743 String classNameComponents[] = path.split("/");
744 StringBuilder legalClassNames = new StringBuilder();
745 for (int i = 0; i < classNameComponents.length; i++) {
746 if (classNameComponents[i].length() > 0) {
747 if (legalClassNames.length() > 0) {
748 legalClassNames.append('.');
749 }
750 legalClassNames.append(makeJavaIdentifier(classNameComponents[i]));
751 }
752 }
753 return legalClassNames.toString();
754 }
755
756
764 public static final String makeJavaIdentifier(String identifier) {
765 return makeJavaIdentifier(identifier, true);
766 }
767
768
777 public static final String makeJavaIdentifierForAttribute(String identifier) {
778 return makeJavaIdentifier(identifier, false);
779 }
780
781
789 private static final String makeJavaIdentifier(String identifier,
790 boolean periodToUnderscore) {
791 StringBuilder modifiedIdentifier = new StringBuilder(identifier.length());
792 if (!Character.isJavaIdentifierStart(identifier.charAt(0))) {
793 modifiedIdentifier.append('_');
794 }
795 for (int i = 0; i < identifier.length(); i++) {
796 char ch = identifier.charAt(i);
797 if (Character.isJavaIdentifierPart(ch) &&
798 (ch != '_' || !periodToUnderscore)) {
799 modifiedIdentifier.append(ch);
800 } else if (ch == '.' && periodToUnderscore) {
801 modifiedIdentifier.append('_');
802 } else {
803 modifiedIdentifier.append(mangleChar(ch));
804 }
805 }
806 if (isJavaKeyword(modifiedIdentifier.toString())) {
807 modifiedIdentifier.append('_');
808 }
809 return modifiedIdentifier.toString();
810 }
811
812
817 public static final String mangleChar(char ch) {
818 char[] result = new char[5];
819 result[0] = '_';
820 result[1] = Character.forDigit((ch >> 12) & 0xf, 16);
821 result[2] = Character.forDigit((ch >> 8) & 0xf, 16);
822 result[3] = Character.forDigit((ch >> 4) & 0xf, 16);
823 result[4] = Character.forDigit(ch & 0xf, 16);
824 return new String(result);
825 }
826
827
832 public static boolean isJavaKeyword(String key) {
833 int i = 0;
834 int j = javaKeywords.length;
835 while (i < j) {
836 int k = (i + j) >>> 1;
837 int result = javaKeywords[k].compareTo(key);
838 if (result == 0) {
839 return true;
840 }
841 if (result < 0) {
842 i = k + 1;
843 } else {
844 j = k;
845 }
846 }
847 return false;
848 }
849
850 static InputStreamReader getReader(String fname, String encoding,
851 Jar jar, JspCompilationContext ctxt, ErrorDispatcher err)
852 throws JasperException, IOException {
853
854 return getReader(fname, encoding, jar, ctxt, err, 0);
855 }
856
857 static InputStreamReader getReader(String fname, String encoding,
858 Jar jar, JspCompilationContext ctxt, ErrorDispatcher err, int skip)
859 throws JasperException, IOException {
860
861 InputStreamReader reader = null;
862 InputStream in = getInputStream(fname, jar, ctxt);
863 try {
864 for (int i = 0; i < skip; i++) {
865 in.read();
866 }
867 } catch (IOException ioe) {
868 try {
869 in.close();
870 } catch (IOException e) {
871
872 }
873 throw ioe;
874 }
875 try {
876 reader = new InputStreamReader(in, encoding);
877 } catch (UnsupportedEncodingException ex) {
878 err.jspError("jsp.error.unsupported.encoding", encoding);
879 }
880
881 return reader;
882 }
883
884
892 public static String toJavaSourceTypeFromTld(String type) {
893 if (type == null || "void".equals(type)) {
894 return "java.lang.Void.TYPE";
895 }
896 return type + ".class";
897 }
898
899
906 public static String toJavaSourceType(String type) {
907
908 if (type.charAt(0) != '[') {
909 return type;
910 }
911
912 int dims = 1;
913 String t = null;
914 for (int i = 1; i < type.length(); i++) {
915 if (type.charAt(i) == '[') {
916 dims++;
917 } else {
918 switch (type.charAt(i)) {
919 case 'Z': t = "boolean"; break;
920 case 'B': t = "byte"; break;
921 case 'C': t = "char"; break;
922 case 'D': t = "double"; break;
923 case 'F': t = "float"; break;
924 case 'I': t = "int"; break;
925 case 'J': t = "long"; break;
926 case 'S': t = "short"; break;
927 case 'L': t = type.substring(i+1, type.indexOf(';')); break;
928 }
929 break;
930 }
931 }
932
933 if (t == null) {
934
935 throw new IllegalArgumentException(Localizer.getMessage("jsp.error.unable.getType", type));
936 }
937
938 StringBuilder resultType = new StringBuilder(t);
939 for (; dims > 0; dims--) {
940 resultType.append("[]");
941 }
942 return resultType.toString();
943 }
944 }
945