Coverage Report

Created: 2025-08-26 06:02

/src/tidy-html5/src/access.c
Line
Count
Source (jump to first uncovered line)
1
/* access.c -- carry out accessibility checks
2
3
  Copyright University of Toronto
4
  Portions (c) 1998-2009 (W3C) MIT, ERCIM, Keio University
5
  See tidy.h for the copyright notice.
6
  
7
*/
8
9
10
#include "tidy-int.h"
11
#include "access.h"
12
#include "message.h"
13
#include "tags.h"
14
#include "attrs.h"
15
#include "tmbstr.h"
16
17
18
/* 
19
    The accessibility checks to perform depending on user's desire.
20
21
    1. priority 1
22
    2. priority 1 & 2
23
    3. priority 1, 2, & 3
24
*/
25
26
/* List of possible image types */
27
static const ctmbstr imageExtensions[] =
28
{".jpg", ".gif", ".tif", ".pct", ".pic", ".iff", ".dib",
29
 ".tga", ".pcx", ".png", ".jpeg", ".tiff", ".bmp"};
30
31
0
#define N_IMAGE_EXTS (sizeof(imageExtensions)/sizeof(ctmbstr))
32
33
/* List of possible sound file types */
34
static const ctmbstr soundExtensions[] =
35
{".wav", ".au", ".aiff", ".snd", ".ra", ".rm"};
36
37
static const int soundExtErrCodes[] = 
38
{
39
    AUDIO_MISSING_TEXT_WAV,
40
    AUDIO_MISSING_TEXT_AU,
41
    AUDIO_MISSING_TEXT_AIFF,
42
    AUDIO_MISSING_TEXT_SND,
43
    AUDIO_MISSING_TEXT_RA,
44
    AUDIO_MISSING_TEXT_RM
45
};
46
47
0
#define N_AUDIO_EXTS (sizeof(soundExtensions)/sizeof(ctmbstr))
48
49
/* List of possible media extensions */
50
static const ctmbstr mediaExtensions[] = 
51
{".mpg", ".mov", ".asx", ".avi", ".ivf", ".m1v", ".mmm", ".mp2v",
52
 ".mpa", ".mpe", ".mpeg", ".ram", ".smi", ".smil", ".swf",
53
 ".wm", ".wma", ".wmv"};
54
55
0
#define N_MEDIA_EXTS (sizeof(mediaExtensions)/sizeof(ctmbstr))
56
57
/* List of possible frame sources */
58
static const ctmbstr frameExtensions[] =
59
{".htm", ".html", ".shtm", ".shtml", ".cfm", ".cfml",
60
".asp", ".cgi", ".pl", ".smil"};
61
62
0
#define N_FRAME_EXTS (sizeof(frameExtensions)/sizeof(ctmbstr))
63
64
/* List of possible colour values */
65
static const int colorValues[][3] =
66
{
67
  {240, 248, 255 },
68
  {250, 235, 215 },
69
  {0, 255, 255 },
70
  {127, 255, 212 },
71
  {240, 255, 255 },
72
  {245, 245, 220 },
73
  {255, 228, 196 },
74
  {0, 0, 0 },
75
  {255, 235, 205 },
76
  {0, 0, 255 },
77
  {138, 43, 226 },
78
  {165, 42, 42 },
79
  {222, 184, 135 },
80
  {95, 158, 160 },
81
  {127, 255, 0 },
82
  {210, 105, 30 },
83
  {255, 127, 80 },
84
  {100, 149, 237 },
85
  {255, 248, 220 },
86
  {220, 20, 60 },
87
  {0, 255, 255 },
88
  {0, 0, 139 },
89
  {0, 139, 139 },
90
  {184, 134, 11 },
91
  {169, 169, 169 },
92
  {0, 100, 0 },
93
  {169, 169, 169 },
94
  {189, 183, 107 },
95
  {139, 0, 139 },
96
  {85, 107, 47 },
97
  {255, 140, 0 },
98
  {153, 50, 204 },
99
  {139, 0, 0 },
100
  {233, 150, 122 },
101
  {143, 188, 143 },
102
  {72, 61, 139 },
103
  {47, 79, 79 },
104
  {47, 79, 79 },
105
  {0, 206, 209 },
106
  {148, 0, 211 },
107
  {255, 20, 147 },
108
  {0, 191, 255 },
109
  {105, 105, 105 },
110
  {105, 105, 105 },
111
  {30, 144, 255 },
112
  {178, 34, 34 },
113
  {255, 250, 240 },
114
  {34, 139, 34 },
115
  {255, 0, 255 },
116
  {220, 220, 220 },
117
  {248, 248, 255 },
118
  {255, 215, 0 },
119
  {218, 165, 32 },
120
  {128, 128, 128 },
121
  {0, 128, 0 },
122
  {173, 255, 47 },
123
  {128, 128, 128 },
124
  {240, 255, 240 },
125
  {255, 105, 180 },
126
  {205, 92, 92 },
127
  {75, 0, 130 },
128
  {255, 255, 240 },
129
  {240, 230, 140 },
130
  {230, 230, 250 },
131
  {255, 240, 245 },
132
  {124, 252, 0 },
133
  {255, 250, 205 },
134
  {173, 216, 230 },
135
  {240, 128, 128 },
136
  {224, 255, 255 },
137
  {250, 250, 210 },
138
  {211, 211, 211 },
139
  {144, 238, 144 },
140
  {211, 211, 211 },
141
  {255, 182, 193 },
142
  {255, 160, 122 },
143
  {32, 178, 170 },
144
  {135, 206, 250 },
145
  {119, 136, 153 },
146
  {119, 136, 153 },
147
  {176, 196, 222 },
148
  {255, 255, 224 },
149
  {0, 255, 0 },
150
  {50, 205, 50 },
151
  {250, 240, 230 },
152
  {255, 0, 255 },
153
  {128, 0, 0 },
154
  {102, 205, 170 },
155
  {0, 0, 205 },
156
  {186, 85, 211 },
157
  {147, 112, 219 },
158
  {60, 179, 113 },
159
  {123, 104, 238 },
160
  {0, 250, 154 },
161
  {72, 209, 204 },
162
  {199, 21, 133 },
163
  {25, 25, 112 },
164
  {245, 255, 250 },
165
  {255, 228, 225 },
166
  {255, 228, 181 },
167
  {255, 222, 173 },
168
  {0, 0, 128 },
169
  {253, 245, 230 },
170
  {128, 128, 0 },
171
  {107, 142, 35 },
172
  {255, 165, 0 },
173
  {255, 69, 0 },
174
  {218, 112, 214 },
175
  {238, 232, 170 },
176
  {152, 251, 152 },
177
  {175, 238, 238 },
178
  {219, 112, 147 },
179
  {255, 239, 213 },
180
  {255, 218, 185 },
181
  {205, 133, 63 },
182
  {255, 192, 203 },
183
  {221, 160, 221 },
184
  {176, 224, 230 },
185
  {128, 0, 128 },
186
  {102, 51, 153 },
187
  {255, 0, 0 },
188
  {188, 143, 143 },
189
  {65, 105, 225 },
190
  {139, 69, 19 },
191
  {250, 128, 114 },
192
  {244, 164, 96 },
193
  {46, 139, 87 },
194
  {255, 245, 238 },
195
  {160, 82, 45 },
196
  {192, 192, 192 },
197
  {135, 206, 235 },
198
  {106, 90, 205 },
199
  {112, 128, 144 },
200
  {112, 128, 144 },
201
  {255, 250, 250 },
202
  {0, 255, 127 },
203
  {70, 130, 180 },
204
  {210, 180, 140 },
205
  {0, 128, 128 },
206
  {216, 191, 216 },
207
  {255, 99, 71 },
208
  {64, 224, 208 },
209
  {238, 130, 238 },
210
  {245, 222, 179 },
211
  {255, 255, 255 },
212
  {245, 245, 245 },
213
  {255, 255, 0 },
214
  {154, 205, 50 }
215
};
216
217
#define N_COLOR_VALS (sizeof(colorValues)/(sizeof(int[3]))
218
219
/* These arrays are used to convert color names to their RGB values */
220
static const ctmbstr colorNames[] =
221
{
222
  "aliceblue",
223
  "antiquewhite",
224
  "aqua",
225
  "aquamarine",
226
  "azure",
227
  "beige",
228
  "bisque",
229
  "black",
230
  "blanchedalmond",
231
  "blue",
232
  "blueviolet",
233
  "brown",
234
  "burlywood",
235
  "cadetblue",
236
  "chartreuse",
237
  "chocolate",
238
  "coral",
239
  "cornflowerblue",
240
  "cornsilk",
241
  "crimson",
242
  "cyan",
243
  "darkblue",
244
  "darkcyan",
245
  "darkgoldenrod",
246
  "darkgray",
247
  "darkgreen",
248
  "darkgrey",
249
  "darkkhaki",
250
  "darkmagenta",
251
  "darkolivegreen",
252
  "darkorange",
253
  "darkorchid",
254
  "darkred",
255
  "darksalmon",
256
  "darkseagreen",
257
  "darkslateblue",
258
  "darkslategray",
259
  "darkslategrey",
260
  "darkturquoise",
261
  "darkviolet",
262
  "deeppink",
263
  "deepskyblue",
264
  "dimgray",
265
  "dimgrey",
266
  "dodgerblue",
267
  "firebrick",
268
  "floralwhite",
269
  "forestgreen",
270
  "fuchsia",
271
  "gainsboro",
272
  "ghostwhite",
273
  "gold",
274
  "goldenrod",
275
  "gray",
276
  "green",
277
  "greenyellow",
278
  "grey",
279
  "honeydew",
280
  "hotpink",
281
  "indianred",
282
  "indigo",
283
  "ivory",
284
  "khaki",
285
  "lavender",
286
  "lavenderblush",
287
  "lawngreen",
288
  "lemonchiffon",
289
  "lightblue",
290
  "lightcoral",
291
  "lightcyan",
292
  "lightgoldenrodyellow",
293
  "lightgray",
294
  "lightgreen",
295
  "lightgrey",
296
  "lightpink",
297
  "lightsalmon",
298
  "lightseagreen",
299
  "lightskyblue",
300
  "lightslategray",
301
  "lightslategrey",
302
  "lightsteelblue",
303
  "lightyellow",
304
  "lime",
305
  "limegreen",
306
  "linen",
307
  "magenta",
308
  "maroon",
309
  "mediumaquamarine",
310
  "mediumblue",
311
  "mediumorchid",
312
  "mediumpurple",
313
  "mediumseagreen",
314
  "mediumslateblue",
315
  "mediumspringgreen",
316
  "mediumturquoise",
317
  "mediumvioletred",
318
  "midnightblue",
319
  "mintcream",
320
  "mistyrose",
321
  "moccasin",
322
  "navajowhite",
323
  "navy",
324
  "oldlace",
325
  "olive",
326
  "olivedrab",
327
  "orange",
328
  "orangered",
329
  "orchid",
330
  "palegoldenrod",
331
  "palegreen",
332
  "paleturquoise",
333
  "palevioletred",
334
  "papayawhip",
335
  "peachpuff",
336
  "peru",
337
  "pink",
338
  "plum",
339
  "powderblue",
340
  "purple",
341
  "rebeccapurple",
342
  "red",
343
  "rosybrown",
344
  "royalblue",
345
  "saddlebrown",
346
  "salmon",
347
  "sandybrown",
348
  "seagreen",
349
  "seashell",
350
  "sienna",
351
  "silver",
352
  "skyblue",
353
  "slateblue",
354
  "slategray",
355
  "slategrey",
356
  "snow",
357
  "springgreen",
358
  "steelblue",
359
  "tan",
360
  "teal",
361
  "thistle",
362
  "tomato",
363
  "turquoise",
364
  "violet",
365
  "wheat",
366
  "white",
367
  "whitesmoke",
368
  "yellow",
369
  "yellowgreen",
370
};
371
372
0
#define N_COLOR_NAMES (sizeof(colorNames)/sizeof(ctmbstr))
373
0
#define N_COLORS N_COLOR_NAMES
374
375
376
/* function prototypes */
377
static void InitAccessibilityChecks( TidyDocImpl* doc, int level123 );
378
static void FreeAccessibilityChecks( TidyDocImpl* doc );
379
380
static Bool GetRgb( ctmbstr color, int rgb[3] );
381
static Bool CompareColors( const int rgbBG[3], const int rgbFG[3] );
382
static int  ctox( tmbchar ch );
383
384
/*
385
static void CheckMapAccess( TidyDocImpl* doc, Node* node, Node* front);
386
static void GetMapLinks( TidyDocImpl* doc, Node* node, Node* front);
387
static void CompareAnchorLinks( TidyDocImpl* doc, Node* front, int counter);
388
static void FindMissingLinks( TidyDocImpl* doc, Node* node, int counter);
389
*/
390
static void CheckFormControls( TidyDocImpl* doc, Node* node );
391
static void MetaDataPresent( TidyDocImpl* doc, Node* node );
392
static void CheckEmbed( TidyDocImpl* doc, Node* node );
393
static void CheckListUsage( TidyDocImpl* doc, Node* node );
394
395
/*
396
    IsFilePath attempts to determine whether or not the URI indicated
397
    by path is a file rather than a TLD. For example, sample.com.au might
398
    be confused with an audio file.
399
*/
400
static Bool IsFilePath( ctmbstr path )
401
0
{
402
0
    const char *p = path;
403
0
    char c;
404
0
    typedef enum states { initial, protocol_found, slash_found, file_found } states;
405
0
    states state = initial;
406
407
0
    while ( ( c = *p++ ) != 0 && state != file_found )
408
0
    {
409
0
        switch ( state )
410
0
        {
411
0
            case initial:
412
0
                if ( c == ':' )
413
0
                    state = protocol_found;
414
0
                break;
415
416
0
            case protocol_found:
417
0
                if ( c =='/' )
418
0
                    state = slash_found;
419
0
                break;
420
421
0
            case slash_found:
422
0
                if ( c =='/' )
423
0
                    state = protocol_found;
424
0
                else
425
0
                    state = file_found;
426
0
                break;
427
                
428
0
            default:
429
0
                break;
430
0
        }
431
        
432
0
    }
433
    
434
0
    return state == file_found || state == initial;
435
0
}
436
437
438
/*
439
    GetFileExtension takes a path and returns the extension
440
    portion of the path (if any).
441
*/
442
443
static void GetFileExtension( ctmbstr path, tmbchar *ext, uint maxExt )
444
0
{
445
0
    int i = TY_(tmbstrlen)(path) - 1;
446
    
447
0
    ext[0] = '\0';
448
    
449
0
    do {
450
0
        if ( path[i] == '/' || path[i] == '\\' )
451
0
            break;
452
0
        else if ( path[i] == '.' )
453
0
        {
454
0
            TY_(tmbstrncpy)( ext, path+i, maxExt );
455
0
            break;
456
0
        }
457
0
    } while ( --i > 0 );
458
0
}
459
460
/************************************************************************
461
* IsImage
462
*
463
* Checks if the given filename is an image file.
464
* Returns 'yes' if it is, 'no' if it's not.
465
************************************************************************/
466
467
static Bool IsImage( ctmbstr iType )
468
0
{
469
0
    uint i;
470
0
    tmbchar ext[20];
471
472
0
    if ( !IsFilePath(iType) ) return 0;
473
474
0
    GetFileExtension( iType, ext, sizeof(ext) );
475
476
    /* Compare it to the array of known image file extensions */
477
0
    for (i = 0; i < N_IMAGE_EXTS; i++)
478
0
    {
479
0
        if ( TY_(tmbstrcasecmp)(ext, imageExtensions[i]) == 0 )
480
0
            return yes;
481
0
    }
482
    
483
0
    return no;
484
0
}
485
486
487
/***********************************************************************
488
* IsSoundFile
489
*
490
* Checks if the given filename is a sound file.
491
* Returns 'yes' if it is, 'no' if it's not.
492
***********************************************************************/
493
494
static int IsSoundFile( ctmbstr sType )
495
0
{
496
0
    uint i;
497
0
    tmbchar ext[ 20 ];
498
499
0
    if ( !IsFilePath(sType) ) return 0;
500
    
501
0
    GetFileExtension( sType, ext, sizeof(ext) );
502
    
503
0
    for (i = 0; i < N_AUDIO_EXTS; i++)
504
0
    {
505
0
        if ( TY_(tmbstrcasecmp)(ext, soundExtensions[i]) == 0 )
506
0
            return soundExtErrCodes[i];
507
0
    }
508
0
    return 0;
509
0
}
510
511
512
/***********************************************************************
513
* IsValidSrcExtension
514
*
515
* Checks if the 'SRC' value within the FRAME element is valid
516
* The 'SRC' extension must end in ".htm", ".html", ".shtm", ".shtml", 
517
* ".cfm", ".cfml", ".asp", ".cgi", ".pl", or ".smil"
518
*
519
* Returns yes if it is, returns no otherwise.
520
***********************************************************************/
521
522
static Bool IsValidSrcExtension( ctmbstr sType )
523
0
{
524
0
    uint i;
525
0
    tmbchar ext[20];
526
    
527
0
    if ( !IsFilePath(sType) ) return 0;
528
    
529
0
    GetFileExtension( sType, ext, sizeof(ext) );
530
531
0
    for (i = 0; i < N_FRAME_EXTS; i++)
532
0
    {
533
0
        if ( TY_(tmbstrcasecmp)(ext, frameExtensions[i]) == 0 )
534
0
            return yes;
535
0
    }
536
0
    return no;
537
0
}
538
539
540
/*********************************************************************
541
* IsValidMediaExtension
542
*
543
* Checks to warn the user that synchronized text equivalents are
544
* required if multimedia is used.
545
*********************************************************************/
546
547
static Bool IsValidMediaExtension( ctmbstr sType )
548
0
{
549
0
    uint i;
550
0
    tmbchar ext[20];
551
552
0
    if ( !IsFilePath(sType) ) return 0;
553
554
0
    GetFileExtension( sType, ext, sizeof(ext) );
555
556
0
    for (i = 0; i < N_MEDIA_EXTS; i++)
557
0
    {
558
0
        if ( TY_(tmbstrcasecmp)(ext, mediaExtensions[i]) == 0 )
559
0
            return yes;
560
0
    }
561
0
    return no;
562
0
}
563
564
565
/************************************************************************
566
* IsWhitespace
567
*
568
* Checks if the given string is all whitespace.
569
* Returns 'yes' if it is, 'no' if it's not.
570
************************************************************************/
571
572
static Bool IsWhitespace( ctmbstr pString )
573
0
{
574
0
    Bool isWht = yes;
575
0
    ctmbstr cp;
576
577
0
    for ( cp = pString; isWht && cp && *cp; ++cp )
578
0
    {
579
0
        isWht = TY_(IsWhite)( *cp );
580
0
    }
581
0
    return isWht;
582
0
}
583
584
static Bool hasValue( AttVal* av )
585
0
{
586
0
    return ( av && ! IsWhitespace(av->value) );
587
0
}
588
589
/***********************************************************************
590
* IsPlaceholderAlt
591
*  
592
* Checks to see if there is an image and photo place holder contained
593
* in the ALT text.
594
*
595
* Returns 'yes' if there is, 'no' if not.
596
***********************************************************************/
597
598
static Bool IsPlaceholderAlt( ctmbstr txt )
599
0
{
600
0
    return ( strstr(txt, "image") != NULL || 
601
0
             strstr(txt, "photo") != NULL );
602
0
}
603
604
605
/***********************************************************************
606
* IsPlaceholderTitle
607
*  
608
* Checks to see if there is an TITLE place holder contained
609
* in the 'ALT' text.
610
*
611
* Returns 'yes' if there is, 'no' if not.
612
613
static Bool IsPlaceHolderTitle( ctmbstr txt )
614
{
615
    return ( strstr(txt, "title") != NULL );
616
}
617
***********************************************************************/
618
619
620
/***********************************************************************
621
* IsPlaceHolderObject
622
*  
623
* Checks to see if there is an OBJECT place holder contained
624
* in the 'ALT' text.
625
*
626
* Returns 'yes' if there is, 'no' if not.
627
***********************************************************************/
628
629
static Bool IsPlaceHolderObject( ctmbstr txt )
630
0
{
631
0
    return ( strstr(txt, "object") != NULL );
632
0
}
633
634
635
/**********************************************************
636
* EndsWithBytes
637
*
638
* Checks to see if the ALT text ends with 'bytes'
639
* Returns 'yes', if true, 'no' otherwise.
640
**********************************************************/
641
642
static Bool EndsWithBytes( ctmbstr txt )
643
0
{
644
0
    uint len = TY_(tmbstrlen)( txt );
645
0
    return ( len >= 5 && TY_(tmbstrcmp)(txt+len-5, "bytes") == 0 );
646
0
}
647
648
649
/*******************************************************
650
* textFromOneNode
651
*
652
* Returns a list of characters contained within one
653
* text node.
654
*******************************************************/
655
656
static ctmbstr textFromOneNode( TidyDocImpl* doc, Node* node )
657
0
{
658
0
    uint i;
659
0
    uint x = 0;
660
0
    tmbstr txt = doc->access.text;
661
    
662
0
    if ( node )
663
0
    {
664
        /* Copy contents of a text node */
665
0
        for (i = node->start; i < node->end; ++i, ++x )
666
0
        {
667
0
            txt[x] = doc->lexer->lexbuf[i];
668
669
            /* Check buffer overflow */
670
0
            if ( x >= sizeof(doc->access.text)-1 )
671
0
                break;
672
0
        }
673
0
    }
674
675
0
    txt[x] = '\0';
676
0
    return txt;
677
0
}
678
679
680
/*********************************************************
681
* getTextNode
682
*
683
* Locates text nodes within a container element.
684
* Retrieves text that are found contained within 
685
* text nodes, and concatenates the text.
686
*********************************************************/
687
    
