~ubuntu-branches/ubuntu/karmic/libxerces2-java/karmic

« back to all changes in this revision

Viewing changes to src/org/apache/xerces/impl/XMLEntityManager.java

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2006-12-04 17:37:55 UTC
  • mfrom: (2.1.2 etch)
  • Revision ID: james.westby@ubuntu.com-20061204173755-hb6ybrrrk097zhx7
Tags: 2.8.1-1ubuntu1
* Merge with Debian unstable; remaining changes:
  - Build -gcj package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * The Apache Software License, Version 1.1
3
 
 *
4
 
 *
5
 
 * Copyright (c) 1999-2004 The Apache Software Foundation.
6
 
 * All rights reserved.
7
 
 *
8
 
 * Redistribution and use in source and binary forms, with or without
9
 
 * modification, are permitted provided that the following conditions
10
 
 * are met:
11
 
 *
12
 
 * 1. Redistributions of source code must retain the above copyright
13
 
 *    notice, this list of conditions and the following disclaimer.
14
 
 *
15
 
 * 2. Redistributions in binary form must reproduce the above copyright
16
 
 *    notice, this list of conditions and the following disclaimer in
17
 
 *    the documentation and/or other materials provided with the
18
 
 *    distribution.
19
 
 *
20
 
 * 3. The end-user documentation included with the redistribution,
21
 
 *    if any, must include the following acknowledgment:
22
 
 *       "This product includes software developed by the
23
 
 *        Apache Software Foundation (http://www.apache.org/)."
24
 
 *    Alternately, this acknowledgment may appear in the software itself,
25
 
 *    if and wherever such third-party acknowledgments normally appear.
26
 
 *
27
 
 * 4. The names "Xerces" and "Apache Software Foundation" must
28
 
 *    not be used to endorse or promote products derived from this
29
 
 *    software without prior written permission. For written
30
 
 *    permission, please contact apache@apache.org.
31
 
 *
32
 
 * 5. Products derived from this software may not be called "Apache",
33
 
 *    nor may "Apache" appear in their name, without prior written
34
 
 *    permission of the Apache Software Foundation.
35
 
 *
36
 
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37
 
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38
 
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39
 
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40
 
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41
 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42
 
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43
 
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44
 
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45
 
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46
 
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47
 
 * SUCH DAMAGE.
48
 
 * ====================================================================
49
 
 *
50
 
 * This software consists of voluntary contributions made by many
51
 
 * individuals on behalf of the Apache Software Foundation and was
52
 
 * originally based on software copyright (c) 1999, International
53
 
 * Business Machines, Inc., http://www.apache.org.  For more
54
 
 * information on the Apache Software Foundation, please see
55
 
 * <http://www.apache.org/>.
 
2
 * Copyright 1999-2006 The Apache Software Foundation.
 
3
 * 
 
4
 * Licensed under the Apache License, Version 2.0 (the "License");
 
5
 * you may not use this file except in compliance with the License.
 
6
 * You may obtain a copy of the License at
 
7
 * 
 
8
 *      http://www.apache.org/licenses/LICENSE-2.0
 
9
 * 
 
10
 * Unless required by applicable law or agreed to in writing, software
 
11
 * distributed under the License is distributed on an "AS IS" BASIS,
 
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
13
 * See the License for the specific language governing permissions and
 
14
 * limitations under the License.
56
15
 */
57
16
 
58
17
package org.apache.xerces.impl;
62
21
import java.io.InputStreamReader;
63
22
import java.io.Reader;
64
23
import java.io.StringReader;
 
24
import java.lang.reflect.Method;
 
25
import java.net.HttpURLConnection;
65
26
import java.net.URL;
66
 
import java.net.HttpURLConnection;
67
27
import java.net.URLConnection;
 
28
import java.security.AccessController;
 
29
import java.security.PrivilegedAction;
68
30
import java.util.Hashtable;
 
31
import java.util.Iterator;
69
32
import java.util.Locale;
 
33
import java.util.Map;
70
34
import java.util.Stack;
71
35
 
72
36
import org.apache.xerces.impl.io.ASCIIReader;
 
37
import org.apache.xerces.impl.io.Latin1Reader;
73
38
import org.apache.xerces.impl.io.UCSReader;
74
39
import org.apache.xerces.impl.io.UTF8Reader;
75
40
import org.apache.xerces.impl.msg.XMLMessageFormatter;
76
41
import org.apache.xerces.impl.validation.ValidationManager;
 
42
import org.apache.xerces.util.AugmentationsImpl;
77
43
import org.apache.xerces.util.EncodingMap;
 
44
import org.apache.xerces.util.HTTPInputSource;
78
45
import org.apache.xerces.util.SecurityManager;
79
46
import org.apache.xerces.util.SymbolTable;
80
47
import org.apache.xerces.util.URI;
81
48
import org.apache.xerces.util.XMLChar;
 
49
import org.apache.xerces.util.XMLEntityDescriptionImpl;
82
50
import org.apache.xerces.util.XMLResourceIdentifierImpl;
 
51
import org.apache.xerces.xni.Augmentations;
83
52
import org.apache.xerces.xni.XMLResourceIdentifier;
84
53
import org.apache.xerces.xni.XNIException;
85
54
import org.apache.xerces.xni.parser.XMLComponent;
107
76
 *  <li>http://apache.org/xml/properties/internal/entity-resolver</li>
108
77
 * </ul>
109
78
 *
110
 
 *
 
79
 * @xerces.internal
 
80
 * 
111
81
 * @author Andy Clark, IBM
112
82
 * @author Arnaud  Le Hors, IBM
113
83
 *
114
 
 * @version $Id: XMLEntityManager.java,v 1.74 2004/02/04 18:45:43 mrglavas Exp $
 
84
 * @version $Id: XMLEntityManager.java 443118 2006-09-13 20:52:53Z mrglavas $
115
85
 */
116
86
public class XMLEntityManager
117
87
    implements XMLComponent, XMLEntityResolver {
126
96
    /** Default buffer size before we've finished with the XMLDecl:  */
127
97
    public static final int DEFAULT_XMLDECL_BUFFER_SIZE = 64;
128
98
 
129
 
    /** Default internal entity buffer size (1024). */
130
 
    public static final int DEFAULT_INTERNAL_BUFFER_SIZE = 1024;
 
99
    /** Default internal entity buffer size (512). */
 
100
    public static final int DEFAULT_INTERNAL_BUFFER_SIZE = 512;
131
101
 
132
102
    // feature identifiers
133
103
 
379
349
 
380
350
    /** Resource identifer. */
381
351
    private final XMLResourceIdentifierImpl fResourceIdentifier = new XMLResourceIdentifierImpl();
 
352
    
 
353
    /** Augmentations for entities. */
 
354
    private final Augmentations fEntityAugs = new AugmentationsImpl();
 
355
    
 
356
    /** Pool of byte buffers. */
 
357
    private final ByteBufferPool fByteBufferPool = new ByteBufferPool(fBufferSize);
 
358
    
 
359
    /** Temporary storage for the current entity's byte buffer. */
 
360
    private byte[] fTempByteBuffer = null;
 
361
    
 
362
    /** Pool of character buffers. */
 
363
    private final CharacterBufferPool fCharacterBufferPool = new CharacterBufferPool(fBufferSize, DEFAULT_INTERNAL_BUFFER_SIZE);
382
364
 
383
365
    //
384
366
    // Constructors
399
381
     */
400
382
    public XMLEntityManager(XMLEntityManager entityManager) {
401
383
 
402
 
 
403
384
        // save shared entity declarations
404
385
        fDeclaredEntities = entityManager != null
405
386
                          ? entityManager.getDeclaredEntities() : null;
525
506
                }
526
507
            }
527
508
            Entity entity = new ExternalEntity(name,
528
 
                    new XMLResourceIdentifierImpl(publicId, literalSystemId, baseSystemId, expandSystemId(literalSystemId, baseSystemId, false)), null, fInExternalSubset);
 
509
                new XMLEntityDescriptionImpl(name, publicId, literalSystemId, baseSystemId, 
 
510
                expandSystemId(literalSystemId, baseSystemId, false)), null, fInExternalSubset);
