Statistics
| Revision:

root / import / ext3D / trunk / install-extension3d / IzPack / src / lib / net / n3 / nanoxml / XMLUtil.java @ 15280

History | View | Annotate | Download (26.6 KB)

1
/* XMLUtil.java                                                    NanoXML/Java
2
 *
3
 * $Revision: 1.1 $
4
 * $Date: 2006/06/14 07:29:07 $
5
 * $Name:  $
6
 *
7
 * This file is part of NanoXML 2 for Java.
8
 * Copyright (C) 2001 Marc De Scheemaecker, All Rights Reserved.
9
 *
10
 * This software is provided 'as-is', without any express or implied warranty.
11
 * In no event will the authors be held liable for any damages arising from the
12
 * use of this software.
13
 *
14
 * Permission is granted to anyone to use this software for any purpose,
15
 * including commercial applications, and to alter it and redistribute it
16
 * freely, subject to the following restrictions:
17
 *
18
 *  1. The origin of this software must not be misrepresented; you must not
19
 *     claim that you wrote the original software. If you use this software in
20
 *     a product, an acknowledgment in the product documentation would be
21
 *     appreciated but is not required.
22
 *
23
 *  2. Altered source versions must be plainly marked as such, and must not be
24
 *     misrepresented as being the original software.
25
 *
26
 *  3. This notice may not be removed or altered from any source distribution.
27
 */
28

    
29
package net.n3.nanoxml;
30

    
31

    
32
import java.io.CharArrayReader;
33
import java.io.IOException;
34
import java.io.Reader;
35

    
36

    
37
/**
38
 * Utility methods for NanoXML.
39
 *
40
 * @author Marc De Scheemaecker
41
 * @version $Name:  $, $Revision: 1.1 $
42
 */
