1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 package org.w3c.tidy;
55
56 import java.util.HashMap;
57 import java.util.Iterator;
58 import java.util.Map;
59
60
61 /**
62 * Check attribute values implementations.
63 * @author Dave Raggett <a href="mailto:dsr@w3.org">dsr@w3.org </a>
64 * @author Andy Quick <a href="mailto:ac.quick@sympatico.ca">ac.quick@sympatico.ca </a> (translation to Java)
65 * @author Fabrizio Giustina
66 * @version $Revision: 779 $ ($Author: fgiust $)
67 */
68 public final class AttrCheckImpl
69 {
70
71 /**
72 * checker for URLs.
73 */
74 public static final AttrCheck URL = new CheckUrl();
75
76 /**
77 * checker for scripts.
78 */
79 public static final AttrCheck SCRIPT = new CheckScript();
80
81 /**
82 * checker for "name" attribute.
83 */
84 public static final AttrCheck NAME = new CheckName();
85
86 /**
87 * checker for ids.
88 */
89 public static final AttrCheck ID = new CheckId();
90
91 /**
92 * checker for "align" attribute.
93 */
94 public static final AttrCheck ALIGN = new CheckAlign();
95
96 /**
97 * checker for "valign" attribute.
98 */
99 public static final AttrCheck VALIGN = new CheckValign();
100
101 /**
102 * checker for boolean attributes.
103 */
104 public static final AttrCheck BOOL = new CheckBool();
105
106 /**
107 * checker for "lenght" attribute.
108 */
109 public static final AttrCheck LENGTH = new CheckLength();
110
111 /**
112 * checker for "target" attribute.
113 */
114 public static final AttrCheck TARGET = new CheckTarget();
115
116 /**
117 * checker for "submit" attribute.
118 */
119 public static final AttrCheck FSUBMIT = new CheckFsubmit();
120
121 /**
122 * checker for "clear" attribute.
123 */
124 public static final AttrCheck CLEAR = new CheckClear();
125
126 /**
127 * checker for "shape" attribute.
128 */
129 public static final AttrCheck SHAPE = new CheckShape();
130
131 /**
132 * checker for "number" attribute.
133 */
134 public static final AttrCheck NUMBER = new CheckNumber();
135
136 /**
137 * checker for "scope" attribute.
138 */
139 public static final AttrCheck SCOPE = new CheckScope();
140
141 /**
142 * checker for "color" attribute.
143 */
144 public static final AttrCheck COLOR = new CheckColor();
145
146 /**
147 * checker for "vtype" attribute.
148 */
149 public static final AttrCheck VTYPE = new CheckVType();
150
151 /**
152 * checker for "scroll" attribute.
153 */
154 public static final AttrCheck SCROLL = new CheckScroll();
155
156 /**
157 * checker for "dir" attribute.
158 */
159 public static final AttrCheck TEXTDIR = new CheckTextDir();
160
161 /**
162 * checker for "lang" and "xml:lang" attributes.
163 */
164 public static final AttrCheck LANG = new CheckLang();
165
166 /**
167 * checker for text attributes. Actually null (no validation).
168 */
169 public static final AttrCheck TEXT = null;
170
171 /**
172 * checker for "charset" attribute. Actually null (no validation).
173 */
174 public static final AttrCheck CHARSET = null;
175
176 /**
177 * checker for "type" attribute. Actually null (no validation).
178 */
179 public static final AttrCheck TYPE = null;
180
181 /**
182 * checker for attributes that can contain a single character. Actually null (no validation).
183 */
184 public static final AttrCheck CHARACTER = null;
185
186 /**
187 * checker for attributes which contain a list of urls. Actually null (no validation).
188 */
189 public static final AttrCheck URLS = null;
190
191 /**
192 * checker for "cols" attribute. Actually null (no validation).
193 */
194 public static final AttrCheck COLS = null;
195
196 /**
197 * checker for "coords" attribute. Actually null (no validation).
198 */
199 public static final AttrCheck COORDS = null;
200
201 /**
202 * checker for attributes containing dates. Actually null (no validation).
203 */
204 public static final AttrCheck DATE = null;
205
206 /**
207 * checker for attributes referencng an id. Actually null (no validation).
208 */
209 public static final AttrCheck IDREF = null;
210
211 /**
212 * checker for table "frame" attribute. Actually null (no validation).
213 */
214 public static final AttrCheck TFRAME = null;
215
216 /**
217 * checker for "frameborder" attribute. Actually null (no validation).
218 */
219 public static final AttrCheck FBORDER = null;
220
221 /**
222 * checker for "media" attribute. Actually null (no validation).
223 */
224 public static final AttrCheck MEDIA = null;
225
226 /**
227 * checker for "rel" and "rev" attributes. Actually null (no validation).
228 */
229 public static final AttrCheck LINKTYPES = null;
230
231 /**
232 * checker for table "rules" attribute. Actually null (no validation).
233 */
234 public static final AttrCheck TRULES = null;
235
236 /**
237 * utility class, don't instantiate.
238 */
239 private AttrCheckImpl()
240 {
241
242 }
243
244 /**
245 * AttrCheck implementation for checking URLs.
246 */
247 public static class CheckUrl implements AttrCheck
248 {
249
250 /**
251 * @see AttrCheck#check(Lexer, Node, AttVal)
252 */
253 public void check(Lexer lexer, Node node, AttVal attval)
254 {
255 char c;
256 StringBuffer dest;
257 boolean escapeFound = false;
258 boolean backslashFound = false;
259 int i = 0;
260
261 if (attval.value == null)
262 {
263 lexer.report.attrError(lexer, node, attval, Report.MISSING_ATTR_VALUE);
264 return;
265 }
266
267 String p = attval.value;
268
269 for (i = 0; i < p.length(); ++i)
270 {
271 c = p.charAt(i);
272
273 if (c == '\\')
274 {
275 backslashFound = true;
276 }
277
278 else if ((c > 0x7e) || (c <= 0x20) || (c == '<') || (c == '>'))
279 {
280 escapeFound = true;
281 }
282 }
283
284
285 if (lexer.configuration.fixBackslash && backslashFound)
286 {
287 attval.value = attval.value.replace('\\', '/');
288 p = attval.value;
289 }
290
291
292 if (lexer.configuration.fixUri && escapeFound)
293 {
294 dest = new StringBuffer();
295
296 for (i = 0; i < p.length(); ++i)
297 {
298 c = p.charAt(i);
299 if ((c > 0x7e) || (c <= 0x20) || (c == '<') || (c == '>'))
300 {
301 dest.append('%');
302 dest.append(Integer.toHexString(c).toUpperCase());
303 }
304 else
305 {
306 dest.append(c);
307 }
308 }
309
310 attval.value = dest.toString();
311 }
312 if (backslashFound)
313 {
314 if (lexer.configuration.fixBackslash)
315 {
316 lexer.report.attrError(lexer, node, attval, Report.FIXED_BACKSLASH);
317 }
318 else
319 {
320 lexer.report.attrError(lexer, node, attval, Report.BACKSLASH_IN_URI);
321 }
322 }
323 if (escapeFound)
324 {
325 if (lexer.configuration.fixUri)
326 {
327 lexer.report.attrError(lexer, node, attval, Report.ESCAPED_ILLEGAL_URI);
328 }
329 else
330 {
331 lexer.report.attrError(lexer, node, attval, Report.ILLEGAL_URI_REFERENCE);
332 }
333
334 lexer.badChars |= Report.INVALID_URI;
335 }
336
337 }
338 }
339
340 /**
341 * AttrCheck implementation for checking scripts.
342 */
343 public static class CheckScript implements AttrCheck
344 {
345
346 /**
347 * @see AttrCheck#check(Lexer, Node, AttVal)
348 */
349 public void check(Lexer lexer, Node node, AttVal attval)
350 {
351
352 }
353
354 }
355
356 /**
357 * AttrCheck implementation for checking the "align" attribute.
358 */
359 public static class CheckAlign implements AttrCheck
360 {
361
362 /**
363 * valid values for this attribute.
364 */
365 private static final String[] VALID_VALUES = new String[]{"left", "center", "right", "justify"};
366
367 /**
368 * @see AttrCheck#check(Lexer, Node, AttVal)
369 */
370 public void check(Lexer lexer, Node node, AttVal attval)
371 {
372
373 if (node.tag != null && ((node.tag.model & Dict.CM_IMG) != 0))
374 {
375 VALIGN.check(lexer, node, attval);
376 return;
377 }
378
379 if (attval.value == null)
380 {
381 lexer.report.attrError(lexer, node, attval, Report.MISSING_ATTR_VALUE);
382 return;
383 }
384
385 attval.checkLowerCaseAttrValue(lexer, node);
386
387 if (!TidyUtils.isInValuesIgnoreCase(VALID_VALUES, attval.value))
388 {
389 lexer.report.attrError(lexer, node, attval, Report.BAD_ATTRIBUTE_VALUE);
390 }
391 }
392
393 }
394
395 /**
396 * AttrCheck implementation for checking the "valign" attribute.
397 */
398 public static class CheckValign implements AttrCheck
399 {
400
401 /**
402 * valid values for this attribute.
403 */
404 private static final String[] VALID_VALUES = new String[]{"top", "middle", "bottom", "baseline"};
405
406 /**
407 * valid values for this attribute (only for img tag).
408 */
409 private static final String[] VALID_VALUES_IMG = new String[]{"left", "right"};
410
411 /**
412 * proprietary values for this attribute.
413 */
414 private static final String[] VALID_VALUES_PROPRIETARY = new String[]{
415 "texttop",
416 "absmiddle",
417 "absbottom",
418 "textbottom"};
419
420 /**
421 * @see AttrCheck#check(Lexer, Node, AttVal)
422 */
423 public void check(Lexer lexer, Node node, AttVal attval)
424 {
425 String value;
426
427 if (attval.value == null)
428 {
429 lexer.report.attrError(lexer, node, attval, Report.MISSING_ATTR_VALUE);
430 return;
431 }
432
433 attval.checkLowerCaseAttrValue(lexer, node);
434
435 value = attval.value;
436
437 if (TidyUtils.isInValuesIgnoreCase(VALID_VALUES, value))
438 {
439
440 return;
441 }
442
443 if (TidyUtils.isInValuesIgnoreCase(VALID_VALUES_IMG, value))
444 {
445 if (!(node.tag != null && ((node.tag.model & Dict.CM_IMG) != 0)))
446 {
447 lexer.report.attrError(lexer, node, attval, Report.BAD_ATTRIBUTE_VALUE);
448 }
449 }
450 else if (TidyUtils.isInValuesIgnoreCase(VALID_VALUES_PROPRIETARY, value))
451 {
452 lexer.constrainVersion(Dict.VERS_PROPRIETARY);
453 lexer.report.attrError(lexer, node, attval, Report.PROPRIETARY_ATTR_VALUE);
454 }
455 else
456 {
457 lexer.report.attrError(lexer, node, attval, Report.BAD_ATTRIBUTE_VALUE);
458 }
459 }
460
461 }
462
463 /**
464 * AttrCheck implementation for checking boolean attributes.
465 */
466 public static class CheckBool implements AttrCheck
467 {
468
469 /**
470 * @see AttrCheck#check(Lexer, Node, AttVal)
471 */
472 public void check(Lexer lexer, Node node, AttVal attval)
473 {
474 if (attval.value == null)
475 {
476 return;
477 }
478
479 attval.checkLowerCaseAttrValue(lexer, node);
480 }
481
482 }
483
484 /**
485 * AttrCheck implementation for checking the "length" attribute.
486 */
487 public static class CheckLength implements AttrCheck
488 {
489
490 /**
491 * @see AttrCheck#check(Lexer, Node, AttVal)
492 */
493 public void check(Lexer lexer, Node node, AttVal attval)
494 {
495
496 if (attval.value == null)
497 {
498 lexer.report.attrError(lexer, node, attval, Report.MISSING_ATTR_VALUE);
499 return;
500 }
501
502
503 if ("width".equalsIgnoreCase(attval.attribute)
504 && (node.tag == lexer.configuration.tt.tagCol || node.tag == lexer.configuration.tt.tagColgroup))
505 {
506 return;
507 }
508
509 String p = attval.value;
510
511 if (p.length() == 0 || (!Character.isDigit(p.charAt(0)) && !('%' == p.charAt(0))))
512 {
513 lexer.report.attrError(lexer, node, attval, Report.BAD_ATTRIBUTE_VALUE);
514 }
515 else
516 {
517
518 TagTable tt = lexer.configuration.tt;
519
520 for (int j = 1; j < p.length(); j++)
521 {
522
523 if ((!Character.isDigit(p.charAt(j)) && (node.tag == tt.tagTd || node.tag == tt.tagTh))
524 || (!Character.isDigit(p.charAt(j)) && p.charAt(j) != '%'))
525 {
526 lexer.report.attrError(lexer, node, attval, Report.BAD_ATTRIBUTE_VALUE);
527 break;
528 }
529 }
530 }
531 }
532 }
533
534 /**
535 * AttrCheck implementation for checking the "target" attribute.
536 */
537 public static class CheckTarget implements AttrCheck
538 {
539
540 /**
541 * valid values for this attribute.
542 */
543 private static final String[] VALID_VALUES = new String[]{"_blank", "_self", "_parent", "_top"};
544
545 /**
546 * @see AttrCheck#check(Lexer, Node, AttVal)
547 */
548 public void check(Lexer lexer, Node node, AttVal attval)
549 {
550
551
552 lexer.constrainVersion(~Dict.VERS_HTML40_STRICT);
553
554 if (attval.value == null || attval.value.length() == 0)
555 {
556 lexer.report.attrError(lexer, node, attval, Report.MISSING_ATTR_VALUE);
557 return;
558 }
559
560 String value = attval.value;
561
562
563 if (Character.isLetter(value.charAt(0)))
564 {
565 return;
566 }
567
568
569 if (!TidyUtils.isInValuesIgnoreCase(VALID_VALUES, value))
570 {
571 lexer.report.attrError(lexer, node, attval, Report.BAD_ATTRIBUTE_VALUE);
572 }
573
574 }
575 }
576
577 /**
578 * AttrCheck implementation for checking the "submit" attribute.
579 */
580 public static class CheckFsubmit implements AttrCheck
581 {
582
583 /**
584 * valid values for this attribute.
585 */
586 private static final String[] VALID_VALUES = new String[]{"get", "post"};
587
588 /**
589 * @see AttrCheck#check(Lexer, Node, AttVal)
590 */
591 public void check(Lexer lexer, Node node, AttVal attval)
592 {
593 if (attval.value == null)
594 {
595 lexer.report.attrError(lexer, node, attval, Report.MISSING_ATTR_VALUE);
596 return;
597 }
598
599 attval.checkLowerCaseAttrValue(lexer, node);
600
601 if (!TidyUtils.isInValuesIgnoreCase(VALID_VALUES, attval.value))
602 {
603 lexer.report.attrError(lexer, node, attval, Report.BAD_ATTRIBUTE_VALUE);
604 }
605 }
606 }
607
608 /**
609 * AttrCheck implementation for checking the "clear" attribute.
610 */
611 public static class CheckClear implements AttrCheck
612 {
613
614 /**
615 * valid values for this attribute.
616 */
617 private static final String[] VALID_VALUES = new String[]{"none", "left", "right", "all"};
618
619 /**
620 * @see AttrCheck#check(Lexer, Node, AttVal)
621 */
622 public void check(Lexer lexer, Node node, AttVal attval)
623 {
624 if (attval.value == null)
625 {
626 lexer.report.attrError(lexer, node, attval, Report.MISSING_ATTR_VALUE);
627 attval.value = VALID_VALUES[0];
628 return;
629 }
630
631 attval.checkLowerCaseAttrValue(lexer, node);
632
633 if (!TidyUtils.isInValuesIgnoreCase(VALID_VALUES, attval.value))
634 {
635 lexer.report.attrError(lexer, node, attval, Report.BAD_ATTRIBUTE_VALUE);
636 }
637
638 }
639 }
640
641 /**
642 * AttrCheck implementation for checking the "shape" attribute.
643 */
644 public static class CheckShape implements AttrCheck
645 {
646
647 /**
648 * valid values for this attribute.
649 */
650 private static final String[] VALID_VALUES = new String[]{"rect", "default", "circle", "poly"};
651
652 /**
653 * @see AttrCheck#check(Lexer, Node, AttVal)
654 */
655 public void check(Lexer lexer, Node node, AttVal attval)
656 {
657 if (attval.value == null)
658 {
659 lexer.report.attrError(lexer, node, attval, Report.MISSING_ATTR_VALUE);
660 return;
661 }
662
663 attval.checkLowerCaseAttrValue(lexer, node);
664
665 if (!TidyUtils.isInValuesIgnoreCase(VALID_VALUES, attval.value))
666 {
667 lexer.report.attrError(lexer, node, attval, Report.BAD_ATTRIBUTE_VALUE);
668 }
669
670 }
671 }
672
673 /**
674 * AttrCheck implementation for checking Scope.
675 */
676 public static class CheckScope implements AttrCheck
677 {
678
679 /**
680 * valid values for this attribute.
681 */
682 private static final String[] VALID_VALUES = new String[]{"row", "rowgroup", "col", "colgroup"};
683
684 /**
685 * @see AttrCheck#check(Lexer, Node, AttVal)
686 */
687 public void check(Lexer lexer, Node node, AttVal attval)
688 {
689
690 if (attval.value == null)
691 {
692 lexer.report.attrError(lexer, node, attval, Report.MISSING_ATTR_VALUE);
693 return;
694 }
695
696 attval.checkLowerCaseAttrValue(lexer, node);
697
698 if (!TidyUtils.isInValuesIgnoreCase(VALID_VALUES, attval.value))
699 {
700 lexer.report.attrError(lexer, node, attval, Report.BAD_ATTRIBUTE_VALUE);
701 }
702 }
703 }
704
705 /**
706 * AttrCheck implementation for checking numbers.
707 */
708 public static class CheckNumber implements AttrCheck
709 {
710
711 /**
712 * @see AttrCheck#check(Lexer, Node, AttVal)
713 */
714 public void check(Lexer lexer, Node node, AttVal attval)
715 {
716
717 if (attval.value == null)
718 {
719 lexer.report.attrError(lexer, node, attval, Report.MISSING_ATTR_VALUE);
720 return;
721 }
722
723
724 if (("cols".equalsIgnoreCase(attval.attribute) || "rows".equalsIgnoreCase(attval.attribute))
725 && node.tag == lexer.configuration.tt.tagFrameset)
726 {
727 return;
728 }
729
730 String value = attval.value;
731
732 int j = 0;
733
734
735 if (node.tag == lexer.configuration.tt.tagFont && (value.startsWith("+") || value.startsWith("-")))
736 {
737 ++j;
738 }
739
740 for (; j < value.length(); j++)
741 {
742 char p = value.charAt(j);
743 if (!Character.isDigit(p))
744 {
745 lexer.report.attrError(lexer, node, attval, Report.BAD_ATTRIBUTE_VALUE);
746 break;
747 }
748 }
749 }
750 }
751
752 /**
753 * AttrCheck implementation for checking ids.
754 */
755 public static class CheckId implements AttrCheck
756 {
757
758 /**
759 * @see AttrCheck#check(Lexer, Node, AttVal)
760 */
761 public void check(Lexer lexer, Node node, AttVal attval)
762 {
763 Node old;
764
765 if (attval.value == null || attval.value.length() == 0)
766 {
767 lexer.report.attrError(lexer, node, attval, Report.MISSING_ATTR_VALUE);
768 return;
769 }
770
771 String p = attval.value;
772 char s = p.charAt(0);
773
774 if (p.length() == 0 || !Character.isLetter(p.charAt(0)))
775 {
776 if (lexer.isvoyager && (TidyUtils.isXMLLetter(s) || s == '_' || s == ':'))
777 {
778 lexer.report.attrError(lexer, node, attval, Report.XML_ID_SYNTAX);
779 }
780 else
781 {
782 lexer.report.attrError(lexer, node, attval, Report.BAD_ATTRIBUTE_VALUE);
783 }
784 }
785 else
786 {
787
788 for (int j = 1; j < p.length(); j++)
789 {
790 s = p.charAt(j);
791
792 if (!TidyUtils.isNamechar(s))
793 {
794 if (lexer.isvoyager && TidyUtils.isXMLNamechar(s))
795 {
796 lexer.report.attrError(lexer, node, attval, Report.XML_ID_SYNTAX);
797 }
798 else
799 {
800 lexer.report.attrError(lexer, node, attval, Report.BAD_ATTRIBUTE_VALUE);
801 }
802 break;
803 }
804 }
805 }
806
807 if (((old = lexer.configuration.tt.getNodeByAnchor(attval.value)) != null) && old != node)
808 {
809 lexer.report.attrError(lexer, node, attval, Report.ANCHOR_NOT_UNIQUE);
810 }
811 else
812 {
813 lexer.configuration.tt.anchorList = lexer.configuration.tt.addAnchor(attval.value, node);
814 }
815 }
816
817 }
818
819 /**
820 * AttrCheck implementation for checking the "name" attribute.
821 */
822 public static class CheckName implements AttrCheck
823 {
824
825 /**
826 * @see AttrCheck#check(Lexer, Node, AttVal)
827 */
828 public void check(Lexer lexer, Node node, AttVal attval)
829 {
830 Node old;
831
832 if (attval.value == null)
833 {
834 lexer.report.attrError(lexer, node, attval, Report.MISSING_ATTR_VALUE);
835 return;
836 }
837 else if (lexer.configuration.tt.isAnchorElement(node))
838 {
839 lexer.constrainVersion(~Dict.VERS_XHTML11);
840
841 if (((old = lexer.configuration.tt.getNodeByAnchor(attval.value)) != null) && old != node)
842 {
843 lexer.report.attrError(lexer, node, attval, Report.ANCHOR_NOT_UNIQUE);
844 }
845 else
846 {
847 lexer.configuration.tt.anchorList = lexer.configuration.tt.addAnchor(attval.value, node);
848 }
849 }
850 }
851
852 }
853
854 /**
855 * AttrCheck implementation for checking colors.
856 */
857 public static class CheckColor implements AttrCheck
858 {
859
860 /**
861 * valid html colors.
862 */
863 private static final Map COLORS = new HashMap();
864
865 static
866 {
867 COLORS.put("black", "#000000");
868 COLORS.put("green", "#008000");
869 COLORS.put("silver", "#C0C0C0");
870 COLORS.put("lime", "#00FF00");
871 COLORS.put("gray", "#808080");
872 COLORS.put("olive", "#808000");
873 COLORS.put("white", "#FFFFFF");
874 COLORS.put("yellow", "#FFFF00");
875 COLORS.put("maroon", "#800000");
876 COLORS.put("navy", "#000080");
877 COLORS.put("red", "#FF0000");
878 COLORS.put("blue", "#0000FF");
879 COLORS.put("purple", "#800080");
880 COLORS.put("teal", "#008080");
881 COLORS.put("fuchsia", "#FF00FF");
882 COLORS.put("aqua", "#00FFFF");
883 }
884
885 /**
886 * @see AttrCheck#check(Lexer, Node, AttVal)
887 */
888 public void check(Lexer lexer, Node node, AttVal attval)
889 {
890 boolean hexUppercase = true;
891 boolean invalid = false;
892 boolean found = false;
893
894 if (attval.value == null || attval.value.length() == 0)
895 {
896 lexer.report.attrError(lexer, node, attval, Report.MISSING_ATTR_VALUE);
897 return;
898 }
899
900 String given = attval.value;
901
902 Iterator colorIter = COLORS.entrySet().iterator();
903
904 while (colorIter.hasNext())
905 {
906 Map.Entry color = (Map.Entry) colorIter.next();
907
908 if (given.charAt(0) == '#')
909 {
910 if (given.length() != 7)
911 {
912 lexer.report.attrError(lexer, node, attval, Report.BAD_ATTRIBUTE_VALUE);
913 invalid = true;
914 break;
915 }
916 else if (given.equalsIgnoreCase((String) color.getValue()))
917 {
918 if (lexer.configuration.replaceColor)
919 {
920 attval.value = (String) color.getKey();
921 }
922 found = true;
923 break;
924 }
925 }
926 else if (TidyUtils.isLetter(given.charAt(0)))
927 {
928 if (given.equalsIgnoreCase((String) color.getKey()))
929 {
930 if (lexer.configuration.replaceColor)
931 {
932 attval.value = (String) color.getKey();
933 }
934 found = true;
935 break;
936 }
937 }
938 else
939 {
940
941 lexer.report.attrError(lexer, node, attval, Report.BAD_ATTRIBUTE_VALUE);
942
943 invalid = true;
944 break;
945 }
946 }
947 if (!found && !invalid)
948 {
949 if (given.charAt(0) == '#')
950 {
951
952
953 for (int i = 1; i < 7; ++i)
954 {
955 if (!TidyUtils.isDigit(given.charAt(i))
956 && ("abcdef".indexOf(Character.toLowerCase(given.charAt(i))) == -1))
957 {
958 lexer.report.attrError(lexer, node, attval, Report.BAD_ATTRIBUTE_VALUE);
959 invalid = true;
960 break;
961 }
962 }
963
964 if (!invalid && hexUppercase)
965 {
966 for (int i = 1; i < 7; ++i)
967 {
968 attval.value = given.toUpperCase();
969 }
970 }
971 }
972
973 else
974 {
975
976
977 lexer.report.attrError(lexer, node, attval, Report.BAD_ATTRIBUTE_VALUE);
978 invalid = true;
979 }
980 }
981 }
982 }
983
984 /**
985 * AttrCheck implementation for checking valuetype.
986 */
987 public static class CheckVType implements AttrCheck
988 {
989
990 /**
991 * valid values for this attribute.
992 */
993 private static final String[] VALID_VALUES = new String[]{"data", "object", "ref"};
994
995 /**
996 * @see AttrCheck#check(Lexer, Node, AttVal)
997 */
998 public void check(Lexer lexer, Node node, AttVal attval)
999 {
1000 if (attval.value == null)
1001 {
1002 lexer.report.attrError(lexer, node, attval, Report.MISSING_ATTR_VALUE);
1003 return;
1004 }
1005
1006 attval.checkLowerCaseAttrValue(lexer, node);
1007
1008 if (!TidyUtils.isInValuesIgnoreCase(VALID_VALUES, attval.value))
1009 {
1010 lexer.report.attrError(lexer, node, attval, Report.BAD_ATTRIBUTE_VALUE);
1011 }
1012 }
1013 }
1014
1015 /**
1016 * AttrCheck implementation for checking scroll.
1017 */
1018 public static class CheckScroll implements AttrCheck
1019 {
1020
1021 /**
1022 * valid values for this attribute.
1023 */
1024 private static final String[] VALID_VALUES = new String[]{"no", "yes", "auto"};
1025
1026 /**
1027 * @see AttrCheck#check(Lexer, Node, AttVal)
1028 */
1029 public void check(Lexer lexer, Node node, AttVal attval)
1030 {
1031
1032 if (attval.value == null)
1033 {
1034 lexer.report.attrError(lexer, node, attval, Report.MISSING_ATTR_VALUE);
1035 return;
1036 }
1037
1038 attval.checkLowerCaseAttrValue(lexer, node);
1039
1040 if (!TidyUtils.isInValuesIgnoreCase(VALID_VALUES, attval.value))
1041 {
1042 lexer.report.attrError(lexer, node, attval, Report.BAD_ATTRIBUTE_VALUE);
1043 }
1044 }
1045 }
1046
1047 /**
1048 * AttrCheck implementation for checking dir.
1049 */
1050 public static class CheckTextDir implements AttrCheck
1051 {
1052
1053 /**
1054 * valid values for this attribute.
1055 */
1056 private static final String[] VALID_VALUES = new String[]{"rtl", "ltr"};
1057
1058 /**
1059 * @see AttrCheck#check(Lexer, Node, AttVal)
1060 */
1061 public void check(Lexer lexer, Node node, AttVal attval)
1062 {
1063
1064 if (attval.value == null)
1065 {
1066 lexer.report.attrError(lexer, node, attval, Report.MISSING_ATTR_VALUE);
1067 return;
1068 }
1069
1070 attval.checkLowerCaseAttrValue(lexer, node);
1071
1072 if (!TidyUtils.isInValuesIgnoreCase(VALID_VALUES, attval.value))
1073 {
1074 lexer.report.attrError(lexer, node, attval, Report.BAD_ATTRIBUTE_VALUE);
1075 }
1076 }
1077 }
1078
1079 /**
1080 * AttrCheck implementation for checking lang and xml:lang.
1081 */
1082 public static class CheckLang implements AttrCheck
1083 {
1084
1085 /**
1086 * @see AttrCheck#check(Lexer, Node, AttVal)
1087 */
1088 public void check(Lexer lexer, Node node, AttVal attval)
1089 {
1090
1091 if ("lang".equals(attval.attribute))
1092 {
1093 lexer.constrainVersion(~Dict.VERS_XHTML11);
1094 }
1095
1096 if (attval.value == null)
1097 {
1098 lexer.report.attrError(lexer, node, attval, Report.MISSING_ATTR_VALUE);
1099 return;
1100 }
1101 }
1102 }
1103
1104 }