529
511
            fEntities.put(name, entity);
530
512
        }
531
513
        else{
592
574
                                  String publicId, String systemId,
593
575
                                  String baseSystemId, String notation) {
594
576
        if (!fEntities.containsKey(name)) {
595
 
            Entity entity = new ExternalEntity(name, new XMLResourceIdentifierImpl(publicId, systemId, baseSystemId, null), notation, fInExternalSubset);
 
577
            Entity entity = new ExternalEntity(name, 
 
578
                new XMLEntityDescriptionImpl(name, publicId, systemId, baseSystemId, null), 
 
579
                notation, fInExternalSubset);
596
580
            fEntities.put(name, entity);
597
581
        }
598
582
        else{
728
712
            if (fEntityHandler != null) {
729
713
                String encoding = null;
730
714
                fResourceIdentifier.clear();
731
 
                fEntityHandler.startEntity(entityName, fResourceIdentifier, encoding);
732
 
                fEntityHandler.endEntity(entityName);
 
715
                fEntityAugs.removeAllItems();
 
716
                fEntityAugs.putItem(Constants.ENTITY_SKIPPED, Boolean.TRUE);
 
717
                fEntityHandler.startEntity(entityName, fResourceIdentifier, encoding, fEntityAugs);
 
718
                fEntityAugs.removeAllItems();
 
719
                fEntityAugs.putItem(Constants.ENTITY_SKIPPED, Boolean.TRUE);
 
720
                fEntityHandler.endEntity(entityName, fEntityAugs);
733
721
            }
734
722
            return;
735
723
        }
755
743
                    fResourceIdentifier.setValues(
756
744
                            (externalEntity.entityLocation != null ? externalEntity.entityLocation.getPublicId() : null),
757
745
                            extLitSysId, extBaseSysId, expandedSystemId);
758
 
                    fEntityHandler.startEntity(entityName, fResourceIdentifier, encoding);
759
 
                    fEntityHandler.endEntity(entityName);
 
746
                    fEntityAugs.removeAllItems();
 
747
                    fEntityAugs.putItem(Constants.ENTITY_SKIPPED, Boolean.TRUE);
 
748
                    fEntityHandler.startEntity(entityName, fResourceIdentifier, encoding, fEntityAugs);
 
749
                    fEntityAugs.removeAllItems();
 
750
                    fEntityAugs.putItem(Constants.ENTITY_SKIPPED, Boolean.TRUE);
 
751
                    fEntityHandler.endEntity(entityName, fEntityAugs);
760
752
                }
761
753
                return;
762
754
            }
769
761
                                ? fCurrentEntity
770
762
                                : (Entity)fEntityStack.elementAt(i);
771
763
            if (activeEntity.name == entityName) {
772
 
                String path = entityName;
 
764
                StringBuffer path = new StringBuffer(entityName);
773
765
                for (int j = i + 1; j < size; j++) {
774
766
                    activeEntity = (Entity)fEntityStack.elementAt(j);
775
 
                    path = path + " -> " + activeEntity.name;
 
767
                    path.append(" -> ");
 
768
                    path.append(activeEntity.name);
776
769
                }
777
 
                path = path + " -> " + fCurrentEntity.name;
778
 
                path = path + " -> " + entityName;
 
770
                path.append(" -> ");
 
771
                path.append(fCurrentEntity.name);
 
772
                path.append(" -> ");
 
773
                path.append(entityName);
779
774
                fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
780
775
                                           "RecursiveReference",
781
 
                                           new Object[] { entityName, path },
 
776
                                           new Object[] { entityName, path.toString() },
782
777
                                           XMLErrorReporter.SEVERITY_FATAL_ERROR);
783
778
                if (fEntityHandler != null) {
784
779
                    fResourceIdentifier.clear();
793
788
                                (externalEntity.entityLocation != null ? externalEntity.entityLocation.getPublicId() : null),
794
789
                                extLitSysId, extBaseSysId, expandedSystemId);
795
790
                    }
796
 
                    fEntityHandler.startEntity(entityName, fResourceIdentifier, encoding);
797
 
                    fEntityHandler.endEntity(entityName);
 
791
                    fEntityAugs.removeAllItems();
 
792
                    fEntityAugs.putItem(Constants.ENTITY_SKIPPED, Boolean.TRUE);
 
793
                    fEntityHandler.startEntity(entityName, fResourceIdentifier, encoding, fEntityAugs);
 
794
                    fEntityAugs.removeAllItems();
 
795
                    fEntityAugs.putItem(Constants.ENTITY_SKIPPED, Boolean.TRUE);
 
796
                    fEntityHandler.endEntity(entityName, fEntityAugs);
798
797
                }
799
798
                return;
800
799
            }
897
896
        
898
897
        // call handler
899
898
        if (fEntityHandler != null) {
900
 
            fEntityHandler.startEntity(name, fResourceIdentifier, encoding);
 
899
            fEntityHandler.startEntity(name, fResourceIdentifier, encoding, null);
901
900
        }
902
901
 
903
902
    } // startEntity(String,XMLInputSource)
924
923
        String literalSystemId = xmlInputSource.getSystemId();
925
924
        String baseSystemId = xmlInputSource.getBaseSystemId();
926
925
        String encoding = xmlInputSource.getEncoding();
 
926
        final boolean encodingExternallySpecified = (encoding != null);
927
927
        Boolean isBigEndian = null;
928
 
                boolean declaredEncoding = false;
 
928
        fTempByteBuffer = null;
929
929
 
930
930
        // create reader
931
931
        InputStream stream = null;
937
937
        }