43
class XMLUtil
44
{
45
    
46
    /**
47
     * Skips the remainder of a comment.
48
     * It is assumed that <!- is already read.
49
     *
50
     * @param reader         the reader
51
     * @param entityResolver the entity resolver
52
     *
53
     * @throws java.io.IOException
54
     *                if an error occurred reading the data
55
     */
56
    static void skipComment(IXMLReader         reader,
57
                            IXMLEntityResolver entityResolver)
58
        throws IOException, XMLParseException
59
    {
60
        if (reader.read() != '-') {
61
            XMLUtil.skipTag(reader, '\0', entityResolver);
62
            return;
63
        }
64
        
65
        int dashesRead = 0;
66
        
67
        for (;;) {
68
            char ch = reader.read();
69
            
70
            switch (ch) {
71
                case '-':
72
                    dashesRead++;
73
                    break;
74
                    
75
                case '>':
76
                    if (dashesRead == 2) {
77
                        return;
78
                    }
79
                    
80
                default:
81
                    dashesRead = 0;
82
            }
83
        }
84
    }
85
    
86
    
87
    /**
88
     * Skips the remainder of the current XML tag.
89
     *
90
     * @param reader         the reader
91
     * @param escapeChar     the escape character (& or %)
92
     * @param entityResolver the entity resolver
93
     *
94
     * @throws java.io.IOException
95
     *                if an error occurred reading the data
96
     */
97
    static void skipTag(IXMLReader         reader,
98
                        char               escapeChar,
99
                        IXMLEntityResolver entityResolver)
100
        throws IOException, XMLParseException
101
    {
102
        int level = 1;
103
        
104
        while (level > 0) {
105
            char ch = XMLUtil.read(reader, null, escapeChar, entityResolver);
106
            
107
            switch (ch) {
108
                case '<':
109
                    ++level;
110
                    break;
111
                    
112
                case '>':
113
                    --level;
114
                    break;
115
            }
116
        }
117
    }
118
    
119
    
120
    /**
121
     * Scans a public ID.
122
     *
123
     * @param publicID       will contain the public ID
124
     * @param reader         the reader
125
     * @param escapeChar     the escape character (&amp; or %)
126
     * @param entityResolver the entity resolver
127
     *
128
     * @return the system ID
129
     *
130
     * @throws java.io.IOException
131
     *                if an error occurred reading the data
132
     */
133
    static String scanPublicID(StringBuffer       publicID,
134
                               IXMLReader         reader,
135
                               char               escapeChar,
136
                               IXMLEntityResolver entityResolver)
137
        throws IOException, XMLParseException
138
    {
139
        if (! XMLUtil.checkLiteral(reader, escapeChar, entityResolver,
140
                                   "UBLIC")) {
141
            return null;
142
        }
143
        
144
        XMLUtil.skipWhitespace(reader, escapeChar, null, null);
145
        publicID.append(XMLUtil.scanString(reader, escapeChar, false,
146
                                           entityResolver));
147
        XMLUtil.skipWhitespace(reader, escapeChar, null, null);
148
        return XMLUtil.scanString(reader, escapeChar, false, entityResolver);
149
    }
150
    
151

    
152
    /**
153
     * Scans a system ID.
154
     *
155
     * @param reader         the reader
156
     * @param escapeChar     the escape character (&amp; or %)
157
     * @param entityResolver the entity resolver
158
     *
159
     * @return the system ID
160
     *
161
     * @throws java.io.IOException
162
     *                if an error occurred reading the data
163
     */
164
    static String scanSystemID(IXMLReader         reader,
165
                               char               escapeChar,
166
                               IXMLEntityResolver entityResolver)
167
        throws IOException, XMLParseException
168
    {
169
        if (! XMLUtil.checkLiteral(reader, escapeChar, entityResolver,
170
                                   "YSTEM")) {
171
            return null;
172
        }
173
        
174
        XMLUtil.skipWhitespace(reader, escapeChar, null, null);
175
        return XMLUtil.scanString(reader, escapeChar, false, entityResolver);
176
    }
177
    
178
    
179
    /**
180
     * Retrieves an identifier from the data.
181
     *
182
     * @param reader         the reader
183
     * @param escapeChar     the escape character (&amp; or %)
184
     * @param entityResolver the entity resolver
185
     *
186
     * @throws java.io.IOException
187
     *                if an error occurred reading the data
188
     */
189
    static String scanIdentifier(IXMLReader         reader,
190
                                 char               escapeChar,
191
                                 IXMLEntityResolver entityResolver)
192
        throws IOException, XMLParseException
193
    {
194
        StringBuffer result = new StringBuffer();
195
        
196
        for (;;) {
197
            char ch = XMLUtil.read(reader, null, escapeChar, entityResolver);
198
            
199
            if ((ch == '_') || (ch == ':') || (ch == '-') || (ch == '.')
200
                    || ((ch >= 'a') && (ch <= 'z'))
201
                    || ((ch >= 'A') && (ch <= 'Z'))
202
                    || ((ch >= '0') && (ch <= '9')) || (ch > '\u007E')) {
203
                result.append(ch);
204
            } else {
205
                reader.unread(ch);
206
                break;
207
            }
208
        }
209
        
210
        return result.toString();
211
    }
212
    
213
    
214
    /**
215
     * Retrieves a delimited string from the data.
216
     *
217
     * @param reader              the reader
218
     * @param escapeChar          the escape character (&amp; or %)
219
     * @param normalizeWhitespace if all whitespace chars need to be converted
220
     *                            to spaces
221
     * @param entityResolver      the entity resolver
222
     *
223
     * @throws java.io.IOException
224
     *                if an error occurred reading the data
225
     */
226
    static String scanString(IXMLReader         reader,
227
                             char               escapeChar,
228
                             boolean            normalizeWhitespace,
229
                             IXMLEntityResolver entityResolver)
230
        throws IOException, XMLParseException
231
    {
232
        StringBuffer result = new StringBuffer();
233
        boolean isEntity[] = new boolean[1];
234
        char delim = XMLUtil.read(reader, null, escapeChar, entityResolver);
235
        
236
        if ((delim != '\'') && (delim != '"')) {
237
            XMLUtil.errorExpectedInput(reader.getSystemID(),
238
                                       reader.getLineNr(),
239
                                       "delimited string");
240
        }
241
        
242
        for (;;) {
243
            char ch = XMLUtil.read(reader, isEntity, escapeChar,
244
                                   entityResolver);
245
            
246
            if ((! isEntity[0]) && (ch == escapeChar)) {
247
                reader.startNewStream(XMLUtil.scanEntity(isEntity, reader,
248
                                                         escapeChar,
249
                                                         entityResolver));
250
                ch = reader.read();
251
            }
252
                    
253
            if ((! isEntity[0]) && (ch == delim)) {
254
                break;
255
            } else if (normalizeWhitespace && (ch < ' ')) {
256
                result.append(' ');
257
            } else {
258
                result.append(ch);
259
            }
260
        }
261
        
262
        return result.toString();
263
    }
264

    
265

    
266
    /**
267
     * Processes an entity.
268
     *
269
     * @param isCharLiteral  will contain true if the entity is a char literal
270
     * @param reader         the reader
271
     * @param escapeChar     the escape character (&amp; or %)
272
     * @param entityResolver the entity resolver
273
     *
274
     * @return a reader from which the entity value can be retrieved
275
     *
276
     * @throws java.io.IOException
277
     *                if an error occurred reading the data
278
     */
279
    static Reader scanEntity(boolean[]          isCharLiteral,
280
                             IXMLReader         reader,
281
                             char               escapeChar,
282
                             IXMLEntityResolver entityResolver)
283
        throws IOException, XMLParseException
284
    {
285
        char ch = reader.read();
286
        StringBuffer keyBuf = new StringBuffer();
287
        
288
        while (ch != ';') {
289
            keyBuf.append(ch);
290
            ch = reader.read();
291
        }
292
        
293
        String key = keyBuf.toString();
294
        
295
        if (key.charAt(0) == '#') {
296
            if (isCharLiteral != null) {
297
                isCharLiteral[0] = true;
298
            }
299
            
300
            char[] chArr = new char[1];
301
            
302
            if (key.charAt(1) == 'x') {
303
                chArr[0] = (char) Integer.parseInt(key.substring(2), 16);
304
            } else {
305
                chArr[0] = (char) Integer.parseInt(key.substring(1), 10);
306
            }
307
            
308
            return new CharArrayReader(chArr);
309
        } else {
310
            Reader entityReader = entityResolver.getEntity(reader, key);
311
            
312
            if (entityReader == null) {
313
                XMLUtil.errorInvalidEntity(reader.getSystemID(),
314
                                           reader.getLineNr(),
315
                                           key);
316
            }
317
            
318
            return entityReader;
319
        }
320
    }
321
    
322

    
323
    /**
324
     * Skips whitespace from the reader.
325
     *
326
     * @param reader         the reader
327
     * @param escapeChar     the escape character (&amp; or %)
328
     * @param buffer         where to put the whitespace; null if the
329
     *                       whitespace does not have to be stored.
330
     * @param isEntity       if not null, will contain true if the data 
331
     *                       following the whitespace is an entity
332
     *
333
     * @throws java.io.IOException
334
     *                if an error occurred reading the data
335
     */
336
    static void skipWhitespace(IXMLReader   reader,
337
                               char         escapeChar,
338
                               StringBuffer buffer,
339
                               boolean[]    isEntity)
340
        throws IOException
341
    {
342
        char ch;
343
        
344
        if (buffer == null) {
345
            do {
346
                ch = reader.read();
347
            } while ((ch == ' ') || (ch == '\t') || (ch == '\n')
348
                     || (ch == '\r'));
349
        } else {
350
            for (;;) {
351
                ch = reader.read();
352
            
353
                if ((ch != ' ') && (ch != '\t') && (ch != '\n')
354
                        && (ch != '\r')) {
355
                    break;
356
                }
357
                
358
                buffer.append(ch);
359
            }
360
        }
361
        
362
        reader.unread(ch);
363
        
364
        if (isEntity != null) {
365
            isEntity[0] = (ch == escapeChar);
366
        }
367
    }
368
    
369

    
370
    /**
371
     * Reads a character from the reader.
372
     *
373
     * @param reader         the reader
374
     * @param isEntityValue  if the character is the first character in an
375
     *                       entity
376
     * @param escapeChar     the escape character (&amp; or %)
377
     * @param entityResolver the entity resolver
378
     *
379
     * @throws java.io.IOException
380
     *                if an error occurred reading the data
381
     */
382
    static char read(IXMLReader         reader,
383
                     boolean[]          isEntityValue,
384
                     char               escapeChar,
385
                     IXMLEntityResolver entityResolver)
386
        throws IOException, XMLParseException
387
    {
388
        char ch = reader.read();
389
        
390
        if (isEntityValue != null) {
391
            isEntityValue[0] = false;
392
        }
393
        
394
        if (ch == escapeChar) {
395
            boolean[] charLiteral = new boolean[1];
396
            reader.startNewStream(XMLUtil.scanEntity(charLiteral, reader,
397
                                                     escapeChar,
398
                                                     entityResolver));
399
            
400
            if (charLiteral[0]) {
401
                ch = reader.read();
402
                
403
                if (isEntityValue != null) {
404
                    isEntityValue[0] = true;
405
                }
406
            } else {
407
                ch = XMLUtil.read(reader, null, escapeChar, entityResolver);
408
            }
409
        }
410
                    
411
        return ch;
412
    }
413
    
414
    
415
    /**
416
     * Returns true if the data starts with <I>literal</I>.
417
     * Enough chars are read to determine this result.
418
     *
419
     * @param reader         the reader
420
     * @param escapeChar     the escape character (&amp; or %)
421
     * @param entityResolver the entity resolver
422
     * @param literal        the literal to check
423
     *
424
     * @throws java.io.IOException
425
     *                if an error occurred reading the data
426
     */
427
    static boolean checkLiteral(IXMLReader         reader,
428
                                char               escapeChar,
429
                                IXMLEntityResolver entityResolver,
430
                                String             literal)
431
        throws IOException, XMLParseException
432
    {
433
        for (int i = 0; i < literal.length(); i++) {
434
            char ch = XMLUtil.read(reader, null, escapeChar, entityResolver);
435

    
436
            if (ch != literal.charAt(i)) {
437
                return false;
438
            }
439
        }
440
        
441
        return true;
442
    }
443
    
444
    
445
    /**
446
     * Throws an XMLParseException to indicate that an expected string is not
447
     * encountered.
448
     *
449
     * @param systemID       the system ID from where the data came
450
     * @param lineNr         the line number in the XML data where the
451
     *                       exception occurred.
452
     * @param expectedString the string that is expected
453
     */
454
    static void errorExpectedInput(String systemID,
455
                                   int    lineNr,
456
                                   String expectedString)
457
        throws XMLParseException
458
    {
459
        throw new XMLParseException(systemID, lineNr,
460
                                    "Expected: " + expectedString);
461
    }
462

    
463
    
464
    /**
465
     * Throws an XMLParseException to indicate that an entity could not be
466
     * resolved.
467
     *
468
     * @param systemID       the system ID from where the data came
469
     * @param lineNr         the line number in the XML data where the
470
     *                       exception occurred.
471
     * @param key    the name of the entity
472
     */
473
    static void errorInvalidEntity(String systemID,
474
                                   int    lineNr,
475
                                   String     key)
476
        throws XMLParseException
477
    {
478
        throw new XMLParseException(systemID, lineNr,
479
                                    "Invalid entity: `&" + key + ";'");
480
    }
481
    
482
    
483
    /**
484
     * Throws an XMLParseException to indicate that a string is not expected
485
     * at this point.
486
     *
487
     * @param systemID       the system ID from where the data came
488
     * @param lineNr         the line number in the XML data where the
489
     *                       exception occurred.
490
     * @param unexpectedString the string that is unexpected
491
     */
492
    static void errorInvalidInput(String systemID,
493
                                  int    lineNr,
494
                                  String     unexpectedString)
495
        throws XMLParseException
496
    {
497
        throw new XMLParseException(systemID, lineNr,
498
                                    "Invalid input: " + unexpectedString);
499
    }
500
    
501
    
502
    /**
503
     * Throws an XMLParseException to indicate that the closing tag of an
504
     * element does not match the opening tag.
505
     *
506
     * @param systemID       the system ID from where the data came
507
     * @param lineNr         the line number in the XML data where the
508
     *                       exception occurred.
509
     * @param expectedName the name of the opening tag
510
     * @param wrongName    the name of the closing tag
511
     */
512
    static void errorWrongClosingTag(String systemID,
513
                                     int    lineNr,
514
                                     String     expectedName,
515
                                     String     wrongName)
516
        throws XMLParseException
517
    {
518
        throw new XMLParseException(systemID, lineNr,
519
                                    "Closing tag does not match opening tag: `"
520
                                    + wrongName + "' != `" + expectedName
521
                                    + "'");
522
    }
523

    
524

    
525
    /**
526
     * Throws an XMLParseException to indicate that extra data is encountered
527
     * in a closing tag.
528
     *
529
     * @param systemID       the system ID from where the data came
530
     * @param lineNr         the line number in the XML data where the
531
     *                       exception occurred.
532
     */
533
    static void errorClosingTagNotEmpty(String systemID,
534
                                        int    lineNr)
535
        throws XMLParseException
536
    {
537
        throw new XMLParseException(systemID, lineNr,
538
                                    "Closing tag must be empty");
539
    }
540

    
541

    
542
    /**
543
     * Throws an XMLValidationException to indicate that an element is missing.
544
     *
545
     * @param systemID       the system ID from where the data came
546
     * @param lineNr         the line number in the XML data where the
547
     *                       exception occurred.
548
     * @param parentElementName  the name of the offending element
549
     * @param missingElementName the name of the offending attribute
550
     */
551
    static void errorMissingElement(String systemID,
552
                                    int    lineNr,
553
                                    String parentElementName,
554
                                    String missingElementName)
555
        throws XMLValidationException
556
    {
557
        throw new XMLValidationException(
558
                XMLValidationException.MISSING_ELEMENT,
559
                systemID, lineNr,
560
                missingElementName,
561
                /*attributeName*/ null,
562
                /*attributeValue*/ null,
563
                "Element " + parentElementName 
564
                + " expects to have a " + missingElementName);
565
    }
566

    
567

    
568
    /**
569
     * Throws an XMLValidationException to indicate that an element is
570
     * unexpected.
571
     *
572
     * @param systemID       the system ID from where the data came
573
     * @param lineNr         the line number in the XML data where the
574
     *                       exception occurred.
575
     * @param parentElementName     the name of the parent attribute
576
     * @param unexpectedElementName the name of the offending attribute
577
     */
578
    static void errorUnexpectedElement(String systemID,
579
                                       int    lineNr,
580
                                       String parentElementName,
581
                                       String unexpectedElementName)
582
        throws XMLValidationException
583
    {
584
        throw new XMLValidationException(
585
                XMLValidationException.UNEXPECTED_ELEMENT,
586
                systemID, lineNr,
587
                unexpectedElementName,
588
                /*attributeName*/ null,
589
                /*attributeValue*/ null,
590
                "Unexpected " + unexpectedElementName + " in a "
591
                + parentElementName);
592
    }
593

    
594

    
595
    /**
596
     * Throws an XMLValidationException to indicate that an attribute is
597
     * missing.
598
     *
599
     * @param systemID       the system ID from where the data came
600
     * @param lineNr         the line number in the XML data where the
601
     *                       exception occurred.
602
     * @param elementName    the name of the offending element
603
     * @param attributeName  the name of the offending attribute
604
     */
605
    static void errorMissingAttribute(String systemID,
606
                                      int    lineNr,
607
                                      String elementName,
608
                                      String attributeName)
609
        throws XMLValidationException
610
    {
611
        throw new XMLValidationException(
612
                XMLValidationException.MISSING_ATTRIBUTE,
613
                systemID, lineNr,
614
                elementName,
615
                attributeName,
616
                /*attributeValue*/ null,
617
                "Element " + elementName + " expects an attribute named "
618
                + attributeName);
619
    }
620

    
621

    
622
    /**
623
     * Throws an XMLValidationException to indicate that an attribute is
624
     * unexpected.
625
     *
626
     * @param systemID       the system ID from where the data came
627
     * @param lineNr         the line number in the XML data where the
628
     *                       exception occurred.
629
     * @param elementName    the name of the offending element
630
     * @param attributeName  the name of the offending attribute
631
     */
632
    static void errorUnexpectedAttribute(String systemID,
633
                                         int    lineNr,
634
                                         String elementName,
635
                                         String attributeName)
636
        throws XMLValidationException
637
    {
638
        throw new XMLValidationException(
639
                XMLValidationException.UNEXPECTED_ATTRIBUTE,
640
                systemID, lineNr,
641
                elementName,
642
                attributeName,
643
                /*attributeValue*/ null,
644
                "Element " + elementName + " did not expect an attribute "
645
                + "named " + attributeName);
646
    }
647

    
648

    
649
    /**
650
     * Throws an XMLValidationException to indicate that an attribute has an
651
     * invalid value.
652
     *
653
     * @param systemID       the system ID from where the data came
654
     * @param lineNr         the line number in the XML data where the
655
     *                       exception occurred.
656
     * @param elementName    the name of the offending element
657
     * @param attributeName  the name of the offending attribute
658
     * @param attributeValue the value of the offending attribute
659
     */
660
    static void errorInvalidAttributeValue(String systemID,
661
                                           int    lineNr,
662
                                           String elementName,
663
                                           String attributeName,
664
                                           String attributeValue)
665
        throws XMLValidationException
666
    {
667
        throw new XMLValidationException(
668
                XMLValidationException.ATTRIBUTE_WITH_INVALID_VALUE,
669
                systemID, lineNr,
670
                elementName,
671
                attributeName,
672
                attributeValue,
673
                "Invalid value for attribute " + attributeName);
674
    }
675

    
676

    
677
    /**
678
     * Throws an XMLValidationException to indicate that a #PCDATA element was
679
     * missing.
680
     *
681
     * @param systemID       the system ID from where the data came
682
     * @param lineNr         the line number in the XML data where the
683
     *                       exception occurred.
684
     * @param parentElementName the name of the offending element
685
     */
686
    static void errorMissingPCData(String systemID,
687
                                         int    lineNr,
688
                                         String parentElementName)
689
        throws XMLValidationException
690
    {
691
        throw new XMLValidationException(
692
                XMLValidationException.MISSING_PCDATA,
693
                systemID, lineNr,
694
                /*elementName*/ null,
695
                /*attributeName*/ null,
696
                /*attributeValue*/ null,
697
                "Missing #PCDATA in element " + parentElementName);
698
    }
699

    
700

    
701
    /**
702
     * Throws an XMLValidationException to indicate that a #PCDATA element was
703
     * unexpected.
704
     *
705
     * @param systemID       the system ID from where the data came
706
     * @param lineNr         the line number in the XML data where the
707
     *                       exception occurred.
708
     * @param parentElementName the name of the offending element
709
     */
710
    static void errorUnexpectedPCData(String systemID,
711
                                      int    lineNr,
712
                                      String parentElementName)
713
        throws XMLValidationException
714
    {
715
        throw new XMLValidationException(
716
                XMLValidationException.UNEXPECTED_PCDATA,
717
                systemID, lineNr,
718
                /*elementName*/ null,
719
                /*attributeName*/ null,
720
                /*attributeValue*/ null,
721
                "Unexpected #PCDATA in element " + parentElementName);
722
    }
723

    
724

    
725
    /**
726
     * Throws an XMLValidationException.
727
     *
728
     * @param systemID       the system ID from where the data came
729
     * @param lineNr         the line number in the XML data where the
730
     *                       exception occurred.
731
     * @param message        the message of the exception.
732
     * @param elementName    the name of the offending element
733
     * @param attributeName  the name of the offending attribute
734
     * @param attributeValue the value of the offending attribute
735
     */
736
    static void validationError(String systemID,
737
                                int    lineNr,
738
                                String message,
739
                                String elementName,
740
                                String attributeName,
741
                                String attributeValue)
742
        throws XMLValidationException
743
    {
744
        throw new XMLValidationException(
745
                XMLValidationException.MISC_ERROR,
746
                systemID, lineNr,
747
                elementName,
748
                attributeName,
749
                attributeValue,
750
                message);
751
    }
752

    
753
}