688
static void getTextNode( TidyDocImpl* doc, Node* node )
689
0
{
690
0
    tmbstr txtnod = doc->access.textNode;       
691
    
692
    /* 
693
       Continues to traverse through container element until it no
694
       longer contains any more contents 
695
    */
696
697
    /* If the tag of the node is NULL, then grab the text within the node */
698
0
    if ( TY_(nodeIsText)(node) )
699
0
    {
700
0
        uint i;
701
702
        /* Retrieves each character found within the text node */
703
0
        for (i = node->start; i < node->end; i++)
704
0
        {
705
            /* The text must not exceed buffer */
706
0
            if ( doc->access.counter >= TEXTBUF_SIZE-1 )
707
0
                return;
708
709
0
            txtnod[ doc->access.counter++ ] = doc->lexer->lexbuf[i];
710
0
        }
711
712
        /* Traverses through the contents within a container element */
713
0
        for ( node = node->content; node != NULL; node = node->next )
714
0
            getTextNode( doc, node );
715
0
    }   
716
0
}
717
718
719
/**********************************************************
720
* getTextNodeClear
721
*
722
* Clears the current 'textNode' and reloads it with new
723
* text.  The textNode must be cleared before use.
724
**********************************************************/
725
726
static tmbstr getTextNodeClear( TidyDocImpl* doc, Node* node )
727
0
{
728
    /* Clears list */
729
0
    TidyClearMemory( doc->access.textNode, TEXTBUF_SIZE );
730
0
    doc->access.counter = 0;
731
732
0
    getTextNode( doc, node->content );
733
0
    return doc->access.textNode;
734
0
}
735
736
/**********************************************************
737
* LevelX_Enabled
738
*
739
* Tell whether access "X" is enabled.
740
**********************************************************/
741
742
static Bool Level1_Enabled( TidyDocImpl* doc )
743
0
{
744
0
   return doc->access.PRIORITYCHK == 1 ||
745
0
          doc->access.PRIORITYCHK == 2 ||
746
0
          doc->access.PRIORITYCHK == 3;
747
0
}
748
static Bool Level2_Enabled( TidyDocImpl* doc )
749
0
{
750
0
    return doc->access.PRIORITYCHK == 2 ||
751
0
           doc->access.PRIORITYCHK == 3;
752
0
}
753
static Bool Level3_Enabled( TidyDocImpl* doc )
754
0
{
755
0
    return doc->access.PRIORITYCHK == 3;
756
0
}
757
758
/********************************************************
759
* CheckColorAvailable
760
*
761
* Verify that information conveyed with color is 
762
* available without color.
763
********************************************************/
764
765
static void CheckColorAvailable( TidyDocImpl* doc, Node* node )
766
0
{
767
0
    if (Level1_Enabled( doc ))
768
0
    {
769
0
        if ( nodeIsIMG(node) )
770
0
            TY_(ReportAccessError)( doc, node, INFORMATION_NOT_CONVEYED_IMAGE );
771
772
0
        else if ( nodeIsAPPLET(node) )
773
0
            TY_(ReportAccessError)( doc, node, INFORMATION_NOT_CONVEYED_APPLET );
774
775
0
        else if ( nodeIsOBJECT(node) )
776
0
            TY_(ReportAccessError)( doc, node, INFORMATION_NOT_CONVEYED_OBJECT );
777
778
0
        else if ( nodeIsSCRIPT(node) )
779
0
            TY_(ReportAccessError)( doc, node, INFORMATION_NOT_CONVEYED_SCRIPT );
780
781
0
        else if ( nodeIsINPUT(node) )
782
0
            TY_(ReportAccessError)( doc, node, INFORMATION_NOT_CONVEYED_INPUT );
783
0
    }
784
0
}
785
786
/*********************************************************************
787
* CheckColorContrast
788
*
789
* Checks elements for color contrast.  Must have valid contrast for
790
* valid visibility.
791
*
792
* This logic is extremely fragile as it does not recognize
793
* the fact that color is inherited by many components and
794
* that BG and FG colors are often set separately.  E.g. the
795
* background color may be set by for the body or a table 
796
* or a cell.  The foreground color may be set by any text
797
* element (p, h1, h2, input, textarea), either explicitly
798
* or by style.  Ergo, this test will not handle most real
799
* world cases.  It's a start, however.
800
*********************************************************************/
801
802
static void CheckColorContrast( TidyDocImpl* doc, Node* node )
803
0
{
804
0
    int rgbBG[3] = {255,255,255};   /* Black text on white BG */
805
806
0
    if (Level3_Enabled( doc ))
807
0
    {
808
0
        Bool gotBG = yes;
809
0
        AttVal* av;
810
811
        /* Check for 'BGCOLOR' first to compare with other color attributes */
812
0
        for ( av = node->attributes; av; av = av->next )
813
0
        {            
814
0
            if ( attrIsBGCOLOR(av) )
815
0
            {
816
0
                if ( hasValue(av) )
817
0
                    gotBG = GetRgb( av->value, rgbBG );
818
0
            }
819
0
        }
820
        
821
        /* 
822
           Search for COLOR attributes to compare with background color
823
           Must have valid colour contrast
824
        */
825
0
        for ( av = node->attributes; gotBG && av != NULL; av = av->next )
826
0
        {
827
0
            uint errcode = 0;
828
0
            if ( attrIsTEXT(av) )
829
0
                errcode = COLOR_CONTRAST_TEXT;
830
0
            else if ( attrIsLINK(av) )
831
0
                errcode = COLOR_CONTRAST_LINK;
832
0
            else if ( attrIsALINK(av) )
833
0
                errcode = COLOR_CONTRAST_ACTIVE_LINK;
834
0
            else if ( attrIsVLINK(av) )
835
0
                errcode = COLOR_CONTRAST_VISITED_LINK;
836
837
0
            if ( errcode && hasValue(av) )
838
0
            {
839
0
                int rgbFG[3] = {0, 0, 0};  /* Black text */
840
841
0
                if ( GetRgb(av->value, rgbFG) &&
842
0
                     !CompareColors(rgbBG, rgbFG) )
843
0
                {
844
0
                    TY_(ReportAccessError)( doc, node, errcode );
845
0
                }
846
0
            }
847
0
        }
848
0
    }
849
0
}
850
851
852
/**************************************************************
853
* CompareColors
854
*
855
* Compares two RGB colors for good contrast.
856
**************************************************************/
857
static int minmax( int i1, int i2 )
858
0
{
859
0
   return MAX(i1, i2) - MIN(i1,i2);
860
0
}
861
static int brightness( const int rgb[3] )
862
0
{
863
0
   return ((rgb[0]*299) + (rgb[1]*587) + (rgb[2]*114)) / 1000;
864
0
}
865
866
static Bool CompareColors( const int rgbBG[3], const int rgbFG[3] )
867
0
{
868
0
    int brightBG = brightness( rgbBG );
869
0
    int brightFG = brightness( rgbFG );
870
871
0
    int diffBright = minmax( brightBG, brightFG );
872
873
0
    int diffColor = minmax( rgbBG[0], rgbFG[0] )
874
0
                  + minmax( rgbBG[1], rgbFG[1] )
875
0
                  + minmax( rgbBG[2], rgbFG[2] );
876
877
0
    return ( diffBright > 180 &&
878
0
             diffColor > 500 );
879
0
}
880
881
882
/*********************************************************************
883
* GetRgb
884
*
885
* Gets the red, green and blue values for this attribute for the 
886
* background.
887
*
888
* Example: If attribute is BGCOLOR="#121005" then red = 18, green = 16,
889
* blue = 5.
890
*********************************************************************/
891
892
static Bool GetRgb( ctmbstr color, int rgb[] )
893
0
{
894
0
    uint x;
895
896
    /* Check if we have a color name */
897
0
    for (x = 0; x < N_COLORS; x++)
898
0
    {
899
0
        if ( strstr(colorNames[x], color) != NULL )
900
0
        {
901
0
            rgb[0] = colorValues[x][0];
902
0
            rgb[1] = colorValues[x][1];
903
0
            rgb[2] = colorValues[x][2];
904
0
            return yes;
905
0
        }
906
0
    }
907
908
    /*
909
       No color name so must be hex values 
910
       Is this a number in hexadecimal format?
911
    */
912
    
913
    /* Must be 7 characters in the RGB value (including '#') */
914
0
    if ( TY_(tmbstrlen)(color) == 7 && color[0] == '#' )
915
0
    {
916
0
        rgb[0] = (ctox(color[1]) * 16) + ctox(color[2]);
917
0
        rgb[1] = (ctox(color[3]) * 16) + ctox(color[4]);
918
0
        rgb[2] = (ctox(color[5]) * 16) + ctox(color[6]);
919
0
        return yes;
920
0
    }
921
0
    return no;
922
0
} 
923
924
925
926
/*******************************************************************
927
* ctox
928
*
929
* Converts a character to a number.
930
* Example: if given character is 'A' then returns 10.
931
*
932
* Returns the number that the character represents. Returns -1 if not a
933
* valid number.
934
*******************************************************************/
935
936
static int ctox( tmbchar ch )
937
0
{
938
0
    if ( ch >= '0' && ch <= '9' )
939
0
    {
940
0
         return ch - '0';
941
0
    }
942
0
    else if ( ch >= 'a' && ch <= 'f' )
943
0
    {
944
0
        return ch - 'a' + 10;
945
0
    }
946
0
    else if ( ch >= 'A' && ch <= 'F' )
947
0
    {
948
0
        return ch - 'A' + 10;
949
0
    }
950
0
    return -1;
951
0
}
952
953
954
/***********************************************************
955
* CheckImage
956
*
957
* Checks all image attributes for specific elements to
958
* check for validity of the values contained within
959
* the attributes.  An appropriate warning message is displayed
960
* to indicate the error.  
961
***********************************************************/
962
963
static void CheckImage( TidyDocImpl* doc, Node* node )
964
0
{
965
0
    Bool HasAlt = no;
966
0
    Bool HasIsMap = no;
967
0
    Bool HasLongDesc = no;
968
0
    Bool HasDLINK = no;
969
0
    Bool HasValidHeight = no;
970
0
    Bool HasValidWidthBullet = no;
971
0
    Bool HasValidWidthHR = no; 
972
0
    Bool HasTriggeredMissingLongDesc = no;
973
974
0
    AttVal* av;
975
                
976
0
    if (Level1_Enabled( doc ))
977
0
    {
978
        /* Checks all image attributes for invalid values within attributes */
979
0
        for (av = node->attributes; av != NULL; av = av->next)
980
0
        {
981
            /* 
982
               Checks for valid ALT attribute.
983
               The length of the alt text must be less than 150 characters 
984
               long.
985
            */
986
0
            if ( attrIsALT(av) )
987
0
            {
988
0
                if (av->value != NULL) 
989
0
                {
990
0
                    if ((TY_(tmbstrlen)(av->value) < 150) &&
991
0
                        (IsPlaceholderAlt (av->value) == no) &&
992
0
                        (IsPlaceHolderObject (av->value) == no) &&
993
0
                        (EndsWithBytes (av->value) == no) &&
994
0
                        (IsImage (av->value) == no))
995
0
                    {
996
0
                        HasAlt = yes;
997
0
                    }
998
999
0
                    else if (TY_(tmbstrlen)(av->value) > 150)
1000
0
                    {
1001
0
                        HasAlt = yes;
1002
0
                        TY_(ReportAccessError)( doc, node, IMG_ALT_SUSPICIOUS_TOO_LONG );
1003
0
                    }
1004
1005
0
                    else if (IsImage (av->value) == yes)
1006
0
                    {
1007
0
                        HasAlt = yes;
1008
0
                        TY_(ReportAccessError)( doc, node, IMG_ALT_SUSPICIOUS_FILENAME);
1009
0
                    }
1010
            
1011
0
                    else if (IsPlaceholderAlt (av->value) == yes)
1012
0
                    {
1013
0
                        HasAlt = yes;
1014
0
                        TY_(ReportAccessError)( doc, node, IMG_ALT_SUSPICIOUS_PLACEHOLDER);
1015
0
                    }
1016
1017
0
                    else if (EndsWithBytes (av->value) == yes)
1018
0
                    {
1019
0
                        HasAlt = yes;
1020
0
                        TY_(ReportAccessError)( doc, node, IMG_ALT_SUSPICIOUS_FILE_SIZE);
1021
0
                    }
1022
0
                }
1023
0
            }
1024
1025
            /* 
1026
               Checks for width values of 'bullets' and 'horizontal
1027
               rules' for validity.
1028
1029
               Valid pixel width for 'bullets' must be < 30, and > 150 for
1030
               horizontal rules.
1031
            */
1032
0
            else if ( attrIsWIDTH(av) )
1033
0
            {
1034
                /* Longdesc attribute needed if width attribute is not present. */
1035
0
                if ( hasValue(av) )
1036
0
                {
1037
0
                    int width = atoi( av->value );
1038
0
                    if ( width < 30 )
1039
0
                        HasValidWidthBullet = yes;
1040
1041
0
                    if ( width > 150 )
1042
0
                        HasValidWidthHR = yes;
1043
0
                }
1044
0
            }
1045
1046
            /* 
1047
               Checks for height values of 'bullets' and horizontal
1048
               rules for validity.
1049
1050
               Valid pixel height for 'bullets' and horizontal rules 
1051
               mustt be < 30.
1052
            */
1053
0
            else if ( attrIsHEIGHT(av) )
1054
0
            {
1055
                /* Longdesc attribute needed if height attribute not present. */
1056
0
                if ( hasValue(av) && atoi(av->value) < 30 )
1057
0
                    HasValidHeight = yes;
1058
0
            }
1059
1060
            /* 
1061
               Checks for longdesc and determines validity.  
1062
               The length of the 'longdesc' must be > 1
1063
            */
1064
0
            else if ( attrIsLONGDESC(av) )
1065
0
            {
1066
0
                if ( hasValue(av) && TY_(tmbstrlen)(av->value) > 1 )
1067
0
                    HasLongDesc = yes;
1068
0
              }
1069
1070
            /* 
1071
               Checks for 'USEMAP' attribute.  Ensures that
1072
               text links are provided for client-side image maps
1073
            */
1074
0
            else if ( attrIsUSEMAP(av) )
1075
0
            {
1076
0
                if ( hasValue(av) )
1077
0
                    doc->access.HasUseMap = yes;
1078
0
            }    
1079
1080
0
            else if ( attrIsISMAP(av) )
1081
0
            {
1082
0
                HasIsMap = yes;
1083
0
            }
1084
0
        }    
1085
        
1086
        
1087
        /* 
1088
            Check to see if a dLINK is present.  The ANCHOR element must
1089
            be present following the IMG element.  The text found between 
1090
            the ANCHOR tags must be < 6 characters long, and must contain
1091
            the letter 'd'.
1092
        */
1093
0
        if ( nodeIsA(node->next) )
1094
0
        {
1095
0
            node = node->next;
1096
            
1097
            /* 
1098
                Node following the anchor must be a text node
1099
                for dLINK to exist 
1100
            */
1101
1102
0
            if (node->content != NULL && (node->content)->tag == NULL)
1103
0
            {
1104
                /* Number of characters found within the text node */
1105
0
                ctmbstr word = textFromOneNode( doc, node->content);
1106
                    
1107
0
                if ((TY_(tmbstrcmp)(word,"d") == 0)||
1108
0
                    (TY_(tmbstrcmp)(word,"D") == 0))
1109
0
                {
1110
0
                    HasDLINK = yes;
1111
0
                }
1112
0
            }
1113
0
        }
1114
                    
1115
        /*
1116
            Special case check for dLINK.  This will occur if there is 
1117
            whitespace between the <img> and <a> elements.  Ignores 
1118
            whitespace and continues check for dLINK.
1119
        */
1120
        
1121
0
        if ( node->next && !node->next->tag )
1122
0
        {
1123
0
            node = node->next;
1124
1125
0
            if ( nodeIsA(node->next) )
1126
0
            {
1127
0
                node = node->next;
1128
1129
                /* 
1130
                    Node following the ANCHOR must be a text node
1131
                    for dLINK to exist 
1132
                */
1133
0
                if (node->content != NULL && node->content->tag == NULL)
1134
0
                {
1135
                    /* Number of characters found within the text node */
1136
0
                    ctmbstr word = textFromOneNode( doc, node->content );
1137
1138
0
                    if ((TY_(tmbstrcmp)(word, "d") == 0)||
1139
0
                        (TY_(tmbstrcmp)(word, "D") == 0))
1140
0
                    {
1141
0
                        HasDLINK = yes;
1142
0
                    }
1143
0
                }
1144
0
            }
1145
0
        }
1146
1147
0
        if ((HasAlt == no)&&
1148
0
            (HasValidWidthBullet == yes)&&
1149
0
            (HasValidHeight == yes))
1150
0
        {
1151
0
        }
1152
1153
0
        if ((HasAlt == no)&&
1154
0
            (HasValidWidthHR == yes)&&
1155
0
            (HasValidHeight == yes))
1156
0
        {
1157
0
        }
1158
1159
0
        if (HasAlt == no)
1160
0
        {
1161
0
            TY_(ReportAccessError)( doc, node, IMG_MISSING_ALT);
1162
0
        }
1163
1164
0
        if ((HasLongDesc == no)&&
1165
0
            (HasValidHeight ==yes)&&
1166
0
            ((HasValidWidthHR == yes)||
1167
0
             (HasValidWidthBullet == yes)))
1168
0
        {
1169
0
            HasTriggeredMissingLongDesc = yes;
1170
0
        }
1171
1172
0
        if (HasTriggeredMissingLongDesc == no)
1173
0
        {
1174
0
            if ((HasDLINK == yes)&&
1175
0
                (HasLongDesc == no))
1176
0
            {
1177
0
                TY_(ReportAccessError)( doc, node, IMG_MISSING_LONGDESC);
1178
0
            }
1179
1180
0
            if ((HasLongDesc == yes)&&
1181
0
                (HasDLINK == no))
1182
0
            {
1183
0
                TY_(ReportAccessError)( doc, node, IMG_MISSING_DLINK);
1184
0
            }
1185
1186
0
            if ((HasLongDesc == no)&&
1187
0
                (HasDLINK == no))
1188
0
            {
1189
0
                TY_(ReportAccessError)( doc, node, IMG_MISSING_LONGDESC_DLINK);
1190
0
            }
1191
0
        }
1192
1193
0
        if (HasIsMap == yes)
1194
0
        {
1195
0
            TY_(ReportAccessError)( doc, node, IMAGE_MAP_SERVER_SIDE_REQUIRES_CONVERSION);
1196
1197
0
            TY_(ReportAccessError)( doc, node, IMG_MAP_SERVER_REQUIRES_TEXT_LINKS);
1198
0
        }
1199
0
    }
1200
0
}
1201
1202
1203
/***********************************************************
1204
* CheckApplet
1205
*
1206
* Checks APPLET element to check for validity pertaining 
1207
* the 'ALT' attribute.  An appropriate warning message is 
1208
* displayed  to indicate the error. An appropriate warning 
1209
* message is displayed to indicate the error.  If no 'ALT'
1210
* text is present, then there must be alternate content
1211
* within the APPLET element.
1212
***********************************************************/
1213
1214
static void CheckApplet( TidyDocImpl* doc, Node* node )
1215
0
{
1216
0
    Bool HasAlt = no;
1217
0
    Bool HasDescription = no;
1218
1219
0
    AttVal* av;
1220
        
1221
0
    if (Level1_Enabled( doc ))
1222
0
    {
1223
        /* Checks for attributes within the APPLET element */
1224
0
        for (av = node->attributes; av != NULL; av = av->next)
1225
0
        {
1226
            /*
1227
               Checks for valid ALT attribute.
1228
               The length of the alt text must be > 4 characters in length
1229
               but must be < 150 characters long.
1230
            */
1231
1232
0
            if ( attrIsALT(av) )
1233
0
            {
1234
0
                if (av->value != NULL)
1235
0
                {
1236
0
                    HasAlt = yes;
1237
0
                }
1238
0
            }
1239
0
        }
1240
1241
0
        if (HasAlt == no)
1242
0
        {
1243
            /* Must have alternate text representation for that element */
1244
0
            if (node->content != NULL) 
1245
0
            {
1246
0
                ctmbstr word = NULL;
1247
1248
0
                if ( node->content->tag == NULL )
1249
0
                    word = textFromOneNode( doc, node->content);
1250
1251
0
                if ( node->content->content != NULL &&
1252
0
                     node->content->content->tag == NULL )
1253
0
                {
1254
0
                    word = textFromOneNode( doc, node->content->content);
1255
0
                }
1256
                
1257
0
                if ( word != NULL && !IsWhitespace(word) )
1258
0
                    HasDescription = yes;
1259
0
            }
1260
0
        }
1261
1262
0
        if ( !HasDescription && !HasAlt )
1263
0
        {
1264
0
            TY_(ReportAccessError)( doc, node, APPLET_MISSING_ALT );
1265
0
        }
1266
0
    }
1267
0
}
1268
1269
1270
/*******************************************************************
1271
* CheckObject
1272
*
1273
* Checks to verify whether the OBJECT element contains
1274
* 'ALT' text, and to see that the sound file selected is 
1275
* of a valid sound file type.  OBJECT must have an alternate text 
1276
* representation.
1277
*******************************************************************/
1278
1279
static void CheckObject( TidyDocImpl* doc, Node* node )
1280
0
{
1281
0
    Bool HasAlt = no;
1282
0
    Bool HasDescription = no;
1283
1284
0
    if (Level1_Enabled( doc ))
1285
0
    {
1286
0
        if ( node->content != NULL)
1287
0
        {
1288
0
            if ( node->content->type != TextNode )
1289
0
            {
1290
0
                Node* tnode = node->content;
1291
0
                AttVal* av;
1292
1293
0
                for ( av=tnode->attributes; av; av = av->next )
1294
0
                {
1295
0
                    if ( attrIsALT(av) )
1296
0
                    {
1297
0
                        HasAlt = yes;
1298
0
                        break;
1299
0
                    }
1300
0
                }
1301
0
            }
1302
1303
            /* Must have alternate text representation for that element */
1304
0
            if ( !HasAlt )
1305
0
            {
1306
0
                ctmbstr word = NULL;
1307
1308
0
                if ( TY_(nodeIsText)(node->content) )
1309
0
                    word = textFromOneNode( doc, node->content );
1310
1311
0
                if ( word == NULL &&
1312
0
                     TY_(nodeIsText)(node->content->content) )
1313
0
                {
1314
0
                    word = textFromOneNode( doc, node->content->content );
1315
0
                }
1316
                    
1317
0
                if ( word != NULL && !IsWhitespace(word) )
1318
0
                    HasDescription = yes;
1319
0
            }
1320
0
        }
1321
1322
0
        if ( !HasAlt && !HasDescription )
1323
0
        {
1324
0
            TY_(ReportAccessError)( doc, node, OBJECT_MISSING_ALT );
1325
0
        }
1326
0
    }
1327
0
}
1328
1329
1330
/***************************************************************
1331
* CheckMissingStyleSheets
1332
*
1333
* Ensures that stylesheets are used to control the presentation.
1334
***************************************************************/
1335
1336
static Bool CheckMissingStyleSheets( TidyDocImpl* doc, Node* node )
1337
0
{
1338
0
    AttVal* av;
1339
0
    Node* content;
1340
0
    Bool sspresent = no;
1341
1342
0
    for ( content = node->content;
1343
0
          !sspresent && content != NULL;
1344
0
          content = content->next )
1345
0
    {
1346
0
        sspresent = ( nodeIsLINK(content)  ||
1347
0
                      nodeIsSTYLE(content) ||
1348
0
                      nodeIsFONT(content)  ||
1349
0
                      nodeIsBASEFONT(content) );
1350
1351
0
        for ( av = content->attributes;
1352
0
              !sspresent && av != NULL;
1353
0
              av = av->next )
1354
0
        {
1355
0
            sspresent = ( attrIsSTYLE(av) || attrIsTEXT(av)  ||
1356
0
                          attrIsVLINK(av) || attrIsALINK(av) ||
1357
0
                          attrIsLINK(av) );
1358
1359
0
            if ( !sspresent && attrIsREL(av) )
1360
0
            {
1361
0
                sspresent = AttrValueIs(av, "stylesheet");
1362
0
            }
1363
0
        }
1364
1365
0
        if ( ! sspresent )
1366
0
            sspresent = CheckMissingStyleSheets( doc, content );
1367
0
    }
1368
0
    return sspresent;
1369
0
}
1370
1371
1372
/*******************************************************************
1373
* CheckFrame
1374
*
1375
* Checks if the URL is valid and to check if a 'LONGDESC' is needed
1376
* within the FRAME element.  If a 'LONGDESC' is needed, the value must 
1377
* be valid. The URL must end with the file extension, htm, or html. 
1378
* Also, checks to ensure that the 'SRC' and 'TITLE' values are valid. 
1379
*******************************************************************/
1380
1381
static void CheckFrame( TidyDocImpl* doc, Node* node )
1382
0
{
1383
0
    Bool HasTitle = no;
1384
0
    AttVal* av;
1385
1386
0
    doc->access.numFrames++;
1387
1388
0
    if (Level1_Enabled( doc ))
1389
0
    {
1390
        /* Checks for attributes within the FRAME element */
1391
0
        for (av = node->attributes; av != NULL; av = av->next)
1392
0
        {
1393
            /* Checks if 'LONGDESC' value is valid only if present */
1394
0
            if ( attrIsLONGDESC(av) )
1395
0
            {
1396
0
                if ( hasValue(av) && TY_(tmbstrlen)(av->value) > 1 )
1397
0
                {
1398
0
                    doc->access.HasCheckedLongDesc++;
1399
0
                }
1400
0
            }
1401
1402
            /* Checks for valid 'SRC' value within the frame element */
1403
0
            else if ( attrIsSRC(av) )
1404
0
            {
1405
0
                if ( hasValue(av) && !IsValidSrcExtension(av->value) )
1406
0
                {
1407
0
                    TY_(ReportAccessError)( doc, node, FRAME_SRC_INVALID );
1408
0
                }
1409
0
            }
1410
1411
            /* Checks for valid 'TITLE' value within frame element */
1412
0
            else if ( attrIsTITLE(av) )
1413
0
            {
1414
0
                if ( hasValue(av) )
1415
0
                    HasTitle = yes;
1416
1417
0
                if ( !HasTitle )
1418
0
                {
1419
0
                    if ( av->value == NULL || TY_(tmbstrlen)(av->value) == 0 )
1420
0
                    {
1421
0
                        HasTitle = yes;
1422
0
                        TY_(ReportAccessError)( doc, node, FRAME_TITLE_INVALID_NULL);
1423
0
                    }
1424
0
                    else
1425
0
                    {
1426
0
                        if ( IsWhitespace(av->value) && TY_(tmbstrlen)(av->value) > 0 )
1427
0
                        {
1428
0
                            HasTitle = yes;
1429
0
                            TY_(ReportAccessError)( doc, node, FRAME_TITLE_INVALID_SPACES );
1430
0
                        }
1431
0
                    }
1432
0
                }
1433
0
            }
1434
0
        }
1435
1436
0
        if ( !HasTitle )
1437
0
        {
1438
0
            TY_(ReportAccessError)( doc, node, FRAME_MISSING_TITLE);
1439
0
        }
1440
1441
0
        if ( doc->access.numFrames==3 && doc->access.HasCheckedLongDesc<3 )
1442
0
        {
1443
0
            doc->access.numFrames = 0;
1444
0
            TY_(ReportAccessError)( doc, node, FRAME_MISSING_LONGDESC );
1445
0
        }
1446
0
    }
1447
0
}
1448
1449
1450
/****************************************************************
1451
* CheckIFrame
1452
*
1453
* Checks if 'SRC' value is valid.  Must end in appropriate
1454
* file extension.
1455
****************************************************************/
1456
1457
static void CheckIFrame( TidyDocImpl* doc, Node* node )
1458
0
{
1459
0
    if (Level1_Enabled( doc ))
1460
0
    {
1461
        /* Checks for valid 'SRC' value within the IFRAME element */
1462
0
        AttVal* av = attrGetSRC( node );
1463
0
        if ( hasValue(av) )
1464
0
        {
1465
0
            if ( !IsValidSrcExtension(av->value) )
1466
0
                TY_(ReportAccessError)( doc, node, FRAME_SRC_INVALID );
1467
0
        }
1468
0
    }
1469
0
}
1470
1471
1472
/**********************************************************************
1473
* CheckAnchorAccess
1474
*
1475
* Checks that the sound file is valid, and to ensure that
1476
* text transcript is present describing the 'HREF' within the 
1477
* ANCHOR element.  Also checks to see ensure that the 'TARGET' attribute
1478
* (if it exists) is not NULL and does not contain '_new' or '_blank'.
1479
**********************************************************************/
1480
1481
static void CheckAnchorAccess( TidyDocImpl* doc, Node* node )
1482
0
{
1483
0
    AttVal* av;
1484
0
    Bool HasDescription = no;
1485
0
    Bool HasTriggeredLink = no;
1486
1487
    /* Checks for attributes within the ANCHOR element */
1488
0
    for ( av = node->attributes; av != NULL; av = av->next )
1489
0
    {
1490
0
        if (Level1_Enabled( doc ))
1491
0
        {
1492
            /* Must be of valid sound file type */
1493
0
            if ( attrIsHREF(av) )
1494
0
            {
1495
0
                if ( hasValue(av) )
1496
0
                {
1497
0
                    tmbchar ext[ 20 ];
1498
0
                    GetFileExtension (av->value, ext, sizeof(ext) );
1499
1500
                    /* Checks to see if multimedia is used */
1501
0
                    if ( IsValidMediaExtension(av->value) )
1502
0
                    {
1503
0
                        TY_(ReportAccessError)( doc, node, MULTIMEDIA_REQUIRES_TEXT );
1504
0
                    }
1505
            
1506
                    /* 
1507
                        Checks for validity of sound file, and checks to see if 
1508
                        the file is described within the document, or by a link
1509
                        that is present which gives the description.
1510
                    */
1511
0
                    if ( TY_(tmbstrlen)(ext) < 6 && TY_(tmbstrlen)(ext) > 0 )
1512
0
                    {
1513
0
                        int errcode = IsSoundFile( av->value );
1514
0
                        if ( errcode )
1515
0
                        {
1516
0
                            if (node->next != NULL)
1517
0
                            {
1518
0
                                if (node->next->tag == NULL)
1519
0
                                {
1520
0
                                    ctmbstr word = textFromOneNode( doc, node->next);
1521
                                
1522
                                    /* Must contain at least one letter in the text */
1523
0
                                    if (IsWhitespace (word) == no)
1524
0
                                    {
1525
0
                                        HasDescription = yes;
1526
0
                                    }
1527
0
                                }
1528
0
                            }
1529
1530
                            /* Must contain text description of sound file */
1531
0
                            if ( !HasDescription )
1532
0
                            {
1533
0
                                TY_(ReportAccessError)( doc, node, errcode );
1534
0
                            }
1535
0
                        }
1536
0
                    }
1537
0
                }
1538
0
            }
1539
0
        }
1540
1541
0
        if (Level2_Enabled( doc ))
1542
0
        {
1543
            /* Checks 'TARGET' attribute for validity if it exists */
1544
0
            if ( attrIsTARGET(av) )
1545
0
            {
1546
0
                if (AttrValueIs(av, "_new"))
1547
0
                {
1548
0
                    TY_(ReportAccessError)( doc, node, NEW_WINDOWS_REQUIRE_WARNING_NEW);
1549
0
                }
1550
0
                else if (AttrValueIs(av, "_blank"))
1551
0
                {
1552
0
                    TY_(ReportAccessError)( doc, node, NEW_WINDOWS_REQUIRE_WARNING_BLANK);
1553
0
                }
1554
0
            }
1555
0
        }
1556
0
    }
1557
    
1558
0
    if (Level2_Enabled( doc ))
1559
0
    {
1560
0
        if ((node->content != NULL)&&
1561
0
            (node->content->tag == NULL))
1562
0
        {
1563
0
            ctmbstr word = textFromOneNode( doc, node->content);
1564
1565
0
            if ((word != NULL)&&
1566
0
                (IsWhitespace (word) == no))
1567
0
            {
1568
0
                if (TY_(tmbstrcmp) (word, "more") == 0)
1569
0
                {
1570
0
                    HasTriggeredLink = yes;
1571
0
                }
1572
1573
0
                if (TY_(tmbstrcmp) (word, "click here") == 0)
1574
0
                {
1575
0
                    TY_(ReportAccessError)( doc, node, LINK_TEXT_NOT_MEANINGFUL_CLICK_HERE);
1576
0
                }
1577
1578
0
                if (HasTriggeredLink == no)
1579
0
                {
1580
0
                    if (TY_(tmbstrlen)(word) < 6)
1581
0
                    {
1582
0
                        TY_(ReportAccessError)( doc, node, LINK_TEXT_NOT_MEANINGFUL);
1583
0
                    }
1584
0
                }
1585
1586
0
                if (TY_(tmbstrlen)(word) > 60)
1587
0
                {
1588
0
                    TY_(ReportAccessError)( doc, node, LINK_TEXT_TOO_LONG);
1589
0
                }
1590
1591
0
            }
1592
0
        }
1593
        
1594
0
        if (node->content == NULL)
1595
0
        {
1596
0
            TY_(ReportAccessError)( doc, node, LINK_TEXT_MISSING);
1597
0
        }
1598
0
    }
1599
0
}
1600
1601
1602
/************************************************************
1603
* CheckArea
1604
*
1605
* Checks attributes within the AREA element to 
1606
* determine if the 'ALT' text and 'HREF' values are valid.
1607
* Also checks to see ensure that the 'TARGET' attribute
1608
* (if it exists) is not NULL and does not contain '_new' 
1609
* or '_blank'.
1610
************************************************************/
1611
1612
static void CheckArea( TidyDocImpl* doc, Node* node )
1613
0
{
1614
0
    Bool HasAlt = no;
1615
0
    AttVal* av;
1616
1617
    /* Checks all attributes within the AREA element */
1618
0
    for (av = node->attributes; av != NULL; av = av->next)
1619
0
    {
1620
0
        if (Level1_Enabled( doc ))
1621
0
        {
1622
            /*
1623
              Checks for valid ALT attribute.
1624
              The length of the alt text must be > 4 characters long
1625
              but must be less than 150 characters long.
1626
            */
1627
                
1628
0
            if ( attrIsALT(av) )
1629
0
            {
1630
                /* The check for validity */
1631
0
                if (av->value != NULL) 
1632
0
                {
1633
0
                    HasAlt = yes;
1634
0
                }
1635
0
            }
1636
0
        }
1637
1638
0
        if (Level2_Enabled( doc ))
1639
0
        {
1640
0
            if ( attrIsTARGET(av) )
1641
0
            {
1642
0
                if (AttrValueIs(av, "_new"))
1643
0
                {
1644
0
                    TY_(ReportAccessError)( doc, node, NEW_WINDOWS_REQUIRE_WARNING_NEW);
1645
0
                }
1646
0
                else if (AttrValueIs(av, "_blank"))
1647
0
                {
1648
0
                    TY_(ReportAccessError)( doc, node, NEW_WINDOWS_REQUIRE_WARNING_BLANK);
1649
0
                }
1650
0
            }
1651
0
        }
1652
0
    }
1653
1654
0
    if (Level1_Enabled( doc ))
1655
0
    {
1656
        /* AREA must contain alt text */
1657
0
        if (HasAlt == no)
1658
0
        {
1659
0
            TY_(ReportAccessError)( doc, node, AREA_MISSING_ALT);
1660
0
        }    
1661
0
    }
1662
0
}
1663
1664
1665
/***************************************************
1666
* CheckScript
1667
*
1668
* Checks the SCRIPT element to ensure that a
1669
* NOSCRIPT section follows the SCRIPT.  
1670
***************************************************/
1671
1672
static void CheckScriptAcc( TidyDocImpl* doc, Node* node )
1673
0
{
1674
0
    if (Level1_Enabled( doc ))
1675
0
    {
1676
        /* NOSCRIPT element must appear immediately following SCRIPT element */
1677
0
        if ( node->next == NULL || !nodeIsNOSCRIPT(node->next) )
1678
0
        {
1679
0
            TY_(ReportAccessError)( doc, node, SCRIPT_MISSING_NOSCRIPT);
1680
0
        }
1681
0
    }
1682
0
}
1683
1684
1685
/**********************************************************
1686
* CheckRows
1687
*
1688
* Check to see that each table has a row of headers if
1689
* a column of columns doesn't exist. 
1690
**********************************************************/
1691
1692
static void CheckRows( TidyDocImpl* doc, Node* node )
1693
0
{
1694
0
    int numTR = 0;
1695
0
    int numValidTH = 0;
1696
    
1697
0
    doc->access.CheckedHeaders++;
1698
1699
0
    for (; node != NULL; node = node->next )
1700
0
    {
1701
0
        numTR++;
1702
0
        if ( nodeIsTH(node->content) )
1703
0
        {
1704
0
            doc->access.HasTH = yes;            
1705
0
            if ( TY_(nodeIsText)(node->content->content) )
1706
0
            {
1707
0
                ctmbstr word = textFromOneNode( doc, node->content->content);
1708
0
                if ( !IsWhitespace(word) )
1709
0
                    numValidTH++;
1710
0
            }
1711
0
        }
1712
0
    }
1713
1714
0
    if (numTR == numValidTH)
1715
0
        doc->access.HasValidRowHeaders = yes;
1716
1717
0
    if ( numTR >= 2 &&
1718
0
         numTR > numValidTH &&
1719
0
         numValidTH >= 2 &&
1720
0
         doc->access.HasTH == yes )
1721
0
        doc->access.HasInvalidRowHeader = yes;
1722
0
}
1723
1724
1725
/**********************************************************
1726
* CheckColumns
1727
*
1728
* Check to see that each table has a column of headers if
1729
* a row of columns doesn't exist.  
1730
**********************************************************/
1731
1732
static void CheckColumns( TidyDocImpl* doc, Node* node )
1733
0
{
1734
0
    Node* tnode;
1735
0
    int numTH = 0;
1736
0
    Bool isMissingHeader = no;
1737
1738
0
    doc->access.CheckedHeaders++;
1739
1740
    /* Table must have row of headers if headers for columns don't exist */
1741
0
    if ( nodeIsTH(node->content) )
1742
0
    {
1743
0
        doc->access.HasTH = yes;
1744
1745
0
        for ( tnode = node->content; tnode; tnode = tnode->next )
1746
0
        {
1747
0
            if ( nodeIsTH(tnode) )
1748
0
            {
1749
0
                if ( TY_(nodeIsText)(tnode->content) )
1750
0
                {
1751
0
                    ctmbstr word = textFromOneNode( doc, tnode->content);
1752
0
                    if ( !IsWhitespace(word) )
1753
0
                        numTH++;
1754
0
                }
1755
0
            }
1756
0
            else
1757
0
            {
1758
0
                isMissingHeader = yes;
1759
0
            }
1760
0
        }
1761
0
    }
1762
1763
0
    if ( !isMissingHeader && numTH > 0 )
1764
0
        doc->access.HasValidColumnHeaders = yes;
1765
1766
0
    if ( isMissingHeader && numTH >= 2 )
1767
0
        doc->access.HasInvalidColumnHeader = yes;
1768
0
}
1769
1770
1771
/*****************************************************
1772
* CheckTH
1773
*
1774
* Checks to see if the header provided for a table
1775
* requires an abbreviation. (only required if the 
1776
* length of the header is greater than 15 characters)
1777
*****************************************************/
1778
1779
static void CheckTH( TidyDocImpl* doc, Node* node )
1780
0
{
1781
0
    Bool HasAbbr = no;
1782
0
    ctmbstr word = NULL;
1783
0
    AttVal* av;
1784
1785
0
    if (Level3_Enabled( doc ))
1786
0
    {
1787
        /* Checks TH element for 'ABBR' attribute */
1788
0
        for (av = node->attributes; av != NULL; av = av->next)
1789
0
        {
1790
0
            if ( attrIsABBR(av) )
1791
0
            {
1792
                /* Value must not be NULL and must be less than 15 characters */
1793
0
                if ((av->value != NULL)&&
1794
0
                    (IsWhitespace (av->value) == no))
1795
0
                {
1796
0
                    HasAbbr = yes;
1797
0
                }
1798
1799
0
                if ((av->value == NULL)||
1800
0
                    (TY_(tmbstrlen)(av->value) == 0))
1801
0
                {
1802
0
                    HasAbbr = yes;
1803
0
                    TY_(ReportAccessError)( doc, node, TABLE_MAY_REQUIRE_HEADER_ABBR_NULL);
1804
0
                }
1805
                
1806
0
                if ((IsWhitespace (av->value) == yes)&&
1807
0
                    (TY_(tmbstrlen)(av->value) > 0))
1808
0
                {
1809
0
                    HasAbbr = yes;
1810
0
                    TY_(ReportAccessError)( doc, node, TABLE_MAY_REQUIRE_HEADER_ABBR_SPACES);
1811
0
                }
1812
0
            }
1813
0
        }
1814
1815
        /* If the header is greater than 15 characters, an abbreviation is needed */
1816
0
        word = textFromOneNode( doc, node->content);
1817
1818
0
        if ((word != NULL)&&
1819
0
            (IsWhitespace (word) == no))
1820
0
        {
1821
            /* Must have 'ABBR' attribute if header is > 15 characters */
1822
0
            if ((TY_(tmbstrlen)(word) > 15)&&
1823
0
                (HasAbbr == no))
1824
0
            {
1825
0
                TY_(ReportAccessError)( doc, node, TABLE_MAY_REQUIRE_HEADER_ABBR);
1826
0
            }
1827
0
        }
1828
0
    }
1829
0
}
1830
1831
1832
/*****************************************************************
1833
* CheckMultiHeaders
1834
*
1835
* Layout tables should make sense when linearized.
1836
* TABLE must contain at least one TH element.
1837
* This technique applies only to tables used for layout purposes, 
1838
* not to data tables. Checks for column of multiple headers.
1839
*****************************************************************/
1840
1841
static void CheckMultiHeaders( TidyDocImpl* doc, Node* node )
1842
0
{
1843
0
    Node* TNode;
1844
0
    Node* temp;
1845
    
1846
0
    Bool validColSpanRows = yes;
1847
0
    Bool validColSpanColumns = yes;
1848
1849
0
    int flag = 0;
1850
1851
0
    if (Level1_Enabled( doc ))
1852
0
    {
1853
0
        if (node->content != NULL)
1854
0
        {
1855
0
            TNode = node->content;
1856
1857
            /* 
1858
               Checks for column of multiple headers found 
1859
               within a data table. 
1860
            */
1861
0
            while (TNode != NULL)
1862
0
            {
1863
0
                if ( nodeIsTR(TNode) )
1864
0
                {
1865
0
                    flag = 0; /* Issue #168 - access test 5-2-1-2 */
1866
0
                    if (TNode->content != NULL)
1867
0
                    {
1868
0
                        temp = TNode->content;
1869
1870
                        /* The number of TH elements found within TR element */
1871
0
                        if (flag == 0)
1872
0
                        {
1873
0
                            while (temp != NULL)
1874
0
                            {
1875
                                /* 
1876
                                   Must contain at least one TH element 
1877
                                   within in the TR element 
1878
                                */
1879
0
                                if ( nodeIsTH(temp) )
1880
0
                                {
1881
0
                                    AttVal* av;
1882
0
                                    for (av = temp->attributes; av != NULL; av = av->next)
1883
0
                                    {
1884
0
                                        if ( attrIsCOLSPAN(av)
1885
0
                                             && (atoi(av->value) > 1) )
1886
0
                                            validColSpanColumns = no;
1887
1888
0
                                        if ( attrIsROWSPAN(av)
1889
0
                                             && (atoi(av->value) > 1) )
1890
0
                                            validColSpanRows = no;
1891
0
                                    }
1892
0
                                }
1893
1894
0
                                temp = temp->next;
1895
0
                            }    
1896
1897
0
                            flag = 1;
1898
0
                        }
1899
0
                    }
1900
0
                }
1901
            
1902
0
                TNode = TNode->next;
1903
0
            }
1904
1905
            /* Displays HTML 4 Table Algorithm when multiple column of headers used */
1906
0
            if (validColSpanRows == no)
1907
0
            {
1908
0
                TY_(ReportAccessError)( doc, node, DATA_TABLE_REQUIRE_MARKUP_ROW_HEADERS );
1909
0
                TY_(Dialogue)( doc, TEXT_HTML_T_ALGORITHM );
1910
0
            }
1911
1912
0
            if (validColSpanColumns == no)
1913
0
            {
1914
0
                TY_(ReportAccessError)( doc, node, DATA_TABLE_REQUIRE_MARKUP_COLUMN_HEADERS );
1915
0
                TY_(Dialogue)( doc, TEXT_HTML_T_ALGORITHM );
1916
0
            }
1917
0
        }
1918
0
    }
1919
0
}
1920
1921
1922
/****************************************************
1923
* CheckTable
1924
*
1925
* Checks the TABLE element to ensure that the
1926
* table is not missing any headers.  Must have either
1927
* a row or column of headers.  
1928
****************************************************/
1929
1930
static void CheckTable( TidyDocImpl* doc, Node* node )
1931
0
{
1932
0
    Node* TNode;
1933
0
    Node* temp;
1934
1935
0
    tmbstr word = NULL;
1936
1937
0
    int numTR = 0;
1938
1939
0
    Bool HasSummary = no;
1940
0
    Bool HasCaption = no;
1941
1942
0
    if (Level3_Enabled( doc ))
1943
0
    {
1944
0
        AttVal* av;
1945
        /* Table must have a 'SUMMARY' describing the purpose of the table */
1946
0
        for (av = node->attributes; av != NULL; av = av->next)
1947
0
        {
1948
0
            if ( attrIsSUMMARY(av) )
1949
0
            {
1950
0
                if ( hasValue(av) )
1951
0
                {
1952
0
                    HasSummary = yes;
1953
1954
0
                    if (AttrContains(av, "summary") && 
1955
0
                        AttrContains(av, "table"))
1956
0
                    {
1957
0
                        TY_(ReportAccessError)( doc, node, TABLE_SUMMARY_INVALID_PLACEHOLDER );
1958
0
                    }
1959
0
                }
1960
1961
0
                if ( av->value == NULL || TY_(tmbstrlen)(av->value) == 0 )
1962
0
                {
1963
0
                    HasSummary = yes;
1964
0
                    TY_(ReportAccessError)( doc, node, TABLE_SUMMARY_INVALID_NULL );
1965
0
                }
1966
0
                else if ( IsWhitespace(av->value) && TY_(tmbstrlen)(av->value) > 0 )
1967
0
                {
1968
0
                    HasSummary = yes;
1969
0
                    TY_(ReportAccessError)( doc, node, TABLE_SUMMARY_INVALID_SPACES );
1970
0
                }
1971
0
            }
1972
0
        }
1973
1974
        /* TABLE must have content. */
1975
0
        if (node->content == NULL)
1976
0
        {
1977
0
            TY_(ReportAccessError)( doc, node, DATA_TABLE_MISSING_HEADERS);
1978
        
1979
0
            return;
1980
0
        }
1981
0
    }
1982
1983
0
    if (Level1_Enabled( doc ))
1984
0
    {
1985
        /* Checks for multiple headers */
1986
0
        CheckMultiHeaders( doc, node );
1987
0
    }
1988
    
1989
0
    if (Level2_Enabled( doc ))
1990
0
    {
1991
        /* Table must have a CAPTION describing the purpose of the table */
1992
0
        if ( nodeIsCAPTION(node->content) )
1993
0
        {
1994
0
            TNode = node->content;
1995
1996
0
            if (TNode->content && TNode->content->tag == NULL)
1997
0
            {
1998
0
                word = getTextNodeClear( doc, TNode);
1999
0
            }
2000
2001
0
            if ( !IsWhitespace(word) )
2002
0
            {
2003
0
                HasCaption = yes;
2004
0
            }
2005
0
        }
2006
2007
0
        if (HasCaption == no)
2008
0
        {
2009
0
            TY_(ReportAccessError)( doc, node, TABLE_MISSING_CAPTION);
2010
0
        }
2011
0
    }
2012
2013
    
2014
0
    if (node->content != NULL)
2015
0
    {
2016
0
        if ( nodeIsCAPTION(node->content) && nodeIsTR(node->content->next) )
2017
0
        {
2018
0
            CheckColumns( doc, node->content->next );
2019
0
        }
2020
0
        else if ( nodeIsTR(node->content) )
2021
0
        {
2022
0
            CheckColumns( doc, node->content );
2023
0
        }
2024
0
    }
2025
    
2026
0
    if ( ! doc->access.HasValidColumnHeaders )
2027
0
    {
2028
0
        if (node->content != NULL)
2029
0
        {
2030
0
            if ( nodeIsCAPTION(node->content) && nodeIsTR(node->content->next) )
2031
0
            {
2032
0
                CheckRows( doc, node->content->next);
2033
0
            }
2034
0
            else if ( nodeIsTR(node->content) )
2035
0
            {
2036
0
                CheckRows( doc, node->content);
2037
0
            }
2038
0
        }
2039
0
    }
2040
    
2041
    
2042
0
    if (Level3_Enabled( doc ))
2043
0
    {
2044
        /* Suppress warning for missing 'SUMMARY for HTML 2.0 and HTML 3.2 */
2045
0
        if (HasSummary == no)
2046
0
        {
2047
0
            TY_(ReportAccessError)( doc, node, TABLE_MISSING_SUMMARY);
2048
0
        }
2049
0
    }
2050
2051
0
    if (Level2_Enabled( doc ))
2052
0
    {
2053
0
        if (node->content != NULL)
2054
0
        {
2055
0
            temp = node->content;
2056
2057
0
            while (temp != NULL)
2058
0
            {
2059
0
                if ( nodeIsTR(temp) )
2060
0
                {
2061
0
                    numTR++;
2062
0
                }
2063
2064
0
                temp = temp->next;
2065
0
            }
2066
2067
0
            if (numTR == 1)
2068
0
            {
2069
0
                TY_(ReportAccessError)( doc, node, LAYOUT_TABLES_LINEARIZE_PROPERLY);
2070
0
            }
2071
0
        }
2072
    
2073
0
        if ( doc->access.HasTH )
2074
0
        {
2075
0
            TY_(ReportAccessError)( doc, node, LAYOUT_TABLE_INVALID_MARKUP);
2076
0
        }
2077
0
    }
2078
2079
0
    if (Level1_Enabled( doc ))
2080
0
    {
2081
0
        if ( doc->access.CheckedHeaders == 2 )
2082
0
        {
2083
0
            if ( !doc->access.HasValidRowHeaders &&
2084
0
                 !doc->access.HasValidColumnHeaders &&
2085
0
                 !doc->access.HasInvalidRowHeader &&
2086
0
                 !doc->access.HasInvalidColumnHeader  )
2087
0
            {
2088
0
                TY_(ReportAccessError)( doc, node, DATA_TABLE_MISSING_HEADERS);
2089
0
            }
2090
2091
0
            if ( !doc->access.HasValidRowHeaders && 
2092
0
                 doc->access.HasInvalidRowHeader )
2093
0
            {
2094
0
                TY_(ReportAccessError)( doc, node, DATA_TABLE_MISSING_HEADERS_ROW);
2095
0
            }
2096
2097
0
            if ( !doc->access.HasValidColumnHeaders &&
2098
0
                 doc->access.HasInvalidColumnHeader )
2099
0
            {
2100
0
                TY_(ReportAccessError)( doc, node, DATA_TABLE_MISSING_HEADERS_COLUMN);
2101
0
            }
2102
0
        }
2103
0
    }
2104
0
}
2105
2106
2107
/***************************************************
2108
* CheckASCII
2109
* 
2110
* Checks for valid text equivalents for XMP and PRE
2111
* elements for ASCII art.  Ensures that there is
2112
* a skip over link to skip multi-lined ASCII art.
2113
***************************************************/
2114
2115
static void CheckASCII( TidyDocImpl* doc, Node* node )
2116
0
{
2117
0
    Node* temp1;
2118
0
    Node* temp2;
2119
2120
0
    tmbstr skipOver = NULL;
2121
0
    Bool IsAscii = no;
2122
0
    int HasSkipOverLink = 0;
2123
        
2124
0
    uint i, x;
2125
0
    int newLines = -1;
2126
0
    tmbchar compareLetter;
2127
0
    int matchingCount = 0;
2128
0
    AttVal* av;
2129
    
2130
0
    if (Level1_Enabled( doc ) && node->content)
2131
0
    {
2132
        /* 
2133
           Checks the text within the PRE and XMP tags to see if ascii 
2134
           art is present 
2135
        */
2136
0
        for (i = node->content->start + 1; i < node->content->end; i++)
2137
0
        {
2138
0
            matchingCount = 0;
2139
2140
            /* Counts the number of lines of text */
2141
0
            if (doc->lexer->lexbuf[i] == '\n')
2142
0
            {
2143
0
                newLines++;
2144
0
            }
2145
            
2146
0
            compareLetter = doc->lexer->lexbuf[i];
2147
2148
            /* Counts consecutive character matches */
2149
0
            for (x = i; x < i + 5; x++)
2150
0
            {
2151
0
                if (doc->lexer->lexbuf[x] == compareLetter)
2152
0
                {
2153
0
                    matchingCount++;
2154
0
                }
2155
2156
0
                else
2157
0
                {
2158
0
                    break;
2159
0
                }
2160
0
            }
2161
2162
            /* Must have at least 5 consecutive character matches */
2163
0
            if (matchingCount >= 5)
2164
0
            {
2165
0
                break;
2166
0
            }
2167
0
        }
2168
2169
        /* 
2170
           Must have more than 6 lines of text OR 5 or more consecutive 
2171
           letters that are the same for there to be ascii art 
2172
        */
2173
0
        if (newLines >= 6 || matchingCount >= 5)
2174
0
        {
2175
0
            IsAscii = yes;
2176
0
        }
2177
2178
        /* Checks for skip over link if ASCII art is present */
2179
0
        if (IsAscii == yes)
2180
0
        {
2181
0
            if (node->prev != NULL && node->prev->prev != NULL)
2182
0
            {
2183
0
                temp1 = node->prev->prev;
2184
2185
                /* Checks for 'HREF' attribute */
2186
0
                for (av = temp1->attributes; av != NULL; av = av->next)
2187
0
                {
2188
0
                    if ( attrIsHREF(av) && hasValue(av) )
2189
0
                    {
2190
0
                        skipOver = av->value;
2191
0
                        HasSkipOverLink++;
2192
0
                    }
2193
0
                }
2194
0
            }
2195
0
        }
2196
0
    }
2197
2198
0
    if (Level2_Enabled( doc ))
2199
0
    {
2200
        /* 
2201
           Checks for A element following PRE to ensure proper skipover link
2202
           only if there is an A element preceding PRE.
2203
        */
2204
0
        if (HasSkipOverLink == 1)
2205
0
        {
2206
0
            if ( nodeIsA(node->next) )
2207
0
            {
2208
0
                temp2 = node->next;
2209
                
2210
                /* Checks for 'NAME' attribute */
2211
0
                for (av = temp2->attributes; av != NULL; av = av->next)
2212
0
                {
2213
0
                    if ( attrIsNAME(av) && hasValue(av) )
2214
0
                    {
2215
                        /* 
2216
                           Value within the 'HREF' attribute must be the same
2217
                           as the value within the 'NAME' attribute for valid
2218
                           skipover.
2219
                        */
2220
0
                        if ( strstr(skipOver, av->value) != NULL )
2221
0
                        {
2222
0
                            HasSkipOverLink++;
2223
0
                        }
2224
0
                    }
2225
0
                }
2226
0
            }
2227
0
        }
2228
2229
0
        if (IsAscii == yes)
2230
0
        {
2231
0
            TY_(ReportAccessError)( doc, node, ASCII_REQUIRES_DESCRIPTION);
2232
0
            if (Level3_Enabled( doc ) && (HasSkipOverLink < 2))
2233
0
                TY_(ReportAccessError)( doc, node, SKIPOVER_ASCII_ART);
2234
0
        }
2235
2236
0
    }
2237
0
}
2238
2239
2240
/***********************************************************
2241
* CheckFormControls
2242
*
2243
* <form> must have valid 'FOR' attribute, and <label> must
2244
* have valid 'ID' attribute for valid form control.
2245
***********************************************************/
2246
2247
static void CheckFormControls( TidyDocImpl* doc, Node* node )
2248
0
{
2249
0
    if ( !doc->access.HasValidFor &&
2250
0
         doc->access.HasValidId )
2251
0
    {
2252
0
        TY_(ReportAccessError)( doc, node, ASSOCIATE_LABELS_EXPLICITLY_FOR);
2253
0
    }    
2254
2255
0
    if ( !doc->access.HasValidId &&
2256
0
         doc->access.HasValidFor )
2257
0
    {
2258
0
        TY_(ReportAccessError)( doc, node, ASSOCIATE_LABELS_EXPLICITLY_ID);
2259
0
    }
2260
2261
0
    if ( !doc->access.HasValidId &&
2262
0
         !doc->access.HasValidFor )
2263
0
    {
2264
0
        TY_(ReportAccessError)( doc, node, ASSOCIATE_LABELS_EXPLICITLY);
2265
0
    }
2266
0
}
2267
2268
2269
/************************************************************
2270
* CheckLabel
2271
*
2272
* Check for valid 'FOR' attribute within the LABEL element
2273
************************************************************/
2274
2275
static void CheckLabel( TidyDocImpl* doc, Node* node )
2276
0
{
2277
0
    if (Level2_Enabled( doc ))
2278
0
    {    
2279
        /* Checks for valid 'FOR' attribute */
2280
0
        AttVal* av = attrGetFOR( node );
2281
0
        if ( hasValue(av) )
2282
0
            doc->access.HasValidFor = yes;
2283
2284
0
        if ( ++doc->access.ForID == 2 )
2285
0
        {
2286
0
            doc->access.ForID = 0;
2287
0
            CheckFormControls( doc, node );
2288
0
        }
2289
0
    }
2290
0
}
2291
2292
2293
/************************************************************
2294
* CheckInputLabel
2295
* 
2296
* Checks for valid 'ID' attribute within the INPUT element.
2297
* Checks to see if there is a LABEL directly before
2298
* or after the INPUT element determined by the 'TYPE'.  
2299
* Each INPUT element must have a LABEL describing the form.
2300
************************************************************/
2301
2302
static void CheckInputLabel( TidyDocImpl* doc, Node* node )
2303
0
{
2304
0
    if (Level2_Enabled( doc ))
2305
0
    {
2306
0
        AttVal* av;
2307
2308
        /* Checks attributes within the INPUT element */
2309
0
        for (av = node->attributes; av != NULL; av = av->next)
2310
0
        {
2311
            /* Must have valid 'ID' value */
2312
0
            if ( attrIsID(av) && hasValue(av) )
2313
0
                doc->access.HasValidId = yes;
2314
0
        }
2315
2316
0
        if ( ++doc->access.ForID == 2 )
2317
0
        {
2318
0
            doc->access.ForID = 0;
2319
0
            CheckFormControls( doc, node );
2320
0
        }
2321
0
    }
2322
0
}
2323
2324
2325
/***************************************************************
2326
* CheckInputAttributes 
2327
*
2328
* INPUT element must have a valid 'ALT' attribute if the
2329
* 'VALUE' attribute is present.
2330
***************************************************************/
2331
2332
static void CheckInputAttributes( TidyDocImpl* doc, Node* node )
2333
0
{
2334
0
    Bool HasAlt = no;
2335
0
    Bool MustHaveAlt = no;
2336
0
    AttVal* av;
2337
2338
    /* Checks attributes within the INPUT element */
2339
0
    for (av = node->attributes; av != NULL; av = av->next)
2340
0
    {
2341
        /* 'VALUE' must be found if the 'TYPE' is 'text' or 'checkbox' */
2342
0
        if ( attrIsTYPE(av) && hasValue(av) )
2343
0
        {
2344
0
            if (Level1_Enabled( doc ))
2345
0
            {
2346
0
                if (AttrValueIs(av, "image"))
2347
0
                {
2348
0
                    MustHaveAlt = yes;
2349
0
                }
2350
0
            }
2351
2352
0
        }
2353
2354
0
        if ( attrIsALT(av) && hasValue(av) )
2355
0
        {
2356
0
            HasAlt = yes;
2357
0
        }
2358
0
    }
2359
2360
0
    if ( MustHaveAlt && !HasAlt )
2361
0
    {
2362
0
        TY_(ReportAccessError)( doc, node, IMG_BUTTON_MISSING_ALT );
2363
0
    }
2364
2365
0
}
2366
2367
2368
/***************************************************************
2369
* CheckFrameSet
2370
*
2371
* Frameset must have valid NOFRAME section.  Must contain some 
2372
* text but must not contain information telling user to update 
2373
* browsers, 
2374
***************************************************************/
2375
2376
static void CheckFrameSet( TidyDocImpl* doc, Node* node )
2377
0
{
2378
0
    Node* temp;
2379
0
    Bool HasNoFrames = no;
2380
2381
0
    if (Level1_Enabled( doc ))
2382
0
    {
2383
0
        if ( doc->badAccess & BA_INVALID_LINK_NOFRAMES )
2384
0
        {
2385
0
           TY_(ReportAccessError)( doc, node, NOFRAMES_INVALID_LINK);
2386
0
           doc->badAccess &= ~BA_INVALID_LINK_NOFRAMES; /* emit only once */
2387
0
        }
2388
0
        for ( temp = node->content; temp != NULL ; temp = temp->next )
2389
0
        {
2390
0
            if ( nodeIsNOFRAMES(temp) )
2391
0
            {
2392
0
                HasNoFrames = yes;
2393
2394
0
                if ( temp->content && nodeIsP(temp->content->content) )
2395
0
                {
2396
0
                    Node* para = temp->content->content;
2397
0
                    if ( TY_(nodeIsText)(para->content) )
2398
0
                    {
2399
0
                        ctmbstr word = textFromOneNode( doc, para->content );
2400
0
                        if ( word && strstr(word, "browser") != NULL )
2401
0
                            TY_(ReportAccessError)( doc, para, NOFRAMES_INVALID_CONTENT );
2402
0
                    }
2403
0
                }
2404
0
                else if (temp->content == NULL)
2405
0
                    TY_(ReportAccessError)( doc, temp, NOFRAMES_INVALID_NO_VALUE);
2406
0
                else if ( temp->content &&
2407
0
                          IsWhitespace(textFromOneNode(doc, temp->content)) )
2408
0
                    TY_(ReportAccessError)( doc, temp, NOFRAMES_INVALID_NO_VALUE);
2409
0
            }
2410
0
        }
2411
2412
0
        if (HasNoFrames == no)
2413
0
            TY_(ReportAccessError)( doc, node, FRAME_MISSING_NOFRAMES);
2414
0
    }
2415
0
}
2416
2417
2418
/***********************************************************
2419
* CheckHeaderNesting
2420
*
2421
* Checks for heading increases and decreases.  Headings must
2422
* not increase by more than one header level, but may
2423
* decrease at from any level to any level.  Text within 
2424
* headers must not be more than 20 words in length.  
2425
***********************************************************/
2426
2427
static void CheckHeaderNesting( TidyDocImpl* doc, Node* node )
2428
0
{
2429
0
    Node* temp;
2430
0
    uint i;
2431
0
    int numWords = 1;
2432
2433
0
    Bool IsValidIncrease = no;
2434
0
    Bool NeedsDescription = no;
2435
2436
0
    if (Level2_Enabled( doc ))
2437
0
    {
2438
        /* 
2439
           Text within header element cannot contain more than 20 words without
2440
           a separate description
2441
        */
2442
0
        if (node->content != NULL && node->content->tag == NULL)
2443
0
        {
2444
0
            ctmbstr word = textFromOneNode( doc, node->content);
2445
2446
0
            for (i = 0; i < TY_(tmbstrlen)(word); i++)
2447
0
            {
2448
0
                if (word[i] == ' ')
2449
0
                {
2450
0
                    numWords++;
2451
0
                }
2452
0
            }
2453
2454
0
            if (numWords > 20)
2455
0
            {
2456
0
                NeedsDescription = yes;
2457
0
            }
2458
0
        }
2459
2460
        /* Header following must be same level or same plus 1 for
2461
        ** valid heading increase size.  E.g. H1 -> H1, H2.  H3 -> H3, H4
2462
        */
2463
0
        if ( TY_(nodeIsHeader)(node) )
2464
0
        {
2465
0
            uint level = TY_(nodeHeaderLevel)( node );
2466
0
            IsValidIncrease = yes;
2467
2468
0
            for ( temp = node->next; temp != NULL; temp = temp->next )
2469
0
            {
2470
0
                uint nested = TY_(nodeHeaderLevel)( temp );
2471
0
                if ( nested >= level )
2472
0
                {
2473
0
                    IsValidIncrease = ( nested <= level + 1 );
2474
0
                    break;
2475
0
                }
2476
0
            }
2477
0
        }
2478
2479
0
        if ( !IsValidIncrease )
2480
0
            TY_(ReportAccessError)( doc, node, HEADERS_IMPROPERLY_NESTED );
2481
    
2482
0
        if ( NeedsDescription )
2483
0
            TY_(ReportAccessError)( doc, node, HEADER_USED_FORMAT_TEXT );    
2484
0
    }
2485
0
}
2486
2487
2488
/*************************************************************
2489
* CheckParagraphHeader
2490
*
2491
* Checks to ensure that P elements are not headings.  Must be
2492
* greater than 10 words in length, and they must not be in bold,
2493
* or italics, or underlined, etc.
2494
*************************************************************/
2495
2496
static void CheckParagraphHeader( TidyDocImpl* doc, Node* node )
2497
0
{
2498
0
    Bool IsNotHeader = no;
2499
0
    Node* temp;
2500
2501
0
    if (Level2_Enabled( doc ))
2502
0
    {
2503
        /* Cannot contain text formatting elements */
2504
0
        if (node->content != NULL)   
2505
0
        {                     
2506
0
            if (node->content->tag != NULL)
2507
0
            {
2508
0
                temp = node->content;
2509
2510
0
                while (temp != NULL)
2511
0
                {
2512
0
                    if (temp->tag == NULL)
2513
0
                    {
2514
0
                        IsNotHeader = yes;
2515
0
                        break;
2516
0
                    }
2517
                        
2518
0
                    temp = temp->next;
2519
0
                }
2520
0
            }
2521
2522
0
            if ( !IsNotHeader )
2523
0
            {
2524
0
                if ( nodeIsSTRONG(node->content) )
2525
0
                {
2526
0
                    TY_(ReportAccessError)( doc, node, POTENTIAL_HEADER_BOLD);
2527
0
                }
2528
2529
0
                if ( nodeIsU(node->content) )
2530
0
                {
2531
0
                    TY_(ReportAccessError)( doc, node, POTENTIAL_HEADER_UNDERLINE);
2532
0
                }
2533
2534
0
                if ( nodeIsEM(node->content) )
2535
0
                {
2536
0
                    TY_(ReportAccessError)( doc, node, POTENTIAL_HEADER_ITALICS);
2537
0
                }
2538
0
            }
2539
0
        }
2540
0
    }
2541
0
}
2542
2543
2544
/****************************************************************
2545
* CheckEmbed
2546
*
2547
* Checks to see if 'SRC' is a multimedia type.  Must have 
2548
* synchronized captions if used.
2549
****************************************************************/
2550
2551
static void CheckEmbed( TidyDocImpl* doc, Node* node )
2552
0
{
2553
0
    if (Level1_Enabled( doc ))
2554
0
    {
2555
0
        AttVal* av = attrGetSRC( node );
2556
0
        if ( hasValue(av) && IsValidMediaExtension(av->value) )
2557
0
        {
2558
0
             TY_(ReportAccessError)( doc, node, MULTIMEDIA_REQUIRES_TEXT );
2559
0
        }
2560
0
    }
2561
0
}
2562
2563
2564
/*********************************************************************
2565
* CheckHTMLAccess
2566
*
2567
* Checks HTML element for valid 'LANG' attribute.  Must be a valid
2568
* language.  ie. 'fr' or 'en'
2569
********************************************************************/
2570
2571
static void CheckHTMLAccess( TidyDocImpl* doc, Node* node )
2572
0
{
2573
0
    Bool ValidLang = no;
2574
2575
0
    if (Level3_Enabled( doc ))
2576
0
    {
2577
0
        AttVal* av = attrGetLANG( node );
2578
0
        if ( av )
2579
0
        {
2580
0
            ValidLang = yes;
2581
0
            if ( !hasValue(av) )
2582
0
                TY_(ReportAccessError)( doc, node, LANGUAGE_INVALID );
2583
0
        }
2584
0
        if ( !ValidLang )
2585
0
            TY_(ReportAccessError)( doc, node, LANGUAGE_NOT_IDENTIFIED );
2586
0
    }
2587
0
}
2588
2589
2590
/********************************************************
2591
* CheckBlink
2592
*
2593
* Document must not contain the BLINK element.  
2594
* It is invalid HTML/XHTML.
2595
*********************************************************/
2596
2597
static void CheckBlink( TidyDocImpl* doc, Node* node )
2598
0
{
2599
    
2600
0
    if (Level2_Enabled( doc ))
2601
0
    {
2602
        /* Checks to see if text is found within the BLINK element. */
2603
0
        if ( TY_(nodeIsText)(node->content) )
2604
0
        {
2605
0
            ctmbstr word = textFromOneNode( doc, node->content );
2606
0
            if ( !IsWhitespace(word) )
2607
0
            {
2608
0
                TY_(ReportAccessError)( doc, node, REMOVE_BLINK_MARQUEE );
2609
0
            }
2610
0
        }
2611
0
    }
2612
0
}
2613
2614
2615
/********************************************************
2616
* CheckMarquee
2617
*
2618
* Document must not contain the MARQUEE element.
2619
* It is invalid HTML/XHTML.
2620
********************************************************/
2621
2622
2623
static void CheckMarquee( TidyDocImpl* doc, Node* node )
2624
0
{
2625
0
    if (Level2_Enabled( doc ))
2626
0
    {
2627
        /* Checks to see if there is text in between the MARQUEE element */
2628
0
        if ( TY_(nodeIsText)(node) )
2629
0
        {
2630
0
            ctmbstr word = textFromOneNode( doc, node->content);
2631
0
            if ( !IsWhitespace(word) )
2632
0
            {
2633
0
                TY_(ReportAccessError)( doc, node, REMOVE_BLINK_MARQUEE );
2634
0
            }
2635
0
        }
2636
0
    }
2637
0
}
2638
2639
2640
/**********************************************************
2641
* CheckLink
2642
*
2643
* 'REL' attribute within the LINK element must not contain
2644
* 'stylesheet'.  HTML/XHTML document is unreadable when
2645
* style sheets are applied.  -- CPR huh?
2646
**********************************************************/
2647
2648
static void CheckLink( TidyDocImpl* doc, Node* node )
2649
0
{
2650
0
    Bool HasRel = no;
2651
0
    Bool HasType = no;
2652
2653
0
    if (Level1_Enabled( doc ))
2654
0
    {
2655
0
        AttVal* av;
2656
        /* Check for valid 'REL' and 'TYPE' attribute */
2657
0
        for (av = node->attributes; av != NULL; av = av->next)
2658
0
        {
2659
0
            if ( attrIsREL(av) && hasValue(av) )
2660
0
            {
2661
0
                if (AttrContains(av, "stylesheet"))
2662
0
                    HasRel = yes;
2663
0
            }
2664
2665
0
            if ( attrIsTYPE(av) && hasValue(av) )
2666
0
            {
2667
0
                HasType = yes;
2668
0
            }
2669
0
        }
2670
2671
0
        if (HasRel && HasType)
2672
0
            TY_(ReportAccessError)( doc, node, STYLESHEETS_REQUIRE_TESTING_LINK );
2673
0
    }
2674
0
}
2675
2676
2677
/*******************************************************
2678
* CheckStyle
2679
*
2680
* Document must not contain STYLE element.  HTML/XHTML 
2681
* document is unreadable when style sheets are applied.
2682
*******************************************************/
2683
2684
static void CheckStyle( TidyDocImpl* doc, Node* node )
2685
0
{
2686
0
    if (Level1_Enabled( doc ))
2687
0
    {
2688
0
        TY_(ReportAccessError)( doc, node, STYLESHEETS_REQUIRE_TESTING_STYLE_ELEMENT );
2689
0
    }
2690
0
}
2691
2692
2693
/*************************************************************
2694
* DynamicContent
2695
*
2696
* Verify that equivalents of dynamic content are updated and 
2697
* available as often as the dynamic content.
2698
*************************************************************/
2699
2700
2701
static void DynamicContent( TidyDocImpl* doc, Node* node )
2702
0
{
2703
0
    if (Level1_Enabled( doc ))
2704
0
    {
2705
0
        uint msgcode = 0;
2706
0
        if ( nodeIsAPPLET(node) )
2707
0
            msgcode = TEXT_EQUIVALENTS_REQUIRE_UPDATING_APPLET;
2708
0
        else if ( nodeIsSCRIPT(node) )
2709
0
            msgcode = TEXT_EQUIVALENTS_REQUIRE_UPDATING_SCRIPT;
2710
0
        else if ( nodeIsOBJECT(node) )
2711
0
            msgcode = TEXT_EQUIVALENTS_REQUIRE_UPDATING_OBJECT;
2712
2713
0
        if ( msgcode )
2714
0
            TY_(ReportAccessError)( doc, node, msgcode );
2715
0
    }
2716
0
}
2717
2718
2719
/*************************************************************
2720
* ProgrammaticObjects
2721
*
2722
* Verify that the page is usable when programmatic objects 
2723
* are disabled.
2724
*************************************************************/
2725
2726
static void ProgrammaticObjects( TidyDocImpl* doc, Node* node )
2727
0
{
2728
0
    if (Level1_Enabled( doc ))
2729
0
    {
2730
0
        int msgcode = 0;
2731
0
        if ( nodeIsSCRIPT(node) )
2732
0
            msgcode = PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_SCRIPT;
2733
0
        else if ( nodeIsOBJECT(node) )
2734
0
            msgcode = PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_OBJECT;
2735
0
        else if ( nodeIsEMBED(node) )
2736
0
            msgcode = PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_EMBED;
2737
0
        else if ( nodeIsAPPLET(node) )
2738
0
            msgcode = PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_APPLET;
2739
2740
0
        if ( msgcode )
2741
0
            TY_(ReportAccessError)( doc, node, msgcode );
2742
0
    }
2743
0
}
2744
2745
2746
/*************************************************************
2747
* AccessibleCompatible
2748
*
2749
* Verify that programmatic objects are directly accessible.
2750
*************************************************************/
2751
2752
static void AccessibleCompatible( TidyDocImpl* doc, Node* node )
2753
0
{
2754
0
    if (Level1_Enabled( doc ))
2755
0
    {
2756
0
        int msgcode = 0;
2757
0
        if ( nodeIsSCRIPT(node) )
2758
0
            msgcode = ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_SCRIPT;
2759
0
        else if ( nodeIsOBJECT(node) )
2760
0
            msgcode = ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_OBJECT;
2761
0
        else if ( nodeIsEMBED(node) )
2762
0
            msgcode = ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_EMBED;
2763
0
        else if ( nodeIsAPPLET(node) )
2764
0
            msgcode = ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_APPLET;
2765
2766
0
        if ( msgcode )
2767
0
            TY_(ReportAccessError)( doc, node, msgcode );
2768
0
    }
2769
0
}
2770
2771
2772
/**************************************************
2773
* CheckFlicker
2774
*
2775
* Verify that the page does not cause flicker.
2776
**************************************************/
2777
2778
static void CheckFlicker( TidyDocImpl* doc, Node* node )
2779
0
{
2780
0
    if (Level1_Enabled( doc ))
2781
0
    {
2782
0
        int msgcode = 0;
2783
0
        if ( nodeIsSCRIPT(node) )
2784
0
            msgcode = REMOVE_FLICKER_SCRIPT;
2785
0
        else if ( nodeIsOBJECT(node) )
2786
0
            msgcode = REMOVE_FLICKER_OBJECT;
2787
0
        else if ( nodeIsEMBED(node) )
2788
0
            msgcode = REMOVE_FLICKER_EMBED;
2789
0
        else if ( nodeIsAPPLET(node) )
2790
0
            msgcode = REMOVE_FLICKER_APPLET;
2791
2792
        /* Checks for animated gif within the <img> tag. */
2793
0
        else if ( nodeIsIMG(node) )
2794
0
        {
2795
0
            AttVal* av = attrGetSRC( node );
2796
0
            if ( hasValue(av) )
2797
0
            {
2798
0
                tmbchar ext[20];
2799
0
                GetFileExtension( av->value, ext, sizeof(ext) );
2800
0
                if ( TY_(tmbstrcasecmp)(ext, ".gif") == 0 )
2801
0
                    msgcode = REMOVE_FLICKER_ANIMATED_GIF;
2802
0
            }
2803
0
        }            
2804
2805
0
        if ( msgcode )
2806
0
            TY_(ReportAccessError)( doc, node, msgcode );
2807
0
    }
2808
0
}
2809
2810
2811
/**********************************************************
2812
* CheckDeprecated
2813
*
2814
* APPLET, BASEFONT, CENTER, FONT, ISINDEX, 
2815
* S, STRIKE, and U should not be used.  Becomes deprecated
2816
* HTML if any of the above are used.
2817
**********************************************************/
2818
2819
static void CheckDeprecated( TidyDocImpl* doc, Node* node )
2820
0
{
2821
0
    if (Level2_Enabled( doc ))
2822
0
    {
2823
0
        int msgcode = 0;
2824
0
        if ( nodeIsAPPLET(node) )
2825
0
            msgcode = REPLACE_DEPRECATED_HTML_APPLET;
2826
0
        else if ( nodeIsBASEFONT(node) )
2827
0
            msgcode = REPLACE_DEPRECATED_HTML_BASEFONT;
2828
0
        else if ( nodeIsCENTER(node) )
2829
0
            msgcode = REPLACE_DEPRECATED_HTML_CENTER;
2830
0
        else if ( nodeIsDIR(node) )
2831
0
            msgcode = REPLACE_DEPRECATED_HTML_DIR;
2832
0
        else if ( nodeIsFONT(node) )
2833
0
            msgcode = REPLACE_DEPRECATED_HTML_FONT;
2834
0
        else if ( nodeIsISINDEX(node) )
2835
0
            msgcode = REPLACE_DEPRECATED_HTML_ISINDEX;
2836
0
        else if ( nodeIsMENU(node) )
2837
0
            msgcode = REPLACE_DEPRECATED_HTML_MENU;
2838
0
        else if ( nodeIsS(node) )
2839
0
            msgcode = REPLACE_DEPRECATED_HTML_S;
2840
0
        else if ( nodeIsSTRIKE(node) )
2841
0
            msgcode = REPLACE_DEPRECATED_HTML_STRIKE;
2842
0
        else if ( nodeIsU(node) )
2843
0
            msgcode = REPLACE_DEPRECATED_HTML_U;
2844
2845
0
        if ( msgcode )
2846
0
            TY_(ReportAccessError)( doc, node, msgcode );
2847
0
    }
2848
0
}
2849
2850
2851
/************************************************************
2852
* CheckScriptKeyboardAccessible
2853
*
2854
* Elements must have a device independent event handler if 
2855
* they have any of the following device dependent event 
2856
* handlers. 
2857
************************************************************/
2858
2859
static void CheckScriptKeyboardAccessible( TidyDocImpl* doc, Node* node )
2860
0
{
2861
0
    Node* content;
2862
0
    int HasOnMouseDown = 0;
2863
0
    int HasOnMouseUp = 0;
2864
0
    int HasOnClick = 0;
2865
0
    int HasOnMouseOut = 0;
2866
0
    int HasOnMouseOver = 0;
2867
0
    int HasOnMouseMove = 0;
2868
2869
0
    if (Level2_Enabled( doc ))
2870
0
    {
2871
0
        AttVal* av;
2872
        /* Checks all elements for their attributes */
2873
0
        for (av = node->attributes; av != NULL; av = av->next)
2874
0
        {
2875
            /* Must also have 'ONKEYDOWN' attribute with 'ONMOUSEDOWN' */
2876
0
            if ( attrIsOnMOUSEDOWN(av) )
2877
0
                HasOnMouseDown++;
2878
2879
            /* Must also have 'ONKEYUP' attribute with 'ONMOUSEUP' */
2880
0
            if ( attrIsOnMOUSEUP(av) )
2881
0
                HasOnMouseUp++;
2882
2883
            /* Must also have 'ONKEYPRESS' attribute with 'ONCLICK' */
2884
0
            if ( attrIsOnCLICK(av) )
2885
0
                HasOnClick++;
2886
2887
            /* Must also have 'ONBLUR' attribute with 'ONMOUSEOUT' */
2888
0
            if ( attrIsOnMOUSEOUT(av) )
2889
0
                HasOnMouseOut++;
2890
2891
0
            if ( attrIsOnMOUSEOVER(av) )
2892
0
                HasOnMouseOver++;
2893
2894
0
            if ( attrIsOnMOUSEMOVE(av) )
2895
0
                HasOnMouseMove++;
2896
2897
0
            if ( attrIsOnKEYDOWN(av) )
2898
0
                HasOnMouseDown++;
2899
2900
0
            if ( attrIsOnKEYUP(av) )
2901
0
                HasOnMouseUp++;
2902
2903
0
            if ( attrIsOnKEYPRESS(av) )
2904
0
                HasOnClick++;
2905
2906
0
            if ( attrIsOnBLUR(av) )
2907
0
                HasOnMouseOut++;
2908
0
        }
2909
2910
0
        if ( HasOnMouseDown == 1 )
2911
0
            TY_(ReportAccessError)( doc, node, SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_DOWN);
2912
2913
0
        if ( HasOnMouseUp == 1 )
2914
0
            TY_(ReportAccessError)( doc, node, SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_UP);
2915
2916
0
        if ( HasOnClick == 1 )
2917
0
            TY_(ReportAccessError)( doc, node, SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_CLICK);
2918
0
        if ( HasOnMouseOut == 1 )
2919
0
            TY_(ReportAccessError)( doc, node, SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_OUT);
2920
2921
0
        if ( HasOnMouseOver == 1 )
2922
0
            TY_(ReportAccessError)( doc, node, SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_OVER);
2923
2924
0
        if ( HasOnMouseMove == 1 )
2925
0
            TY_(ReportAccessError)( doc, node, SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_MOVE);
2926
2927
        /* Recursively check all child nodes.
2928
         */
2929
0
        for ( content = node->content; content != NULL; content = content->next )
2930
0
            CheckScriptKeyboardAccessible( doc, content );
2931
0
    }
2932
0
}
2933
2934
2935
/**********************************************************
2936
* CheckMetaData
2937
*
2938
* Must have at least one of these elements in the document.
2939
* META, LINK, TITLE or ADDRESS.  <meta> must contain 
2940
* a "content" attribute that doesn't contain a URL, and
2941
* an "http-Equiv" attribute that doesn't contain 'refresh'.
2942
**********************************************************/
2943
2944
2945
static Bool CheckMetaData( TidyDocImpl* doc, Node* node, Bool HasMetaData )
2946
0
{
2947
0
    Bool HasHttpEquiv = no;
2948
0
    Bool HasContent = no;
2949
0
    Bool ContainsAttr = no;
2950
2951
0
    if (Level2_Enabled( doc ))
2952
0
    {
2953
0
        if ( nodeIsMETA(node) )
2954
0
        {
2955
0
            AttVal* av;
2956
0
            for (av = node->attributes; av != NULL; av = av->next)
2957
0
            {
2958
0
                if ( attrIsHTTP_EQUIV(av) && hasValue(av) )
2959
0
                {
2960
0
                    ContainsAttr = yes;
2961
2962
                    /* Must not have an auto-refresh */
2963
0
                    if (AttrValueIs(av, "refresh"))
2964
0
                    {
2965
0
                        HasHttpEquiv = yes;
2966
0
                        TY_(ReportAccessError)( doc, node, REMOVE_AUTO_REFRESH );
2967
0
                    }
2968
0
                }
2969
2970
0
                if ( attrIsCONTENT(av) && hasValue(av) )
2971
0
                {
2972
0
                    ContainsAttr = yes;
2973
2974
                    /* If the value is not an integer, then it must not be a URL */
2975
0
                    if ( TY_(tmbstrncmp)(av->value, "http:", 5) == 0)
2976
0
                    {
2977
0
                        HasContent = yes;
2978
0
                        TY_(ReportAccessError)( doc, node, REMOVE_AUTO_REDIRECT);
2979
0
                    }
2980
0
                }
2981
0
                if (TY_(IsHTML5Mode)(doc) && attrIsCHARSET(av) && hasValue(av))
2982
0
                {
2983
0
                    ContainsAttr = yes;
2984
0
                }
2985
0
            }
2986
        
2987
0
            if ( HasContent || HasHttpEquiv )
2988
0
            {
2989
0
                HasMetaData = yes;
2990
0
                TY_(ReportAccessError)( doc, node, METADATA_MISSING_REDIRECT_AUTOREFRESH);
2991
0
            }
2992
0
            else
2993
0
            {
2994
0
                if ( ContainsAttr && !HasContent && !HasHttpEquiv )
2995
0
                    HasMetaData = yes;                    
2996
0
            }
2997
0
        }
2998
2999
0
        if ( !HasMetaData && 
3000
0
             nodeIsADDRESS(node) &&
3001
0
             nodeIsA(node->content) )
3002
0
        {
3003
0
            HasMetaData = yes;
3004
0
        }
3005
            
3006
0
        if ( !HasMetaData &&
3007
0
             !nodeIsTITLE(node) &&
3008
0
             TY_(nodeIsText)(node->content) )
3009
0
        {
3010
0
            ctmbstr word = textFromOneNode( doc, node->content );
3011
0
            if ( !IsWhitespace(word) )
3012
0
                HasMetaData = yes;
3013
0
        }
3014
3015
0
        if( !HasMetaData && nodeIsLINK(node) )
3016
0
        {
3017
0
            AttVal* av = attrGetREL(node);
3018
0
            if( !AttrContains(av, "stylesheet") )
3019
0
                HasMetaData = yes;
3020
0
        }
3021
            
3022
        /* Check for MetaData */
3023
0
        for ( node = node->content; node; node = node->next )
3024
0
        {
3025
0
            HasMetaData = CheckMetaData( doc, node, HasMetaData );
3026
0
        }
3027
0
    }
3028
0
    return HasMetaData;
3029
0
}
3030
3031
3032
/*******************************************************
3033
* MetaDataPresent
3034
*
3035
* Determines if MetaData is present in document
3036
*******************************************************/
3037
3038
static void MetaDataPresent( TidyDocImpl* doc, Node* node )
3039
0
{
3040
0
    if (Level2_Enabled( doc ))
3041
0
    {
3042
0
        TY_(ReportAccessError)( doc, node, METADATA_MISSING );
3043
0
    }
3044
0
}
3045
3046
3047
/*****************************************************
3048
* CheckDocType
3049
*
3050
* Checks that every HTML/XHTML document contains a 
3051
* '!DOCTYPE' before the root node. ie.  <HTML>
3052
*****************************************************/
3053
3054
static void CheckDocType( TidyDocImpl* doc )
3055
0
{
3056
0
    if (Level2_Enabled( doc ))
3057
0
    {
3058
0
        Node* DTnode = TY_(FindDocType)(doc);
3059
3060
        /* If the doctype has been added by tidy, DTnode->end will be 0. */
3061
0
        if (DTnode && DTnode->end != 0)
3062
0
        {
3063
0
            ctmbstr word = textFromOneNode( doc, DTnode);
3064
0
            if (TY_(IsHTML5Mode)(doc))
3065
0
            {
3066
0
                if ((strstr(word, "HTML") == NULL) &&
3067
0
                    (strstr(word, "html") == NULL))
3068
0
                    DTnode = NULL;
3069
0
            }
3070
0
            else {
3071
0
                if ((strstr(word, "HTML PUBLIC") == NULL) &&
3072
0
                    (strstr(word, "html PUBLIC") == NULL))
3073
0
                    DTnode = NULL;
3074
0
            }
3075
0
        }
3076
0
        if (!DTnode)
3077
0
           TY_(ReportAccessError)( doc, &doc->root, DOCTYPE_MISSING);
3078
0
    }
3079
0
}
3080
3081
3082
3083
/********************************************************
3084
* CheckMapLinks
3085
*
3086
* Checks to see if an HREF for A element matches HREF
3087
* for AREA element.  There must be an HREF attribute 
3088
* of an A element for every HREF of an AREA element. 
3089
********************************************************/
3090
3091
static Bool urlMatch( ctmbstr url1, ctmbstr url2 )
3092
0
{
3093
  /* TODO: Make host part case-insensitive and
3094
  ** remainder case-sensitive.
3095
  */
3096
0
  return ( TY_(tmbstrcmp)( url1, url2 ) == 0 );
3097
0
}
3098
3099
static Bool FindLinkA( TidyDocImpl* doc, Node* node, ctmbstr url )
3100
0
{
3101
0
  Bool found = no;
3102
0
  for ( node = node->content; !found && node; node = node->next )
3103
0
  {
3104
0
    if ( nodeIsA(node) )
3105
0
    {
3106
0
      AttVal* href = attrGetHREF( node );
3107
0
      found = ( hasValue(href) && urlMatch(url, href->value) );
3108
0
    }
3109
0
    else
3110
0
        found = FindLinkA( doc, node, url );
3111
0
  }
3112
0
  return found;
3113
0
}
3114
3115
static void CheckMapLinks( TidyDocImpl* doc, Node* node )
3116
0
{
3117
0
    Node* child;
3118
3119
0
    if (!Level3_Enabled( doc ))
3120
0
        return;
3121
3122
    /* Stores the 'HREF' link of an AREA element within a MAP element */
3123
0
    for ( child = node->content; child != NULL; child = child->next )
3124
0
    {
3125
0
        if ( nodeIsAREA(child) )
3126
0
        {
3127
            /* Checks for 'HREF' attribute */                
3128
0
            AttVal* href = attrGetHREF( child );
3129
0
            if ( hasValue(href) &&
3130
0
                 !FindLinkA( doc, &doc->root, href->value ) )
3131
0
            {
3132
0
                TY_(ReportAccessError)( doc, node, IMG_MAP_CLIENT_MISSING_TEXT_LINKS );
3133
0
            }
3134
0
        }
3135
0
    }
3136
0
}
3137
3138
3139
/****************************************************
3140
* CheckForStyleAttribute
3141
*
3142
* Checks all elements within the document to check 
3143
* for the use of 'STYLE' attribute.
3144
****************************************************/
3145
3146
static void CheckForStyleAttribute( TidyDocImpl* doc, Node* node )
3147
0
{
3148
0
    Node* content;
3149
0
    if (Level1_Enabled( doc ))
3150
0
    {
3151
        /* Must not contain 'STYLE' attribute */
3152
0
        AttVal* style = attrGetSTYLE( node );
3153
0
        if ( hasValue(style) )
3154
0
        {
3155
0
            TY_(ReportAccessError)( doc, node, STYLESHEETS_REQUIRE_TESTING_STYLE_ATTR );
3156
0
        }
3157
0
    }
3158
3159
    /* Recursively check all child nodes.
3160
    */
3161
0
    for ( content = node->content; content != NULL; content = content->next )
3162
0
        CheckForStyleAttribute( doc, content );
3163
0
}
3164
3165
3166
/*****************************************************
3167
* CheckForListElements
3168
*
3169
* Checks document for list elements (<ol>, <ul>, <li>)
3170
*****************************************************/
3171
3172
static void CheckForListElements( TidyDocImpl* doc, Node* node )
3173
0
{
3174
0
    if ( nodeIsLI(node) )
3175
0
    {
3176
0
        doc->access.ListElements++;
3177
0
    }
3178
0
    else if ( nodeIsOL(node) || nodeIsUL(node) )
3179
0
    {
3180
0
        doc->access.OtherListElements++;
3181
0
    }
3182
3183
0
    for ( node = node->content; node != NULL; node = node->next )
3184
0
    {
3185
0
        CheckForListElements( doc, node );
3186
0
    }
3187
0
}
3188
3189
3190
/******************************************************
3191
* CheckListUsage
3192
*
3193
* Ensures that lists are properly used.  <ol> and <ul>
3194
* must contain <li> within itself, and <li> must not be
3195
* by itself.
3196
******************************************************/
3197
3198
static void CheckListUsage( TidyDocImpl* doc, Node* node )
3199
0
{
3200
0
    int msgcode = 0;
3201
3202
0
    if (!Level2_Enabled( doc ))
3203
0
        return;
3204
3205
0
    if ( nodeIsOL(node) )
3206
0
        msgcode = LIST_USAGE_INVALID_OL;
3207
0
    else if ( nodeIsUL(node) )
3208
0
        msgcode = LIST_USAGE_INVALID_UL;
3209
3210
0
    if ( msgcode )
3211
0
    {
3212
       /*
3213
       ** Check that OL/UL
3214
       ** a) has LI child,
3215
       ** b) was not added by Tidy parser
3216
       ** IFF OL/UL node is implicit
3217
       */
3218
0
       if ( !nodeIsLI(node->content) ) {
3219
0
            TY_(ReportAccessError)( doc, node, msgcode );
3220
0
       } else if ( node->implicit ) {  /* if a tidy added node */
3221
0
            TY_(ReportAccessError)( doc, node, LIST_USAGE_INVALID_LI );
3222
0
       }
3223
0
    }
3224
0
    else if ( nodeIsLI(node) )
3225
0
    {
3226
        /* Check that LI parent 
3227
        ** a) exists,
3228
        ** b) is either OL or UL
3229
        ** IFF the LI parent was added by Tidy
3230
        ** ie, if it is marked 'implicit', then
3231
        ** emit warnings LIST_USAGE_INVALID_UL or 
3232
        ** warning LIST_USAGE_INVALID_OL tests 
3233
        */
3234
0
        if ( node->parent == NULL ||
3235
0
             ( !nodeIsOL(node->parent) && !nodeIsUL(node->parent) ) )
3236
0
        {
3237
0
            TY_(ReportAccessError)( doc, node, LIST_USAGE_INVALID_LI );
3238
0
        } else if ( node->implicit && node->parent &&
3239
0
                    ( nodeIsOL(node->parent) || nodeIsUL(node->parent) ) ) {
3240
            /* if tidy added LI node, then */
3241
0
            msgcode = nodeIsUL(node->parent) ?
3242
0
                LIST_USAGE_INVALID_UL : LIST_USAGE_INVALID_OL;
3243
0
            TY_(ReportAccessError)( doc, node, msgcode );
3244
0
        }
3245
0
    }
3246
0
}
3247
3248
/************************************************************
3249
* InitAccessibilityChecks
3250
*
3251
* Initializes the AccessibilityChecks variables as necessary
3252
************************************************************/
3253
3254
static void InitAccessibilityChecks( TidyDocImpl* doc, int level123 )
3255
0
{
3256
0
    TidyClearMemory( &doc->access, sizeof(doc->access) );
3257
0
    doc->access.PRIORITYCHK = level123;
3258
0
}
3259
3260
/************************************************************
3261
* CleanupAccessibilityChecks
3262
*
3263
* Cleans up the AccessibilityChecks variables as necessary
3264
************************************************************/
3265
3266
3267
static void FreeAccessibilityChecks( TidyDocImpl* ARG_UNUSED(doc) )
3268
0
{
3269
    /* free any memory allocated for the lists
3270
3271
    Linked List of Links not used.  Just search document as 
3272
    AREA tags are encountered.  Same algorithm, but no
3273
    data structures necessary.
3274
3275
    current = start;
3276
    while (current)
3277
    {
3278
        void    *templink = (void *)current;
3279
        
3280
        current = current->next;
3281
        TidyDocFree(doc, templink);
3282
    }
3283
    start = NULL;
3284
    */
3285
0
}
3286
3287
/************************************************************
3288
* AccessibilityChecks
3289
*
3290
* Traverses through the individual nodes of the tree
3291
* and checks attributes and elements for accessibility.
3292
* after the tree structure has been formed.
3293
************************************************************/
3294
3295
static void AccessibilityCheckNode( TidyDocImpl* doc, Node* node )
3296
0
{
3297
0
    Node* content;
3298
    
3299
    /* Check BODY for color contrast */
3300
0
    if ( nodeIsBODY(node) )
3301
0
    {
3302
0
        CheckColorContrast( doc, node );
3303
0
    }
3304
3305
    /* Checks document for MetaData */
3306
0
    else if ( nodeIsHEAD(node) )
3307
0
    {
3308
0
        if ( !CheckMetaData( doc, node, no ) )
3309
0
          MetaDataPresent( doc, node );
3310
0
    }
3311
    
3312
    /* Check the ANCHOR tag */
3313
0
    else if ( nodeIsA(node) )
3314
0
    {
3315
0
        CheckAnchorAccess( doc, node );
3316
0
    }
3317
3318
    /* Check the IMAGE tag */
3319
0
    else if ( nodeIsIMG(node) )
3320
0
    {
3321
0
        CheckFlicker( doc, node );
3322
0
        CheckColorAvailable( doc, node );
3323
0
        CheckImage( doc, node );
3324
0
    }
3325
3326
        /* Checks MAP for client-side text links */
3327
0
    else if ( nodeIsMAP(node) )
3328
0
    {
3329
0
        CheckMapLinks( doc, node );
3330
0
    }
3331
3332
    /* Check the AREA tag */
3333
0
    else if ( nodeIsAREA(node) )
3334
0
    {
3335
0
        CheckArea( doc, node );
3336
0
    }
3337
3338
    /* Check the APPLET tag */
3339
0
    else if ( nodeIsAPPLET(node) )
3340
0
    {
3341
0
        CheckDeprecated( doc, node );
3342
0
        ProgrammaticObjects( doc, node );
3343
0
        DynamicContent( doc, node );
3344
0
        AccessibleCompatible( doc, node );
3345
0
        CheckFlicker( doc, node );
3346
0
        CheckColorAvailable( doc, node );
3347
0
        CheckApplet(doc, node );
3348
0
    }
3349
    
3350
    /* Check the OBJECT tag */
3351
0
    else if ( nodeIsOBJECT(node) )
3352
0
    {
3353
0
        ProgrammaticObjects( doc, node );
3354
0
        DynamicContent( doc, node );
3355
0
        AccessibleCompatible( doc, node );
3356
0
        CheckFlicker( doc, node );
3357
0
        CheckColorAvailable( doc, node );
3358
0
        CheckObject( doc, node );
3359
0
    }
3360
    
3361
    /* Check the FRAME tag */
3362
0
    else if ( nodeIsFRAME(node) )
3363
0
    {
3364
0
        CheckFrame( doc, node );
3365
0
    }
3366
    
3367
    /* Check the IFRAME tag */
3368
0
    else if ( nodeIsIFRAME(node) )
3369
0
    {
3370
0
        CheckIFrame( doc, node );
3371
0
    }
3372
    
3373
    /* Check the SCRIPT tag */
3374
0
    else if ( nodeIsSCRIPT(node) )
3375
0
    {
3376
0
        DynamicContent( doc, node );
3377
0
        ProgrammaticObjects( doc, node );
3378
0
        AccessibleCompatible( doc, node );
3379
0
        CheckFlicker( doc, node );
3380
0
        CheckColorAvailable( doc, node );
3381
0
        CheckScriptAcc( doc, node );
3382
0
    }
3383
3384
    /* Check the TABLE tag */
3385
0
    else if ( nodeIsTABLE(node) )
3386
0
    {
3387
0
        CheckColorContrast( doc, node );
3388
0
        CheckTable( doc, node );
3389
0
    }
3390
3391
    /* Check the PRE for ASCII art */
3392
0
    else if ( nodeIsPRE(node) || nodeIsXMP(node) )
3393
0
    {
3394
0
        CheckASCII( doc, node );
3395
0
    }
3396
3397
    /* Check the LABEL tag */
3398
0
    else if ( nodeIsLABEL(node) )
3399
0
    {
3400
0
        CheckLabel( doc, node );
3401
0
    }
3402
3403
    /* Check INPUT tag for validity */
3404
0
    else if ( nodeIsINPUT(node) )
3405
0
    {
3406
0
        CheckColorAvailable( doc, node );
3407
0
        CheckInputLabel( doc, node );
3408
0
        CheckInputAttributes( doc, node );
3409
0
    }
3410
3411
    /* Checks FRAMESET element for NOFRAME section */
3412
0
    else if ( nodeIsFRAMESET(node) )
3413
0
    {
3414
0
        CheckFrameSet( doc, node );
3415
0
    }
3416
    
3417
    /* Checks for header elements for valid header increase */
3418
0
    else if ( TY_(nodeIsHeader)(node) )
3419
0
    {
3420
0
        CheckHeaderNesting( doc, node );
3421
0
    }
3422
3423
    /* Checks P element to ensure that it is not a header */
3424
0
    else if ( nodeIsP(node) )
3425
0
    {
3426
0
        CheckParagraphHeader( doc, node );
3427
0
    }
3428
3429
    /* Checks HTML element for valid 'LANG' */
3430
0
    else if ( nodeIsHTML(node) )
3431
0
    {
3432
0
        CheckHTMLAccess( doc, node );
3433
0
    }
3434
3435
    /* Checks BLINK for any blinking text */
3436
0
    else if ( nodeIsBLINK(node) )
3437
0
    {
3438
0
        CheckBlink( doc, node );
3439
0
    }
3440
3441
    /* Checks MARQUEE for any MARQUEE text */
3442
0
    else if ( nodeIsMARQUEE(node) )
3443
0
    {
3444
0
        CheckMarquee( doc, node );
3445
0
    }
3446
3447
    /* Checks LINK for 'REL' attribute */
3448
0
    else if ( nodeIsLINK(node) )
3449
0
    {
3450
0
        CheckLink( doc, node );
3451
0
    }
3452
3453
    /* Checks to see if STYLE is used */
3454
0
    else if ( nodeIsSTYLE(node) )
3455
0
    {
3456
0
        CheckColorContrast( doc, node );
3457
0
        CheckStyle( doc, node );
3458
0
    }
3459
3460
    /* Checks to see if EMBED is used */
3461
0
    else if ( nodeIsEMBED(node) )
3462
0
    {
3463
0
        CheckEmbed( doc, node );
3464
0
        ProgrammaticObjects( doc, node );
3465
0
        AccessibleCompatible( doc, node );
3466
0
        CheckFlicker( doc, node );
3467
0
    }
3468
3469
    /* Deprecated HTML if the following tags are found in the document */
3470
0
    else if ( nodeIsBASEFONT(node) ||
3471
0
              nodeIsCENTER(node)   ||
3472
0
              nodeIsISINDEX(node)  ||
3473
0
              nodeIsU(node)        ||
3474
0
              nodeIsFONT(node)     ||
3475
0
              nodeIsDIR(node)      ||
3476
0
              nodeIsS(node)        ||
3477
0
              nodeIsSTRIKE(node)   ||
3478
0
              nodeIsMENU(node) )
3479
0
    {
3480
0
        CheckDeprecated( doc, node );
3481
0
    }
3482
3483
    /* Checks for 'ABBR' attribute if needed */
3484
0
    else if ( nodeIsTH(node) )
3485
0
    {
3486
0
        CheckTH( doc, node );
3487
0
    }
3488
3489
    /* Ensures that lists are properly used */
3490
0
    else if ( nodeIsLI(node) || nodeIsOL(node) || nodeIsUL(node) )
3491
0
    {
3492
0
        CheckListUsage( doc, node );
3493
0
    }
3494
3495
    /* Recursively check all child nodes.
3496
    */
3497
0
    for ( content = node->content; content != NULL; content = content->next )
3498
0
    {
3499
0
        AccessibilityCheckNode( doc, content );
3500
0
    }
3501
0
}
3502
3503
3504
void TY_(AccessibilityChecks)( TidyDocImpl* doc )
3505
0
{
3506
    /* Initialize */
3507
0
    InitAccessibilityChecks( doc, cfg(doc, TidyAccessibilityCheckLevel) );
3508
3509
    /* Hello there, ladies and gentlemen... */
3510
0
    TY_(Dialogue)( doc, STRING_HELLO_ACCESS );
3511
3512
    /* Checks all elements for script accessibility */
3513
0
    CheckScriptKeyboardAccessible( doc, &doc->root );
3514
3515
    /* Checks entire document for the use of 'STYLE' attribute */
3516
0
    CheckForStyleAttribute( doc, &doc->root );
3517
3518
    /* Checks for '!DOCTYPE' */
3519
0
    CheckDocType( doc );
3520
3521
    
3522
    /* Checks to see if stylesheets are used to control the layout */
3523
0
    if ( Level2_Enabled( doc )
3524
0
         && ! CheckMissingStyleSheets( doc, &doc->root ) )
3525
0
    {
3526
0
        TY_(ReportAccessError)( doc, &doc->root, STYLE_SHEET_CONTROL_PRESENTATION );
3527
0
    }
3528
3529
    /* Check to see if any list elements are found within the document */
3530
0
    CheckForListElements( doc, &doc->root );
3531
3532
    /* Recursively apply all remaining checks to 
3533
    ** each node in document.
3534
    */
3535
0
    AccessibilityCheckNode( doc, &doc->root );
3536
3537
    /* Cleanup */
3538
0
    FreeAccessibilityChecks( doc );
3539
0
}
3540