938
938
        if (reader == null) {
939
939
            stream = xmlInputSource.getByteStream();
940
 
                        if(stream != null && encoding != null)
941
 
                                declaredEncoding = true;
942
940
            if (stream == null) {
943
941
                URL location = new URL(expandedSystemId);
944
942
                URLConnection connect = location.openConnection();
945
 
                stream = connect.getInputStream();
946
 
                
947
 
                // REVISIT: If the URLConnection has external encoding
948
 
                // information, we should be reading it here. It's located
949
 
                // in the charset parameter of Content-Type. -- mrglavas
950
 
                if (connect instanceof HttpURLConnection) {
951
 
                    String redirect = connect.getURL().toString();
952
 
                    // E43: Check if the URL was redirected, and then
953
 
                    // update literal and expanded system IDs if needed.
954
 
                    if (!redirect.equals(expandedSystemId)) {
955
 
                        literalSystemId = redirect;
956
 
                        expandedSystemId = redirect;
 
943
                if (!(connect instanceof HttpURLConnection)) {
 
944
                    stream = connect.getInputStream();
 
945
                }
 
946
                else {
 
947
                    boolean followRedirects = true;
 
948
                    
 
949
                    // setup URLConnection if we have an HTTPInputSource
 
950
                    if (xmlInputSource instanceof HTTPInputSource) {
 
951
                        final HttpURLConnection urlConnection = (HttpURLConnection) connect;
 
952
                        final HTTPInputSource httpInputSource = (HTTPInputSource) xmlInputSource;
 
953
                        
 
954
                        // set request properties
 
955
                        Iterator propIter = httpInputSource.getHTTPRequestProperties();
 
956
                        while (propIter.hasNext()) {
 
957
                            Map.Entry entry = (Map.Entry) propIter.next();
 
958
                            urlConnection.setRequestProperty((String) entry.getKey(), (String) entry.getValue());
 
959
                        }
 
960
                        
 
961
                        // set preference for redirection
 
962
                        followRedirects = httpInputSource.getFollowHTTPRedirects();
 
963
                        if (!followRedirects) {
 
964
                            setInstanceFollowRedirects(urlConnection, followRedirects);
 
965
                        }
 
966
                    }
 
967
                    
 
968
                    stream = connect.getInputStream();
 
969
                    
 
970
                    // REVISIT: If the URLConnection has external encoding
 
971
                    // information, we should be reading it here. It's located
 
972
                    // in the charset parameter of Content-Type. -- mrglavas
 
973
                    
 
974
                    if (followRedirects) {
 
975
                        String redirect = connect.getURL().toString();
 
976
                        // E43: Check if the URL was redirected, and then
 
977
                        // update literal and expanded system IDs if needed.
 
978
                        if (!redirect.equals(expandedSystemId)) {
 
979
                            literalSystemId = redirect;
 
980
                            expandedSystemId = redirect;
 
981
                        }
957
982
                    }
958
983
                }
959
984
            }
974
999
                    isBigEndian = (Boolean)(encodingDesc[1]);
975
1000
 
976
1001
                    stream.reset();
977
 
                    int offset = 0;
978
1002
                    // Special case UTF-8 files with BOM created by Microsoft
979
1003
                    // tools. It's more efficient to consume the BOM than make
980
1004
                    // the reader perform extra checks. -Ac
1016
1040
                    else {
1017
1041
                        stream.reset();
1018
1042
                    }
 
1043
                    reader = createReader(stream, encoding, isBigEndian);
 
1044
                }
 
1045
                // If encoding is UTF-16, we still need to read the first four bytes
 
1046
                // in order to discover the byte order.
 
1047
                else if (encoding.equals("UTF-16")) {
 
1048
                    final int[] b4 = new int[4];
 
1049
                    int count = 0;
 
1050
                    for (; count < 4; ++count) {
 
1051
                        b4[count] = stream.read();
 
1052
                        if (b4[count] == -1)
 
1053
                            break;
 
1054
                    }
 
1055
                    stream.reset();
 
1056
                    
 
1057
                    String utf16Encoding = "UTF-16";
 
1058
                    if (count >= 2) {
 
1059
                        final int b0 = b4[0];
 
1060
                        final int b1 = b4[1];
 
1061
                        if (b0 == 0xFE && b1 == 0xFF) {
 
1062
                            // UTF-16, big-endian
 
1063
                            utf16Encoding = "UTF-16BE";
 
1064
                            isBigEndian = Boolean.TRUE;
 
1065
                        }
 
1066
                        else if (b0 == 0xFF && b1 == 0xFE) {
 
1067
                            // UTF-16, little-endian
 
1068
                            utf16Encoding = "UTF-16LE";
 
1069
                            isBigEndian = Boolean.FALSE;
 
1070
                        }
 
1071
                        else if (count == 4) {
 
1072
                            final int b2 = b4[2];
 
1073
                            final int b3 = b4[3];
 
1074
                            if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x3F) {
 
1075
                                // UTF-16, big-endian, no BOM
 
1076
                                utf16Encoding = "UTF-16BE";
 
1077
                                isBigEndian = Boolean.TRUE;
 
1078
                            }
 
1079
                            if (b0 == 0x3C && b1 == 0x00 && b2 == 0x3F && b3 == 0x00) {
 
1080
                                // UTF-16, little-endian, no BOM
 
1081
                                utf16Encoding = "UTF-16LE";
 
1082
                                isBigEndian = Boolean.FALSE;
 
1083
                            }
 
1084
                        }
 
1085
                    }
 
1086
                    reader = createReader(stream, utf16Encoding, isBigEndian);
1019
1087
                }
1020
1088
                // If encoding is UCS-4, we still need to read the first four bytes
1021
1089
                // in order to discover the byte order.
1040
1108
                            isBigEndian = Boolean.FALSE;
1041
1109
                        }
1042
1110
                    }
 
1111
                    reader = createReader(stream, encoding, isBigEndian);
1043
1112
                }
1044
1113
                // If encoding is UCS-2, we still need to read the first four bytes
1045
1114
                // in order to discover the byte order.
1063
1132
                            isBigEndian = Boolean.FALSE;
1064
1133
                        }
1065
1134
                    }
1066
 
                }
1067
 
                
1068
 
                reader = createReader(stream, encoding, isBigEndian);
 
1135
                    reader = createReader(stream, encoding, isBigEndian);
 
1136
                }
 
1137
                else {
 
1138
                    reader = createReader(stream, encoding, isBigEndian);
 
1139
                }
1069
1140
            }
1070
1141
 
1071
1142
            // read one character at a time so we don't jump too far
1089
1160
        // create entity
1090
1161
        fCurrentEntity = new ScannedEntity(name,
1091
1162
                new XMLResourceIdentifierImpl(publicId, literalSystemId, baseSystemId, expandedSystemId),
1092
 
                stream, reader, encoding, literal, false, isExternal);
1093
 
                fCurrentEntity.setDeclaredEncoding(declaredEncoding);
 
1163
                stream, reader, fTempByteBuffer, encoding, literal, false, isExternal);
 
1164
                fCurrentEntity.setEncodingExternallySpecified(encodingExternallySpecified);
1094
1165
        fEntityScanner.setCurrentEntity(fCurrentEntity);
1095
1166
        fResourceIdentifier.setValues(publicId, literalSystemId, baseSystemId, expandedSystemId);
1096
1167
        return encoding;
1395
1466
                    bufferSize.intValue() > DEFAULT_XMLDECL_BUFFER_SIZE) {
1396
1467
                    fBufferSize = bufferSize.intValue();
1397
1468
                    fEntityScanner.setBufferSize(fBufferSize);
 
1469
                    fByteBufferPool.setBufferSize(fBufferSize);
 
1470
                    fCharacterBufferPool.setExternalBufferSize(fBufferSize);
1398
1471
                }
1399
1472
            }
1400
1473
            if (suffixLength == Constants.SECURITY_MANAGER_PROPERTY.length() && 
1448
1521
 
1449
1522
    // current value of the "user.dir" property
1450
1523
    private static String gUserDir;
1451
 
    // escaped value of the current "user.dir" property
1452
 
    private static String gEscapedUserDir;
 
1524
    // cached URI object for the current value of the escaped "user.dir" property stored as a URI
 
1525
    private static URI gUserDirURI;
1453
1526
    // which ASCII characters need to be escaped
1454
1527
    private static boolean gNeedEscaping[] = new boolean[128];
1455
1528
    // the first hex character if a character needs to be escaped
1479
1552
            gAfterEscaping2[ch] = gHexChs[ch & 0xf];
1480
1553
        }
1481
1554
    }
 
1555
    
 
1556
    private static PrivilegedAction GET_USER_DIR_SYSTEM_PROPERTY = new PrivilegedAction() {
 
1557
        public Object run() {
 
1558
            return System.getProperty("user.dir");
 
1559
        }
 
1560
    };
 
1561
    
1482
1562
    // To escape the "user.dir" system property, by using %HH to represent
1483
1563
    // special ASCII characters: 0x00~0x1F, 0x7F, ' ', '<', '>', '#', '%'
1484
1564
    // and '"'. It's a static method, so needs to be synchronized.
1485
1565
    // this method looks heavy, but since the system property isn't expected
1486
 
    // to change often, so in most cases, we only need to return the string
 
1566
    // to change often, so in most cases, we only need to return the URI
1487
1567
    // that was escaped before.
1488
1568
    // According to the URI spec, non-ASCII characters (whose value >= 128)
1489
1569
    // need to be escaped too.
1490
1570
    // REVISIT: don't know how to escape non-ASCII characters, especially
1491
1571
    // which encoding to use. Leave them for now.
