Wed, 23 Nov 2016 00:35:47 -0800
8170268: 8u121 L10n resource file update - msgdrop 20
Reviewed-by: coffeys
Contributed-by: li.jiang@oracle.com
1 /*
2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 package com.sun.tools.javadoc;
28 import java.util.Arrays;
29 import java.util.HashMap;
30 import java.util.HashSet;
31 import java.util.Locale;
32 import java.util.Map;
33 import java.util.Set;
35 import com.sun.tools.javadoc.JavaScriptScanner.TagParser.Kind;
37 import static com.sun.tools.javac.util.LayoutCharacters.EOI;
39 /**
40 * Parser to detect use of JavaScript in documentation comments.
41 */
42 @Deprecated
43 public class JavaScriptScanner {
44 public static interface Reporter {
45 void report();
46 }
48 static class ParseException extends Exception {
49 private static final long serialVersionUID = 0;
50 ParseException(String key) {
51 super(key);
52 }
53 }
55 private Reporter reporter;
57 /** The input buffer, index of most recent character read,
58 * index of one past last character in buffer.
59 */
60 protected char[] buf;
61 protected int bp;
62 protected int buflen;
64 /** The current character.
65 */
66 protected char ch;
68 private boolean newline = true;
70 Map<String, TagParser> tagParsers;
71 Set<String> eventAttrs;
72 Set<String> uriAttrs;
74 public JavaScriptScanner() {
75 initTagParsers();
76 initEventAttrs();
77 initURIAttrs();
78 }
80 public void parse(String comment, Reporter r) {
81 reporter = r;
82 String c = comment;
83 buf = new char[c.length() + 1];
84 c.getChars(0, c.length(), buf, 0);
85 buf[buf.length - 1] = EOI;
86 buflen = buf.length - 1;
87 bp = -1;
88 newline = true;
89 nextChar();
91 blockContent();
92 blockTags();
93 }
95 private void checkHtmlTag(String tag) {
96 if (tag.equalsIgnoreCase("script")) {
97 reporter.report();
98 }
99 }
101 private void checkHtmlAttr(String name, String value) {
102 String n = name.toLowerCase(Locale.ENGLISH);
103 if (eventAttrs.contains(n)
104 || uriAttrs.contains(n)
105 && value != null && value.toLowerCase(Locale.ENGLISH).trim().startsWith("javascript:")) {
106 reporter.report();
107 }
108 }
110 void nextChar() {
111 ch = buf[bp < buflen ? ++bp : buflen];
112 switch (ch) {
113 case '\f': case '\n': case '\r':
114 newline = true;
115 }
116 }
118 /**
119 * Read block content, consisting of text, html and inline tags.
120 * Terminated by the end of input, or the beginning of the next block tag:
121 * i.e. @ as the first non-whitespace character on a line.
122 */
123 @SuppressWarnings("fallthrough")
124 protected void blockContent() {
126 loop:
127 while (bp < buflen) {
128 switch (ch) {
129 case '\n': case '\r': case '\f':
130 newline = true;
131 // fallthrough
133 case ' ': case '\t':
134 nextChar();
135 break;
137 case '&':
138 entity(null);
139 break;
141 case '<':
142 html();
143 break;
145 case '>':
146 newline = false;
147 nextChar();
148 break;
150 case '{':
151 inlineTag(null);
152 break;
154 case '@':
155 if (newline) {
156 break loop;
157 }
158 // fallthrough
160 default:
161 newline = false;
162 nextChar();
163 }
164 }
165 }
167 /**
168 * Read a series of block tags, including their content.
169 * Standard tags parse their content appropriately.
170 * Non-standard tags are represented by {@link UnknownBlockTag}.
171 */
172 protected void blockTags() {
173 while (ch == '@')
174 blockTag();
175 }
177 /**
178 * Read a single block tag, including its content.
179 * Standard tags parse their content appropriately.
180 * Non-standard tags are represented by {@link UnknownBlockTag}.
181 */
182 protected void blockTag() {
183 int p = bp;
184 try {
185 nextChar();
186 if (isIdentifierStart(ch)) {
187 String name = readTagName();
188 TagParser tp = tagParsers.get(name);
189 if (tp == null) {
190 blockContent();
191 } else {
192 switch (tp.getKind()) {
193 case BLOCK:
194 tp.parse(p);
195 return;
196 case INLINE:
197 return;
198 }
199 }
200 }
201 blockContent();
202 } catch (ParseException e) {
203 blockContent();
204 }
205 }
207 protected void inlineTag(Void list) {
208 newline = false;
209 nextChar();
210 if (ch == '@') {
211 inlineTag();
212 }
213 }
215 /**
216 * Read a single inline tag, including its content.
217 * Standard tags parse their content appropriately.
218 * Non-standard tags are represented by {@link UnknownBlockTag}.
219 * Malformed tags may be returned as {@link Erroneous}.
220 */
221 protected void inlineTag() {
222 int p = bp - 1;
223 try {
224 nextChar();
225 if (isIdentifierStart(ch)) {
226 String name = readTagName();
227 TagParser tp = tagParsers.get(name);
229 if (tp == null) {
230 skipWhitespace();
231 inlineText(WhitespaceRetentionPolicy.REMOVE_ALL);
232 nextChar();
233 } else {
234 skipWhitespace();
235 if (tp.getKind() == TagParser.Kind.INLINE) {
236 tp.parse(p);
237 } else { // handle block tags (ex: @see) in inline content
238 inlineText(WhitespaceRetentionPolicy.REMOVE_ALL); // skip content
239 nextChar();
240 }
241 }
242 }
243 } catch (ParseException e) {
244 }
245 }
247 private static enum WhitespaceRetentionPolicy {
248 RETAIN_ALL,
249 REMOVE_FIRST_SPACE,
250 REMOVE_ALL
251 }
253 /**
254 * Read plain text content of an inline tag.
255 * Matching pairs of { } are skipped; the text is terminated by the first
256 * unmatched }. It is an error if the beginning of the next tag is detected.
257 */
258 private void inlineText(WhitespaceRetentionPolicy whitespacePolicy) throws ParseException {
259 switch (whitespacePolicy) {
260 case REMOVE_ALL:
261 skipWhitespace();
262 break;
263 case REMOVE_FIRST_SPACE:
264 if (ch == ' ')
265 nextChar();
266 break;
267 case RETAIN_ALL:
268 default:
269 // do nothing
270 break;
272 }
273 int pos = bp;
274 int depth = 1;
276 loop:
277 while (bp < buflen) {
278 switch (ch) {
279 case '\n': case '\r': case '\f':
280 newline = true;
281 break;
283 case ' ': case '\t':
284 break;
286 case '{':
287 newline = false;
288 depth++;
289 break;
291 case '}':
292 if (--depth == 0) {
293 return;
294 }
295 newline = false;
296 break;
298 case '@':
299 if (newline)
300 break loop;
301 newline = false;
302 break;
304 default:
305 newline = false;
306 break;
307 }
308 nextChar();
309 }
310 throw new ParseException("dc.unterminated.inline.tag");
311 }
313 /**
314 * Read Java class name, possibly followed by member
315 * Matching pairs of {@literal < >} are skipped. The text is terminated by the first
316 * unmatched }. It is an error if the beginning of the next tag is detected.
317 */
318 // TODO: boolean allowMember should be enum FORBID, ALLOW, REQUIRE
319 // TODO: improve quality of parse to forbid bad constructions.
320 // TODO: update to use ReferenceParser
321 @SuppressWarnings("fallthrough")
322 protected void reference(boolean allowMember) throws ParseException {
323 int pos = bp;
324 int depth = 0;
326 // scan to find the end of the signature, by looking for the first
327 // whitespace not enclosed in () or <>, or the end of the tag
328 loop:
329 while (bp < buflen) {
330 switch (ch) {
331 case '\n': case '\r': case '\f':
332 newline = true;
333 // fallthrough
335 case ' ': case '\t':
336 if (depth == 0)
337 break loop;
338 break;
340 case '(':
341 case '<':
342 newline = false;
343 depth++;
344 break;
346 case ')':
347 case '>':
348 newline = false;
349 --depth;
350 break;
352 case '}':
353 if (bp == pos)
354 return;
355 newline = false;
356 break loop;
358 case '@':
359 if (newline)
360 break loop;
361 // fallthrough
363 default:
364 newline = false;
366 }
367 nextChar();
368 }
370 if (depth != 0)
371 throw new ParseException("dc.unterminated.signature");
372 }
374 /**
375 * Read Java identifier
376 * Matching pairs of { } are skipped; the text is terminated by the first
377 * unmatched }. It is an error if the beginning of the next tag is detected.
378 */
379 @SuppressWarnings("fallthrough")
380 protected void identifier() throws ParseException {
381 skipWhitespace();
382 int pos = bp;
384 if (isJavaIdentifierStart(ch)) {
385 readJavaIdentifier();
386 return;
387 }
389 throw new ParseException("dc.identifier.expected");
390 }
392 /**
393 * Read a quoted string.
394 * It is an error if the beginning of the next tag is detected.
395 */
396 @SuppressWarnings("fallthrough")
397 protected void quotedString() {
398 int pos = bp;
399 nextChar();
401 loop:
402 while (bp < buflen) {
403 switch (ch) {
404 case '\n': case '\r': case '\f':
405 newline = true;
406 break;
408 case ' ': case '\t':
409 break;
411 case '"':
412 nextChar();
413 // trim trailing white-space?
414 return;
416 case '@':
417 if (newline)
418 break loop;
420 }
421 nextChar();
422 }
423 }
425 /**
426 * Read a term ie. one word.
427 * It is an error if the beginning of the next tag is detected.
428 */
429 @SuppressWarnings("fallthrough")
430 protected void inlineWord() {
431 int pos = bp;
432 int depth = 0;
433 loop:
434 while (bp < buflen) {
435 switch (ch) {
436 case '\n':
437 newline = true;
438 // fallthrough
440 case '\r': case '\f': case ' ': case '\t':
441 return;
443 case '@':
444 if (newline)
445 break loop;
447 case '{':
448 depth++;
449 break;
451 case '}':
452 if (depth == 0 || --depth == 0)
453 return;
454 break;
455 }
456 newline = false;
457 nextChar();
458 }
459 }
461 /**
462 * Read general text content of an inline tag, including HTML entities and elements.
463 * Matching pairs of { } are skipped; the text is terminated by the first
464 * unmatched }. It is an error if the beginning of the next tag is detected.
465 */
466 @SuppressWarnings("fallthrough")
467 private void inlineContent() {
469 skipWhitespace();
470 int pos = bp;
471 int depth = 1;
473 loop:
474 while (bp < buflen) {
476 switch (ch) {
477 case '\n': case '\r': case '\f':
478 newline = true;
479 // fall through
481 case ' ': case '\t':
482 nextChar();
483 break;
485 case '&':
486 entity(null);
487 break;
489 case '<':
490 newline = false;
491 html();
492 break;
494 case '{':
495 newline = false;
496 depth++;
497 nextChar();
498 break;
500 case '}':
501 newline = false;
502 if (--depth == 0) {
503 nextChar();
504 return;
505 }
506 nextChar();
507 break;
509 case '@':
510 if (newline)
511 break loop;
512 // fallthrough
514 default:
515 nextChar();
516 break;
517 }
518 }
520 }
522 protected void entity(Void list) {
523 newline = false;
524 entity();
525 }
527 /**
528 * Read an HTML entity.
529 * {@literal &identifier; } or {@literal &#digits; } or {@literal &#xhex-digits; }
530 */
531 protected void entity() {
532 nextChar();
533 String name = null;
534 if (ch == '#') {
535 int namep = bp;
536 nextChar();
537 if (isDecimalDigit(ch)) {
538 nextChar();
539 while (isDecimalDigit(ch))
540 nextChar();
541 name = new String(buf, namep, bp - namep);
542 } else if (ch == 'x' || ch == 'X') {
543 nextChar();
544 if (isHexDigit(ch)) {
545 nextChar();
546 while (isHexDigit(ch))
547 nextChar();
548 name = new String(buf, namep, bp - namep);
549 }
550 }
551 } else if (isIdentifierStart(ch)) {
552 name = readIdentifier();
553 }
555 if (name != null) {
556 if (ch != ';')
557 return;
558 nextChar();
559 }
560 }
562 /**
563 * Read the start or end of an HTML tag, or an HTML comment
564 * {@literal <identifier attrs> } or {@literal </identifier> }
565 */
566 protected void html() {
567 int p = bp;
568 nextChar();
569 if (isIdentifierStart(ch)) {
570 String name = readIdentifier();
571 checkHtmlTag(name);
572 htmlAttrs();
573 if (ch == '/') {
574 nextChar();
575 }
576 if (ch == '>') {
577 nextChar();
578 return;
579 }
580 } else if (ch == '/') {
581 nextChar();
582 if (isIdentifierStart(ch)) {
583 readIdentifier();
584 skipWhitespace();
585 if (ch == '>') {
586 nextChar();
587 return;
588 }
589 }
590 } else if (ch == '!') {
591 nextChar();
592 if (ch == '-') {
593 nextChar();
594 if (ch == '-') {
595 nextChar();
596 while (bp < buflen) {
597 int dash = 0;
598 while (ch == '-') {
599 dash++;
600 nextChar();
601 }
602 // Strictly speaking, a comment should not contain "--"
603 // so dash > 2 is an error, dash == 2 implies ch == '>'
604 // See http://www.w3.org/TR/html-markup/syntax.html#syntax-comments
605 // for more details.
606 if (dash >= 2 && ch == '>') {
607 nextChar();
608 return;
609 }
611 nextChar();
612 }
613 }
614 }
615 }
617 bp = p + 1;
618 ch = buf[bp];
619 }
621 /**
622 * Read a series of HTML attributes, terminated by {@literal > }.
623 * Each attribute is of the form {@literal identifier[=value] }.
624 * "value" may be unquoted, single-quoted, or double-quoted.
625 */
626 protected void htmlAttrs() {
627 skipWhitespace();
629 loop:
630 while (isIdentifierStart(ch)) {
631 int namePos = bp;
632 String name = readAttributeName();
633 skipWhitespace();
634 StringBuilder value = new StringBuilder();
635 if (ch == '=') {
636 nextChar();
637 skipWhitespace();
638 if (ch == '\'' || ch == '"') {
639 char quote = ch;
640 nextChar();
641 while (bp < buflen && ch != quote) {
642 if (newline && ch == '@') {
643 // No point trying to read more.
644 // In fact, all attrs get discarded by the caller
645 // and superseded by a malformed.html node because
646 // the html tag itself is not terminated correctly.
647 break loop;
648 }
649 value.append(ch);
650 nextChar();
651 }
652 nextChar();
653 } else {
654 while (bp < buflen && !isUnquotedAttrValueTerminator(ch)) {
655 value.append(ch);
656 nextChar();
657 }
658 }
659 skipWhitespace();
660 }
661 checkHtmlAttr(name, value.toString());
662 }
663 }
665 protected void attrValueChar(Void list) {
666 switch (ch) {
667 case '&':
668 entity(list);
669 break;
671 case '{':
672 inlineTag(list);
673 break;
675 default:
676 nextChar();
677 }
678 }
680 protected boolean isIdentifierStart(char ch) {
681 return Character.isUnicodeIdentifierStart(ch);
682 }
684 protected String readIdentifier() {
685 int start = bp;
686 nextChar();
687 while (bp < buflen && Character.isUnicodeIdentifierPart(ch))
688 nextChar();
689 return new String(buf, start, bp - start);
690 }
692 protected String readAttributeName() {
693 int start = bp;
694 nextChar();
695 while (bp < buflen && (Character.isUnicodeIdentifierPart(ch) || ch == '-'))
696 nextChar();
697 return new String(buf, start, bp - start);
698 }
700 protected String readTagName() {
701 int start = bp;
702 nextChar();
703 while (bp < buflen
704 && (Character.isUnicodeIdentifierPart(ch) || ch == '.'
705 || ch == '-' || ch == ':')) {
706 nextChar();
707 }
708 return new String(buf, start, bp - start);
709 }
711 protected boolean isJavaIdentifierStart(char ch) {
712 return Character.isJavaIdentifierStart(ch);
713 }
715 protected String readJavaIdentifier() {
716 int start = bp;
717 nextChar();
718 while (bp < buflen && Character.isJavaIdentifierPart(ch))
719 nextChar();
720 return new String(buf, start, bp - start);
721 }
723 protected boolean isDecimalDigit(char ch) {
724 return ('0' <= ch && ch <= '9');
725 }
727 protected boolean isHexDigit(char ch) {
728 return ('0' <= ch && ch <= '9')
729 || ('a' <= ch && ch <= 'f')
730 || ('A' <= ch && ch <= 'F');
731 }
733 protected boolean isUnquotedAttrValueTerminator(char ch) {
734 switch (ch) {
735 case '\f': case '\n': case '\r': case '\t':
736 case ' ':
737 case '"': case '\'': case '`':
738 case '=': case '<': case '>':
739 return true;
740 default:
741 return false;
742 }
743 }
745 protected boolean isWhitespace(char ch) {
746 return Character.isWhitespace(ch);
747 }
749 protected void skipWhitespace() {
750 while (isWhitespace(ch)) {
751 nextChar();
752 }
753 }
755 /**
756 * @param start position of first character of string
757 * @param end position of character beyond last character to be included
758 */
759 String newString(int start, int end) {
760 return new String(buf, start, end - start);
761 }
763 static abstract class TagParser {
764 enum Kind { INLINE, BLOCK }
766 final Kind kind;
767 final String name;
770 TagParser(Kind k, String tk) {
771 kind = k;
772 name = tk;
773 }
775 TagParser(Kind k, String tk, boolean retainWhiteSpace) {
776 this(k, tk);
777 }
779 Kind getKind() {
780 return kind;
781 }
783 String getName() {
784 return name;
785 }
787 abstract void parse(int pos) throws ParseException;
788 }
790 /**
791 * @see <a href="http://docs.oracle.com/javase/7/docs/technotes/tools/solaris/javadoc.html#javadoctags">Javadoc Tags</a>
792 */
793 @SuppressWarnings("deprecation")
794 private void initTagParsers() {
795 TagParser[] parsers = {
796 // @author name-text
797 new TagParser(Kind.BLOCK, "author") {
798 @Override
799 public void parse(int pos) {
800 blockContent();
801 }
802 },
804 // {@code text}
805 new TagParser(Kind.INLINE, "code", true) {
806 @Override
807 public void parse(int pos) throws ParseException {
808 inlineText(WhitespaceRetentionPolicy.REMOVE_FIRST_SPACE);
809 nextChar();
810 }
811 },
813 // @deprecated deprecated-text
814 new TagParser(Kind.BLOCK, "deprecated") {
815 @Override
816 public void parse(int pos) {
817 blockContent();
818 }
819 },
821 // {@docRoot}
822 new TagParser(Kind.INLINE, "docRoot") {
823 @Override
824 public void parse(int pos) throws ParseException {
825 if (ch == '}') {
826 nextChar();
827 return;
828 }
829 inlineText(WhitespaceRetentionPolicy.REMOVE_ALL); // skip unexpected content
830 nextChar();
831 throw new ParseException("dc.unexpected.content");
832 }
833 },
835 // @exception class-name description
836 new TagParser(Kind.BLOCK, "exception") {
837 @Override
838 public void parse(int pos) throws ParseException {
839 skipWhitespace();
840 reference(false);
841 blockContent();
842 }
843 },
845 // @hidden hidden-text
846 new TagParser(Kind.BLOCK, "hidden") {
847 @Override
848 public void parse(int pos) {
849 blockContent();
850 }
851 },
853 // @index search-term options-description
854 new TagParser(Kind.INLINE, "index") {
855 @Override
856 public void parse(int pos) throws ParseException {
857 skipWhitespace();
858 if (ch == '}') {
859 throw new ParseException("dc.no.content");
860 }
861 if (ch == '"') quotedString(); else inlineWord();
862 skipWhitespace();
863 if (ch != '}') {
864 inlineContent();
865 } else {
866 nextChar();
867 }
868 }
869 },
871 // {@inheritDoc}
872 new TagParser(Kind.INLINE, "inheritDoc") {
873 @Override
874 public void parse(int pos) throws ParseException {
875 if (ch == '}') {
876 nextChar();
877 return;
878 }
879 inlineText(WhitespaceRetentionPolicy.REMOVE_ALL); // skip unexpected content
880 nextChar();
881 throw new ParseException("dc.unexpected.content");
882 }
883 },
885 // {@link package.class#member label}
886 new TagParser(Kind.INLINE, "link") {
887 @Override
888 public void parse(int pos) throws ParseException {
889 reference(true);
890 inlineContent();
891 }
892 },
894 // {@linkplain package.class#member label}
895 new TagParser(Kind.INLINE, "linkplain") {
896 @Override
897 public void parse(int pos) throws ParseException {
898 reference(true);
899 inlineContent();
900 }
901 },
903 // {@literal text}
904 new TagParser(Kind.INLINE, "literal", true) {
905 @Override
906 public void parse(int pos) throws ParseException {
907 inlineText(WhitespaceRetentionPolicy.REMOVE_FIRST_SPACE);
908 nextChar();
909 }
910 },
912 // @param parameter-name description
913 new TagParser(Kind.BLOCK, "param") {
914 @Override
915 public void parse(int pos) throws ParseException {
916 skipWhitespace();
918 boolean typaram = false;
919 if (ch == '<') {
920 typaram = true;
921 nextChar();
922 }
924 identifier();
926 if (typaram) {
927 if (ch != '>')
928 throw new ParseException("dc.gt.expected");
929 nextChar();
930 }
932 skipWhitespace();
933 blockContent();
934 }
935 },
937 // @return description
938 new TagParser(Kind.BLOCK, "return") {
939 @Override
940 public void parse(int pos) {
941 blockContent();
942 }
943 },
945 // @see reference | quoted-string | HTML
946 new TagParser(Kind.BLOCK, "see") {
947 @Override
948 public void parse(int pos) throws ParseException {
949 skipWhitespace();
950 switch (ch) {
951 case '"':
952 quotedString();
953 skipWhitespace();
954 if (ch == '@'
955 || ch == EOI && bp == buf.length - 1) {
956 return;
957 }
958 break;
960 case '<':
961 blockContent();
962 return;
964 case '@':
965 if (newline)
966 throw new ParseException("dc.no.content");
967 break;
969 case EOI:
970 if (bp == buf.length - 1)
971 throw new ParseException("dc.no.content");
972 break;
974 default:
975 if (isJavaIdentifierStart(ch) || ch == '#') {
976 reference(true);
977 blockContent();
978 }
979 }
980 throw new ParseException("dc.unexpected.content");
981 }
982 },
984 // @serialData data-description
985 new TagParser(Kind.BLOCK, "@serialData") {
986 @Override
987 public void parse(int pos) {
988 blockContent();
989 }
990 },
992 // @serialField field-name field-type description
993 new TagParser(Kind.BLOCK, "serialField") {
994 @Override
995 public void parse(int pos) throws ParseException {
996 skipWhitespace();
997 identifier();
998 skipWhitespace();
999 reference(false);
1000 if (isWhitespace(ch)) {
1001 skipWhitespace();
1002 blockContent();
1003 }
1004 }
1005 },
1007 // @serial field-description | include | exclude
1008 new TagParser(Kind.BLOCK, "serial") {
1009 @Override
1010 public void parse(int pos) {
1011 blockContent();
1012 }
1013 },
1015 // @since since-text
1016 new TagParser(Kind.BLOCK, "since") {
1017 @Override
1018 public void parse(int pos) {
1019 blockContent();
1020 }
1021 },
1023 // @throws class-name description
1024 new TagParser(Kind.BLOCK, "throws") {
1025 @Override
1026 public void parse(int pos) throws ParseException {
1027 skipWhitespace();
1028 reference(false);
1029 blockContent();
1030 }
1031 },
1033 // {@value package.class#field}
1034 new TagParser(Kind.INLINE, "value") {
1035 @Override
1036 public void parse(int pos) throws ParseException {
1037 reference(true);
1038 skipWhitespace();
1039 if (ch == '}') {
1040 nextChar();
1041 return;
1042 }
1043 nextChar();
1044 throw new ParseException("dc.unexpected.content");
1045 }
1046 },
1048 // @version version-text
1049 new TagParser(Kind.BLOCK, "version") {
1050 @Override
1051 public void parse(int pos) {
1052 blockContent();
1053 }
1054 },
1055 };
1057 tagParsers = new HashMap<>();
1058 for (TagParser p: parsers)
1059 tagParsers.put(p.getName(), p);
1061 }
1063 private void initEventAttrs() {
1064 eventAttrs = new HashSet<>(Arrays.asList(
1065 // See https://www.w3.org/TR/html-markup/global-attributes.html#common.attrs.event-handler
1066 "onabort", "onblur", "oncanplay", "oncanplaythrough",
1067 "onchange", "onclick", "oncontextmenu", "ondblclick",
1068 "ondrag", "ondragend", "ondragenter", "ondragleave",
1069 "ondragover", "ondragstart", "ondrop", "ondurationchange",
1070 "onemptied", "onended", "onerror", "onfocus", "oninput",
1071 "oninvalid", "onkeydown", "onkeypress", "onkeyup",
1072 "onload", "onloadeddata", "onloadedmetadata", "onloadstart",
1073 "onmousedown", "onmousemove", "onmouseout", "onmouseover",
1074 "onmouseup", "onmousewheel", "onpause", "onplay",
1075 "onplaying", "onprogress", "onratechange", "onreadystatechange",
1076 "onreset", "onscroll", "onseeked", "onseeking",
1077 "onselect", "onshow", "onstalled", "onsubmit", "onsuspend",
1078 "ontimeupdate", "onvolumechange", "onwaiting",
1080 // See https://www.w3.org/TR/html4/sgml/dtd.html
1081 // Most of the attributes that take a %Script are also defined as event handlers
1082 // in HTML 5. The one exception is onunload.
1083 // "onchange", "onclick", "ondblclick", "onfocus",
1084 // "onkeydown", "onkeypress", "onkeyup", "onload",
1085 // "onmousedown", "onmousemove", "onmouseout", "onmouseover",
1086 // "onmouseup", "onreset", "onselect", "onsubmit",
1087 "onunload"
1088 ));
1089 }
1091 private void initURIAttrs() {
1092 uriAttrs = new HashSet<>(Arrays.asList(
1093 // See https://www.w3.org/TR/html4/sgml/dtd.html
1094 // https://www.w3.org/TR/html5/
1095 // These are all the attributes that take a %URI or a valid URL potentially surrounded
1096 // by spaces
1097 "action", "cite", "classid", "codebase", "data",
1098 "datasrc", "for", "href", "longdesc", "profile",
1099 "src", "usemap"
1100 ));
1101 }
1103 }