1492
 
    private static synchronized String getUserDir() {
 
1572
    private static synchronized URI getUserDir() throws URI.MalformedURIException {
1493
1573
        // get the user.dir property
1494
1574
        String userDir = "";
1495
1575
        try {
1496
 
            userDir = System.getProperty("user.dir");
1497
 
        }
1498
 
        catch (SecurityException se) {
1499
 
        }
 
1576
            userDir = (String) AccessController.doPrivileged(GET_USER_DIR_SYSTEM_PROPERTY);
 
1577
        }
 
1578
        catch (SecurityException se) {}
1500
1579
 
1501
1580
        // return empty string if property value is empty string.
1502
 
        if (userDir.length() == 0)
1503
 
            return "";
 
1581
        if (userDir.length() == 0) 
 
1582
            return new URI("file", "", "", null, null);
1504
1583
        
1505
1584
        // compute the new escaped value if the new property value doesn't
1506
1585
        // match the previous one
1507
 
        if (userDir.equals(gUserDir)) {
1508
 
            return gEscapedUserDir;
 
1586
        if (gUserDirURI != null && userDir.equals(gUserDir)) {
 
1587
            return gUserDirURI;
1509
1588
        }
1510
1589
 
1511
1590
        // record the new value as the global property value
1551
1630
                bytes = userDir.substring(i).getBytes("UTF-8");
1552
1631
            } catch (java.io.UnsupportedEncodingException e) {
1553
1632
                // should never happen
1554
 
                return userDir;
 
1633
                return new URI("file", "", userDir, null, null);
1555
1634
            }
1556
1635
            len = bytes.length;
1557
1636
 
1580
1659
        if (!userDir.endsWith("/"))
1581
1660
            buffer.append('/');
1582
1661
        
1583
 
        gEscapedUserDir = buffer.toString();
 
1662
        gUserDirURI = new URI("file", "", buffer.toString(), null, null);
1584
1663
 
1585
 
        return gEscapedUserDir;
 
1664
        return gUserDirURI;
 
1665
    }
 
1666
    
 
1667
    /**
 
1668
     * Absolutizes a URI using the current value
 
1669
     * of the "user.dir" property as the base URI. If
 
1670
     * the URI is already absolute, this is a no-op.
 
1671
     * 
 
1672
     * @param uri the URI to absolutize
 
1673
     */
 
1674
    public static void absolutizeAgainstUserDir(URI uri) 
 
1675
        throws URI.MalformedURIException {
 
1676
        uri.absolutize(getUserDir());
1586
1677
    }
1587
1678
 
1588
1679
    /**
1602
1693
                                        boolean strict)
1603
1694
            throws URI.MalformedURIException {
1604
1695
 
 
1696
        // check if there is a system id before 
 
1697
        // trying to expand it.
 
1698
        if (systemId == null) {
 
1699
            return null;
 
1700
        }
 
1701
        
1605
1702
        // system id has to be a valid URI
1606
1703
        if (strict) {
1607
 
            
1608
 
            // check if there is a system id before 
1609
 
            // trying to expand it.
1610
 
            if (systemId == null) {
1611
 
                return null;
1612
 
            }
1613
 
            
1614
 
            try {
1615
 
                // if it's already an absolute one, return it
1616
 
                URI uri = new URI(systemId);
1617
 
                return systemId;
1618
 
            }
1619
 
            catch (URI.MalformedURIException ex) {
1620
 
            }
1621
 
            URI base = null;
1622
 
            // if there isn't a base uri, use the working directory
1623
 
            if (baseSystemId == null || baseSystemId.length() == 0) {
1624
 
                base = new URI("file", "", getUserDir(), null, null);
1625
 
            }
1626
 
            // otherwise, use the base uri
1627
 
            else {
1628
 
                try {
1629
 
                    base = new URI(baseSystemId);
1630
 
                }
1631
 
                catch (URI.MalformedURIException e) {
1632
 
                    // assume "base" is also a relative uri
1633
 
                    String dir = getUserDir();
1634
 
                    dir = dir + baseSystemId;
1635
 
                    base = new URI("file", "", dir, null, null);
1636
 
                }
1637
 
            }
1638
 
            // absolutize the system id using the base
1639
 
            URI uri = new URI(base, systemId);
1640
 
            // return the string rep of the new uri (an absolute one)
1641
 
            return uri.toString();
1642
 
            
1643
 
            // if any exception is thrown, it'll get thrown to the caller.
 
1704
            return expandSystemIdStrictOn(systemId, baseSystemId);
1644
1705
        }
1645
1706
 
1646
 
        // check for bad parameters id
1647
 
        if (systemId == null || systemId.length() == 0) {
1648
 
            return systemId;
1649
 
        }
1650
 
        // if id already expanded, return
 
1707
        // Assume the URIs are well-formed. If it turns out they're not, try fixing them up.
1651
1708
        try {
1652
 
            URI uri = new URI(systemId.trim());
1653
 
            if (uri != null) {
1654
 
                return systemId;
1655
 
            }
 
1709
            return expandSystemIdStrictOff(systemId, baseSystemId);
1656
1710
        }
1657
1711
        catch (URI.MalformedURIException e) {
1658
1712
            // continue on...
1659
1713
        }
 
1714
        
 
1715
        // check for bad parameters id
 
1716
        if (systemId.length() == 0) {
 
1717
            return systemId;
 
1718
        }
 
1719
        
1660
1720
        // normalize id
1661
1721
        String id = fixURI(systemId);
1662
1722
 
1666
1726
        try {
1667
1727
            if (baseSystemId == null || baseSystemId.length() == 0 ||
1668
1728
                baseSystemId.equals(systemId)) {
1669
 
                String dir = getUserDir();
1670
 
                base = new URI("file", "", dir, null, null);
 
1729
                base = getUserDir();
1671
1730
            }
1672
1731
            else {
1673
1732
                try {
1680
1739
                        base = new URI("file", "", fixURI(baseSystemId).trim(), null, null);
1681
1740
                    }
1682
1741
                    else {
1683
 
                        String dir = getUserDir();
1684
 
                        dir = dir + fixURI(baseSystemId);
1685
 
                        base = new URI("file", "", dir, null, null);
 
1742
                        base = new URI(getUserDir(), fixURI(baseSystemId));
1686
1743
                    }
1687
1744
                }
1688
1745
             }
1699
1756
        }
1700
1757
        return uri.toString();
1701
1758
 
1702
 
    } // expandSystemId(String,String):String
 
1759
    } // expandSystemId(String,String,boolean):String
 
1760
    
 
1761
    /**
 
1762
     * Helper method for expandSystemId(String,String,boolean):String
 
1763
     */
 
1764
    private static String expandSystemIdStrictOn(String systemId, String baseSystemId)
 
1765
        throws URI.MalformedURIException {
 
1766
        
 
1767
        URI systemURI = new URI(systemId, true);
 
1768
        // If it's already an absolute one, return it
 
1769
        if (systemURI.isAbsoluteURI()) {
 
1770
            return systemId;
 
1771
        }
 
1772
        
 
1773
        // If there isn't a base URI, use the working directory
 
1774
        URI baseURI = null;
 
1775
        if (baseSystemId == null || baseSystemId.length() == 0) {
 
1776
            baseURI = getUserDir();
 
1777
        }
 
1778
        else {
 
1779
            baseURI = new URI(baseSystemId, true);
 
1780
            if (!baseURI.isAbsoluteURI()) {
 
1781
                // assume "base" is also a relative uri
 
1782
                baseURI.absolutize(getUserDir());
 
1783
            }
 
1784
        }
 
1785
        
 
1786
        // absolutize the system identifier using the base URI
 
1787
        systemURI.absolutize(baseURI);
 
1788
        
 
1789
        // return the string rep of the new uri (an absolute one)
 
1790
        return systemURI.toString();
 
1791
        
 
1792
        // if any exception is thrown, it'll get thrown to the caller.
 
1793
        
 
1794
    } // expandSystemIdStrictOn(String,String):String
 
1795
    
 
1796
    /**
 
1797
     * Helper method for expandSystemId(String,String,boolean):String
 
1798
     */
 
1799
    private static String expandSystemIdStrictOff(String systemId, String baseSystemId)
 
1800
        throws URI.MalformedURIException {
 
1801
        
 
1802
        URI systemURI = new URI(systemId, true);
 
1803
        // If it's already an absolute one, return it
 
1804
        if (systemURI.isAbsoluteURI()) {
 
1805
            if (systemURI.getScheme().length() > 1) {
 
1806
                return systemId;
 
1807
            }
 
1808
            /** 
 
1809
             * If the scheme's length is only one character,
 
1810
             * it's likely that this was intended as a file
 
1811
             * path. Fixing this up in expandSystemId to
 
1812
             * maintain backwards compatibility.
 
1813
             */
 
1814
            throw new URI.MalformedURIException();
 
1815
        }
 
1816
        
 
1817
        // If there isn't a base URI, use the working directory
 
1818
        URI baseURI = null;
 
1819
        if (baseSystemId == null || baseSystemId.length() == 0) {
 
1820
            baseURI = getUserDir();
 
1821
        }
 
1822
        else {
 
1823
            baseURI = new URI(baseSystemId, true);
 
1824
            if (!baseURI.isAbsoluteURI()) {
 
1825
                // assume "base" is also a relative uri
 
1826
                baseURI.absolutize(getUserDir());
 
1827
            }
 
1828
        }
 
1829
        
 
1830
        // absolutize the system identifier using the base URI
 
1831
        systemURI.absolutize(baseURI);
 
1832
        
 
1833
        // return the string rep of the new uri (an absolute one)
 
1834
        return systemURI.toString();
 
1835
        
 
1836
        // if any exception is thrown, it'll get thrown to the caller.
 
1837
        
 
1838
    } // expandSystemIdStrictOff(String,String):String
 
1839
    
 
1840
    /**
 
1841
     * Attempt to set whether redirects will be followed for an <code>HttpURLConnection</code>.
 
1842
     * This may fail on earlier JDKs which do not support setting this preference.
 
1843
     */
 
1844
    public static void setInstanceFollowRedirects(HttpURLConnection urlCon, boolean followRedirects) {
 
1845
        try {
 
1846
            Method method = HttpURLConnection.class.getMethod("setInstanceFollowRedirects", new Class[] {Boolean.TYPE});
 
1847
            method.invoke(urlCon, new Object[] {followRedirects ? Boolean.TRUE : Boolean.FALSE});
 
1848
        }
 
1849
        // setInstanceFollowRedirects doesn't exist.
 
1850
        catch (Exception exc) {}
 
1851
    }
1703
1852
 
1704
1853
    //
1705
1854
    // Protected methods
1719
1868
            System.out.println();
1720
1869
        }
1721
1870
        if (fEntityHandler != null) {
1722
 
            fEntityHandler.endEntity(fCurrentEntity.name);
 
1871
            fEntityHandler.endEntity(fCurrentEntity.name, null);
1723
1872
        }
1724
1873
        
1725
1874
        // Close the reader for the current entity once we're 
1739
1888
            fReaderStack.pop();
1740
1889
        } 
1741
1890
 
 
1891
        // Release the character buffer back to the pool for reuse
 
1892
        fCharacterBufferPool.returnBuffer(fCurrentEntity.fCharacterBuffer);
 
1893
        
 
1894
        // Release the byte buffer back to the pool for reuse
 
1895
        if (fCurrentEntity.fByteBuffer != null) {
 
1896
            fByteBufferPool.returnBuffer(fCurrentEntity.fByteBuffer);
 
1897
        }
 
1898
        
1742
1899
        // Pop entity stack.
1743
1900
        fCurrentEntity = fEntityStack.size() > 0
1744
1901
                       ? (ScannedEntity)fEntityStack.pop() : null;
1772
1929
        int b1 = b4[1] & 0xFF;
1773
1930
        if (b0 == 0xFE && b1 == 0xFF) {
1774
1931
            // UTF-16, big-endian
1775
 
            return new Object [] {"UTF-16BE", new Boolean(true)};
 
1932
            return new Object [] {"UTF-16BE", Boolean.TRUE};
1776
1933
        }
1777
1934
        if (b0 == 0xFF && b1 == 0xFE) {
1778
1935
            // UTF-16, little-endian
1779
 
            return new Object [] {"UTF-16LE", new Boolean(false)};
 
1936
            return new Object [] {"UTF-16LE", Boolean.FALSE};
1780
1937
        }
1781
1938
 
1782
1939
        // default to UTF-8 if we don't have enough bytes to make a
1801
1958
        int b3 = b4[3] & 0xFF;
1802
1959
        if (b0 == 0x00 && b1 == 0x00 && b2 == 0x00 && b3 == 0x3C) {
1803
1960
            // UCS-4, big endian (1234)
1804
 
            return new Object [] {"ISO-10646-UCS-4", new Boolean(true)};
 
1961
            return new Object [] {"ISO-10646-UCS-4", Boolean.TRUE};
1805
1962
        }
1806
1963
        if (b0 == 0x3C && b1 == 0x00 && b2 == 0x00 && b3 == 0x00) {
1807
1964
            // UCS-4, little endian (4321)
1808
 
            return new Object [] {"ISO-10646-UCS-4", new Boolean(false)};
 
1965
            return new Object [] {"ISO-10646-UCS-4", Boolean.FALSE};
1809
1966
        }
1810
1967
        if (b0 == 0x00 && b1 == 0x00 && b2 == 0x3C && b3 == 0x00) {
1811
1968
            // UCS-4, unusual octet order (2143)
1821
1978
            // UTF-16, big-endian, no BOM
1822
1979
            // (or could turn out to be UCS-2...
1823
1980
            // REVISIT: What should this be?
1824
 
            return new Object [] {"UTF-16BE", new Boolean(true)};
 
1981
            return new Object [] {"UTF-16BE", Boolean.TRUE};
1825
1982
        }
1826
1983
        if (b0 == 0x3C && b1 == 0x00 && b2 == 0x3F && b3 == 0x00) {
1827
1984
            // UTF-16, little-endian, no BOM
1828
1985
            // (or could turn out to be UCS-2...
1829
 
            return new Object [] {"UTF-16LE", new Boolean(false)};
 
1986
            return new Object [] {"UTF-16LE", Boolean.FALSE};
1830
1987
        }
1831
1988
        if (b0 == 0x4C && b1 == 0x6F && b2 == 0xA7 && b3 == 0x94) {
1832
1989
            // EBCDIC
1858
2015
    protected Reader createReader(InputStream inputStream, String encoding, Boolean isBigEndian)
1859
2016
        throws IOException {
1860
2017
 
1861
 
        // normalize encoding name
1862
 
        if (encoding == null) {
1863
 
            encoding = "UTF-8";
 
2018
        // if the encoding is UTF-8 use the optimized UTF-8 reader
 
2019
        if (encoding == "UTF-8" || encoding == null) {
 
2020
            if (DEBUG_ENCODINGS) {
 
2021
                System.out.println("$$$ creating UTF8Reader");
 
2022
            }
 
2023
            if (fTempByteBuffer == null) {
 
2024
                fTempByteBuffer = fByteBufferPool.getBuffer();
 
2025
            }
 
2026
            return new UTF8Reader(inputStream, fTempByteBuffer, fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN), fErrorReporter.getLocale());
1864
2027
        }
1865
2028
 
1866
2029
        // try to use an optimized reader
1869
2032
            if (DEBUG_ENCODINGS) {
1870
2033
                System.out.println("$$$ creating UTF8Reader");
1871
2034
            }
1872
 
            return new UTF8Reader(inputStream, fBufferSize, fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN), fErrorReporter.getLocale() );
1873
 
        }
1874
 
        if (ENCODING.equals("US-ASCII")) {
1875
 
            if (DEBUG_ENCODINGS) {
1876
 
                System.out.println("$$$ creating ASCIIReader");
 
2035
            if (fTempByteBuffer == null) {
 
2036
                fTempByteBuffer = fByteBufferPool.getBuffer();
1877
2037
            }
1878
 
            return new ASCIIReader(inputStream, fBufferSize, fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN), fErrorReporter.getLocale());
 
2038
            return new UTF8Reader(inputStream, fTempByteBuffer, fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN), fErrorReporter.getLocale());
1879
2039
        }
1880
2040
        if(ENCODING.equals("ISO-10646-UCS-4")) {
1881
2041
            if(isBigEndian != null) {
1924
2084
            //       invalid UTF-8 sequence to be detected. This is only
1925
2085
            //       important when continue-after-fatal-error is turned
1926
2086
            //       on. -Ac
1927
 
            encoding = "ISO-8859-1";
 
2087
            if (DEBUG_ENCODINGS) {
 
2088
                System.out.println("$$$ creating Latin1Reader");
 
2089
            }
 
2090
            return new Latin1Reader(inputStream, fBufferSize);
1928
2091
        }
1929
2092
 
1930
2093
        // try to use a Java reader
1931
2094
        String javaEncoding = EncodingMap.getIANA2JavaMapping(ENCODING);
1932
2095
        if (javaEncoding == null) {
1933
 
            if(fAllowJavaEncodings) {
1934
 
            javaEncoding = encoding;
1935
 
            } else {
 
2096
            if (fAllowJavaEncodings) {
 
2097
                javaEncoding = encoding;
 
2098
            } 
 
2099
            else {
1936
2100
                fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1937
2101
                                       "EncodingDeclInvalid",
1938
2102
                                       new Object[] { encoding },
1939
2103
                                       XMLErrorReporter.SEVERITY_FATAL_ERROR);
1940
2104
                // see comment above.
1941
 
                javaEncoding = "ISO8859_1";
1942
 
            }
 
2105
                if (DEBUG_ENCODINGS) {
 
2106
                    System.out.println("$$$ creating Latin1Reader");
 
2107
                }
 
2108
                if (fTempByteBuffer == null) {
 
2109
                    fTempByteBuffer = fByteBufferPool.getBuffer();
 
2110
                }
 
2111
                return new Latin1Reader(inputStream, fTempByteBuffer);
 
2112
            }
 
2113
        }
 
2114
        else if (javaEncoding.equals("ASCII")) {
 
2115
            if (DEBUG_ENCODINGS) {
 
2116
                System.out.println("$$$ creating ASCIIReader");
 
2117
            }
 
2118
            if (fTempByteBuffer == null) {
 
2119
                fTempByteBuffer = fByteBufferPool.getBuffer();
 
2120
            }
 
2121
            return new ASCIIReader(inputStream, fTempByteBuffer, fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN), fErrorReporter.getLocale());
 
2122
        }
 
2123
        else if (javaEncoding.equals("ISO8859_1")) {
 
2124
            if (DEBUG_ENCODINGS) {
 
2125
                System.out.println("$$$ creating Latin1Reader");
 
2126
            }
 
2127
            if (fTempByteBuffer == null) {
 
2128
                fTempByteBuffer = fByteBufferPool.getBuffer();
 
2129
            }
 
2130
            return new Latin1Reader(inputStream, fTempByteBuffer);
1943
2131
        }
1944
2132
        if (DEBUG_ENCODINGS) {
1945
2133
            System.out.print("$$$ creating Java InputStreamReader: encoding="+javaEncoding);
1973
2161
        // Windows fix
1974
2162
        if (str.length() >= 2) {
1975
2163
            char ch1 = str.charAt(1);
1976
 
            // change "C:blah" to "/C:blah"
 
2164
            // change "C:blah" to "file:///C:blah"
1977
2165
            if (ch1 == ':') {
1978
2166
                char ch0 = Character.toUpperCase(str.charAt(0));
1979
2167
                if (ch0 >= 'A' && ch0 <= 'Z') {
1980
 
                    sb = new StringBuffer(str.length());
1981
 
                    sb.append('/');
 
2168
                    sb = new StringBuffer(str.length() + 8);
 
2169
                    sb.append("file:///");
1982
2170
                }
1983
2171
            }
1984
2172
            // change "//blah" to "file://blah"
1985
2173
            else if (ch1 == '/' && str.charAt(0) == '/') {
1986
 
                sb = new StringBuffer(str.length());
 
2174
                sb = new StringBuffer(str.length() + 5);
1987
2175
                sb.append("file:");
1988
2176
            }
1989
2177
        }
2099
2287
 
2100
2288
    /**
2101
2289
     * Entity information.
 
2290
     * 
 
2291
     * @xerces.internal
2102
2292
     *
2103
2293
     * @author Andy Clark, IBM
2104
2294
     */
2161
2351
 
2162
2352
    /**
2163
2353
     * Internal entity.
 
2354
     * 
 
2355
     * @xerces.internal
2164
2356
     *
2165
2357
     * @author Andy Clark, IBM
2166
2358
     */
2225
2417
 
2226
2418
    /**
2227
2419
     * External entity.
 
2420
     * 
 
2421
     * @xerces.internal
2228
2422
     *
2229
2423
     * @author Andy Clark, IBM
2230
2424
     */
2297
2491
 
2298
2492
    /**
2299
2493
     * Entity state.
 
2494
     * 
 
2495
     * @xerces.internal
2300
2496
     *
2301
2497
     * @author Andy Clark, IBM
2302
2498
     */
2327
2523
        public int columnNumber = 1;
2328
2524
 
2329
2525
        // encoding
2330
 
 
 
2526
        
2331
2527
        /** Auto-detected encoding. */
2332
2528
        public String encoding;
2333
 
 
2334
 
                /** Encoding has been set externally for eg: using DOMInput*/
2335
 
                boolean declaredEncoding = false;
 
2529
        
 
2530
        /** 
 
2531
         * Encoding has been set externally, for example
 
2532
         * using a SAX InputSource or a DOM LSInput.
 
2533
         */
 
2534
        boolean externallySpecifiedEncoding = false;
 
2535
        
 
2536
        // version
 
2537
        
 
2538
        /** XML version. **/
 
2539
        public String xmlVersion = "1.0";
2336
2540
        
2337
2541
                // status
2338
2542
 
2346
2550
 
2347
2551
        /** Character buffer. */
2348
2552
        public char[] ch = null;
2349
 
 
 
2553
        
2350
2554
        /** Position in character buffer. */
2351
2555
        public int position;
2352
 
 
 
2556
        
 
2557
        /** Base character offset for computing absolute character offset. */
 
2558
        public int baseCharOffset;
 
2559
        
 
2560
        /** Start position in character buffer. */
 
2561
        public int startPosition;
 
2562
        
2353
2563
        /** Count of characters in buffer. */
2354
2564
        public int count;
2355
2565
 
2356
2566
        // to allow the reader/inputStream to behave efficiently:
2357
2567
        public boolean mayReadChunks;
2358
 
 
 
2568
        
 
2569
        /** Character buffer container. */
 
2570
        private CharacterBuffer fCharacterBuffer;
 
2571
        
 
2572
        /** Byte buffer. */
 
2573
        private byte [] fByteBuffer;
 
2574
        
2359
2575
        //
2360
2576
        // Constructors
2361
2577
        //
2363
2579
        /** Constructs a scanned entity. */
2364
2580
        public ScannedEntity(String name,
2365
2581
                             XMLResourceIdentifier entityLocation,
2366
 
                             InputStream stream, Reader reader,
 
2582
                             InputStream stream, Reader reader, byte [] byteBuffer,
2367
2583
                             String encoding, boolean literal, boolean mayReadChunks, boolean isExternal) {
2368
2584
            super(name,XMLEntityManager.this.fInExternalSubset);
2369
2585
            this.entityLocation = entityLocation;
2373
2589
            this.literal = literal;
2374
2590
            this.mayReadChunks = mayReadChunks;
2375
2591
            this.isExternal = isExternal;
2376
 
            this.ch = new char[isExternal ? fBufferSize : DEFAULT_INTERNAL_BUFFER_SIZE];
 
2592
            this.fCharacterBuffer = fCharacterBufferPool.getBuffer(isExternal);
 
2593
            this.ch = fCharacterBuffer.ch;
 
2594
            this.fByteBuffer = byteBuffer;
2377
2595
        } // <init>(StringXMLResourceIdentifier,InputStream,Reader,String,boolean, boolean)
2378
2596
 
2379
2597
        //
2391
2609
        } // isUnparsed():boolean
2392
2610
 
2393
2611
        public void setReader(InputStream stream, String encoding, Boolean isBigEndian) throws IOException {
 
2612
            fTempByteBuffer = fByteBuffer;
2394
2613
            reader = createReader(stream, encoding, isBigEndian);
 
2614
            fByteBuffer = fTempByteBuffer;
2395
2615
        }
2396
2616
 
2397
2617
        // return the expanded system ID of the 
2401
2621
 
2402
2622
            // search for the first external entity on the stack
2403
2623
            int size = fEntityStack.size();
2404
 
            for (int i = size - 1; i >= 0 ; i--) {
 
2624
            for (int i = size - 1; i >= 0; --i) {
2405
2625
               ScannedEntity externalEntity =
2406
2626
                    (ScannedEntity)fEntityStack.elementAt(i);
2407
2627
 
2418
2638
        public String getLiteralSystemId() { 
2419
2639
            // search for the first external entity on the stack
2420
2640
            int size = fEntityStack.size();
2421
 
            for (int i = size - 1; i >= 0 ; i--) {
 
2641
            for (int i = size - 1; i >= 0; --i) {
2422
2642
               ScannedEntity externalEntity =
2423
2643
                    (ScannedEntity)fEntityStack.elementAt(i);
2424
2644
 
2429
2649
            }
2430
2650
            return null;
2431
2651
        }
2432
 
 
 
2652
        
2433
2653
        // return line number of position in most
2434
2654
        // recent external entity
2435
2655
        public int getLineNumber() {
2436
2656
            // search for the first external entity on the stack
2437
2657
            int size = fEntityStack.size();
2438
 
            for (int i=size-1; i>0 ; i--) {
2439
 
               ScannedEntity firstExternalEntity = (ScannedEntity)fEntityStack.elementAt(i);
 
2658
            for (int i = size - 1; i >= 0 ; --i) {
 
2659
                ScannedEntity firstExternalEntity = (ScannedEntity)fEntityStack.elementAt(i);
2440
2660
                if (firstExternalEntity.isExternal()) {
2441
2661
                    return firstExternalEntity.lineNumber;
2442
2662
                }
2443
2663
            }
2444
2664
            return -1;
2445
2665
        }
2446
 
 
 
2666
        
2447
2667
        // return column number of position in most
2448
2668
        // recent external entity
2449
2669
        public int getColumnNumber() {
2450
2670
            // search for the first external entity on the stack
2451
2671
            int size = fEntityStack.size();
2452
 
            for (int i=size-1; i>0 ; i--) {
2453
 
               ScannedEntity firstExternalEntity = (ScannedEntity)fEntityStack.elementAt(i);
 
2672
            for (int i = size - 1; i >= 0; --i) {
 
2673
                ScannedEntity firstExternalEntity = (ScannedEntity)fEntityStack.elementAt(i);
2454
2674
                if (firstExternalEntity.isExternal()) {
2455
2675
                    return firstExternalEntity.columnNumber;
2456
2676
                }
2457
2677
            }
2458
2678
            return -1;
2459
2679
        }
2460
 
 
 
2680
        
 
2681
        // return character offset of position in most
 
2682
        // recent external entity
 
2683
        public int getCharacterOffset() {
 
2684
            // search for the first external entity on the stack
 
2685
            int size = fEntityStack.size();
 
2686
            for (int i = size - 1; i >= 0; --i) {
 
2687
                ScannedEntity firstExternalEntity = (ScannedEntity)fEntityStack.elementAt(i);
 
2688
                if (firstExternalEntity.isExternal()) {
 
2689
                    return firstExternalEntity.baseCharOffset + (firstExternalEntity.position - firstExternalEntity.startPosition);
 
2690
                }
 
2691
            }
 
2692
            return -1;
 
2693
        }
 
2694
        
2461
2695
        // return encoding of most recent external entity
2462
2696
        public String getEncoding() {
2463
2697
            // search for the first external entity on the stack
2464
2698
            int size = fEntityStack.size();
2465
 
            for (int i=size-1; i>0 ; i--) {
2466
 
               ScannedEntity firstExternalEntity = (ScannedEntity)fEntityStack.elementAt(i);
 
2699
            for (int i = size - 1; i >= 0; --i) {
 
2700
                ScannedEntity firstExternalEntity = (ScannedEntity)fEntityStack.elementAt(i);
2467
2701
                if (firstExternalEntity.isExternal()) {
2468
2702
                    return firstExternalEntity.encoding;
2469
2703
                }
2470
2704
            }
2471
2705
            return null;
2472
2706
        }
2473
 
 
 
2707
        
 
2708
        // return xml version of most recent external entity
 
2709
        public String getXMLVersion() {
 
2710
            // search for the first external entity on the stack
 
2711
            int size = fEntityStack.size();
 
2712
            for (int i = size - 1; i >= 0; --i) {
 
2713
                ScannedEntity firstExternalEntity = (ScannedEntity)fEntityStack.elementAt(i);
 
2714
                if (firstExternalEntity.isExternal()) {
 
2715
                    return firstExternalEntity.xmlVersion;
 
2716
                }
 
2717
            }
 
2718
            return null;
 
2719
        }
 
2720
        
 
2721
        /** Returns whether the encoding of this entity was externally specified. **/
 
2722
        public boolean isEncodingExternallySpecified() {
 
2723
            return externallySpecifiedEncoding;
 
2724
        }
 
2725
        
 
2726
        /** Sets whether the encoding of this entity was externally specified. **/
 
2727
        public void setEncodingExternallySpecified(boolean value) {
 
2728
            externallySpecifiedEncoding = value;
 
2729
        }
 
2730
        
2474
2731
        //
2475
2732
        // Object methods
2476
2733
        //
2477
 
 
 
2734
        
2478
2735
        /** Returns a string representation of this object. */
2479
2736
        public String toString() {
2480
 
 
 
2737
            
2481
2738
            StringBuffer str = new StringBuffer();
2482
 
            str.append("name=\""+name+'"');
 
2739
            str.append("name=\"").append(name).append('"');
2483
2740
            str.append(",ch=");
2484
2741
            str.append(ch);
2485
 
            str.append(",position="+position);
2486
 
            str.append(",count="+count);
 
2742
            str.append(",position=").append(position);
 
2743
            str.append(",count=").append(count);
 
2744
            str.append(",baseCharOffset=").append(baseCharOffset);
 
2745
            str.append(",startPosition=").append(startPosition);
2487
2746
            return str.toString();
2488
 
 
 
2747
            
2489
2748
        } // toString():String
2490
 
                
2491
 
                public boolean isDeclaredEncoding() {
2492
 
                        return declaredEncoding;
2493
 
                }
2494
 
                
2495
 
                public void setDeclaredEncoding(boolean value) {
2496
 
                        declaredEncoding = value;
2497
 
                }
2498
2749
 
2499
2750
    } // class ScannedEntity
2500
 
 
2501
 
    // This class wraps the byte inputstreams we're presented with.
2502
 
    // We need it because java.io.InputStreams don't provide
2503
 
    // functionality to reread processed bytes, and they have a habit
2504
 
    // of reading more than one character when you call their read()
2505
 
    // methods.  This means that, once we discover the true (declared)
2506
 
    // encoding of a document, we can neither backtrack to read the
2507
 
    // whole doc again nor start reading where we are with a new
2508
 
    // reader.
2509
 
    //
2510
 
    // This class allows rewinding an inputStream by allowing a mark
2511
 
    // to be set, and the stream reset to that position.  <strong>The
2512
 
    // class assumes that it needs to read one character per
2513
 
    // invocation when it's read() method is inovked, but uses the
2514
 
    // underlying InputStream's read(char[], offset length) method--it
2515
 
    // won't buffer data read this way!</strong>
2516
 
    //
2517
 
    // @author Neil Graham, IBM
2518
 
    // @author Glenn Marcy, IBM
2519
 
 
 
2751
    
 
2752
    /**
 
2753
     * Pool of byte buffers for the java.io.Readers.
 
2754
     * 
 
2755
     * @xerces.internal
 
2756
     * 
 
2757
     * @author Michael Glavassevich, IBM
 
2758
     */
 
2759
    private static final class ByteBufferPool {
 
2760
        
 
2761
        private static final int DEFAULT_POOL_SIZE = 3;
 
2762
        
 
2763
        private int fPoolSize;
 
2764
        private int fBufferSize;
 
2765
        private byte[][] fByteBufferPool;
 
2766
        private int fDepth;
 
2767
        
 
2768
        public ByteBufferPool(int bufferSize) {
 
2769
            this(DEFAULT_POOL_SIZE, bufferSize);
 
2770
        }
 
2771
        
 
2772
        public ByteBufferPool(int poolSize, int bufferSize) {
 
2773
            fPoolSize = poolSize;
 
2774
            fBufferSize = bufferSize;
 
2775
            fByteBufferPool = new byte[fPoolSize][];
 
2776
            fDepth = 0;
 
2777
        }
 
2778
        
 
2779
        /** Retrieves a byte buffer from the pool. **/
 
2780
        public byte[] getBuffer() {
 
2781
            return (fDepth > 0) ? fByteBufferPool[--fDepth] : new byte[fBufferSize];
 
2782
        }
 
2783
        
 
2784
        /** Returns byte buffer to pool. **/
 
2785
        public void returnBuffer(byte[] buffer) {
 
2786
            if (fDepth < fByteBufferPool.length) {
 
2787
                fByteBufferPool[fDepth++] = buffer;
 
2788
            }
 
2789
        }
 
2790
 
 
2791
        /** Sets the size of the buffers and dumps the old pool. **/
 
2792
        public void setBufferSize(int bufferSize) {
 
2793
            fBufferSize = bufferSize;
 
2794
            fByteBufferPool = new byte[fPoolSize][];
 
2795
            fDepth = 0;
 
2796
        } 
 
2797
    }
 
2798
    
 
2799
    /**
 
2800
     * Buffer used in entity manager to reuse character arrays instead
 
2801
     * of creating new ones every time.
 
2802
     * 
 
2803
     * @xerces.internal
 
2804
     * 
 
2805
     * @author Ankit Pasricha, IBM
 
2806
     */
 
2807
    private static final class CharacterBuffer {
 
2808
 
 
2809
        /** character buffer */
 
2810
        private char[] ch;
 
2811
        
 
2812
        /** whether the buffer is for an external or internal scanned entity */
 
2813
        private boolean isExternal;
 
2814
        
 
2815
        public CharacterBuffer(boolean isExternal, int size) {
 
2816
            this.isExternal = isExternal;
 
2817
            ch = new char[size];
 
2818
        }
 
2819
    }
 
2820
    
 
2821
    /**
 
2822
     * Stores a number of character buffers and provides it to the entity
 
2823
     * manager to use when an entity is seen.
 
2824
     * 
 
2825
     * @xerces.internal 
 
2826
     * 
 
2827
     * @author Ankit Pasricha, IBM
 
2828
     */
 
2829
    private static final class CharacterBufferPool {
 
2830
 
 
2831
        private static final int DEFAULT_POOL_SIZE = 3;
 
2832
        
 
2833
        private CharacterBuffer[] fInternalBufferPool;
 
2834
        private CharacterBuffer[] fExternalBufferPool;
 
2835
 
 
2836
        private int fExternalBufferSize;
 
2837
        private int fInternalBufferSize;
 
2838
        private int fPoolSize;
 
2839
        
 
2840
        private int fInternalTop;
 
2841
        private int fExternalTop;
 
2842
 
 
2843
        public CharacterBufferPool(int externalBufferSize, int internalBufferSize) {
 
2844
            this(DEFAULT_POOL_SIZE, externalBufferSize, internalBufferSize);
 
2845
        }
 
2846
        
 
2847
        public CharacterBufferPool(int poolSize, int externalBufferSize, int internalBufferSize) {
 
2848
            fExternalBufferSize = externalBufferSize;
 
2849
            fInternalBufferSize = internalBufferSize;
 
2850
            fPoolSize = poolSize;
 
2851
            init();
 
2852
        }
 
2853
        
 
2854
        /** Initializes buffer pool. **/
 
2855
        private void init() {
 
2856
            fInternalBufferPool = new CharacterBuffer[fPoolSize];
 
2857
            fExternalBufferPool = new CharacterBuffer[fPoolSize];
 
2858
            fInternalTop = -1;
 
2859
            fExternalTop = -1;
 
2860
        }
 
2861
 
 
2862
        /** Retrieves buffer from pool. **/
 
2863
        public CharacterBuffer getBuffer(boolean external) {
 
2864
            if (external) {
 
2865
                if (fExternalTop > -1) {
 
2866
                    return (CharacterBuffer)fExternalBufferPool[fExternalTop--];
 
2867
                }
 
2868
                else {
 
2869
                    return new CharacterBuffer(true, fExternalBufferSize);
 
2870
                }
 
2871
            }
 
2872
            else {
 
2873
                if (fInternalTop > -1) {
 
2874
                    return (CharacterBuffer)fInternalBufferPool[fInternalTop--];
 
2875
                }
 
2876
                else {
 
2877
                    return new CharacterBuffer(false, fInternalBufferSize);
 
2878
                }
 
2879
            }
 
2880
        }
 
2881
        
 
2882
        /** Returns buffer to pool. **/
 
2883
        public void returnBuffer(CharacterBuffer buffer) {
 
2884
            if (buffer.isExternal) {
 
2885
                if (fExternalTop < fExternalBufferPool.length - 1) {
 
2886
                    fExternalBufferPool[++fExternalTop] = buffer;
 
2887
                }
 
2888
            }
 
2889
            else if (fInternalTop < fInternalBufferPool.length - 1) {
 
2890
                fInternalBufferPool[++fInternalTop] = buffer;
 
2891
            }
 
2892
        }
 
2893
 
 
2894
        /** Sets the size of external buffers and dumps the old pool. **/
 
2895
        public void setExternalBufferSize(int bufferSize) {
 
2896
            fExternalBufferSize = bufferSize;
 
2897
            fExternalBufferPool = new CharacterBuffer[fPoolSize];
 
2898
            fExternalTop = -1;
 
2899
        }
 
2900
    }
 
2901
 
 
2902
    /**
 
2903
     * This class wraps the byte inputstreams we're presented with.
 
2904
     * We need it because java.io.InputStreams don't provide
 
2905
     * functionality to reread processed bytes, and they have a habit
 
2906
     * of reading more than one character when you call their read()
 
2907
     * methods.  This means that, once we discover the true (declared)
 
2908
     * encoding of a document, we can neither backtrack to read the
 
2909
     * whole doc again nor start reading where we are with a new
 
2910
     * reader.
 
2911
     *
 
2912
     * This class allows rewinding an inputStream by allowing a mark
 
2913
     * to be set, and the stream reset to that position.  <strong>The
 
2914
     * class assumes that it needs to read one character per
 
2915
     * invocation when it's read() method is inovked, but uses the
 
2916
     * underlying InputStream's read(char[], offset length) method--it
 
2917
     * won't buffer data read this way!</strong>
 
2918
     *
 
2919
     * @xerces.internal
 
2920
     *  
 
2921
     * @author Neil Graham, IBM
 
2922
     * @author Glenn Marcy, IBM
 
2923
     */
2520
2924
    protected final class RewindableInputStream extends InputStream {
2521
2925
 
2522
2926
        private InputStream fInputStream;