1 /* Woodstox XML processor
2  *
3  * Copyright (c) 2004 Tatu Saloranta, tatu.saloranta@iki.fi
4  *
5  * Licensed under the License specified in file LICENSE, included with
6  * the source code.
7  * You may not use this file except in compliance with the License.
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */

15
16 package com.ctc.wstx.io;
17
18 import java.io.Serializable;
19
20 import javax.xml.stream.Location;
21
22 import org.codehaus.stax2.XMLStreamLocation2;
23
24 import com.ctc.wstx.util.StringUtil;
25
26 /**
27  * Basic implementation of {@link Location}, used by Wstx readers.
28  */

29 public class WstxInputLocation
30     implements Serializable, XMLStreamLocation2
31 {
32     private static final long serialVersionUID = 1L;
33
34     private final static WstxInputLocation sEmptyLocation
35         = new WstxInputLocation(null"""", -1, -1, -1);
36
37     /**
38      * Enclosing (parent) input location; location from which current
39      * location is derived.
40      */

41     final protected WstxInputLocation mContext;
42
43     final protected String mPublicId, mSystemId;
44     
45     final protected long mCharOffset;
46     final protected int mCol, mRow;
47
48     transient protected String mDesc = null;
49
50     /**
51      * @param ctxt Enclosing input location, if any
52      */

53     public WstxInputLocation(WstxInputLocation ctxt,
54             String pubId, String sysId,
55             long charOffset, int row, int col)
56     {
57         mContext = ctxt;
58         mPublicId = pubId;
59         mSystemId = sysId;
60         /* Overflow? Can obviously only handle limited range of overflows,
61          * but let's do that at least?
62          */

63         mCharOffset = charOffset;
64         mCol = col;
65         mRow = row;
66     }
67
68     public WstxInputLocation(WstxInputLocation ctxt,
69             String pubId, SystemId sysId, long charOffset, int row, int col)
70     {
71         mContext = ctxt;
72         mPublicId = pubId;
73         mSystemId = (sysId == null) ? "N/A" : sysId.toString();
74         mCharOffset = charOffset;
75         mCol = col;
76         mRow = row;
77     }
78     
79     public static WstxInputLocation getEmptyLocation() {
80         return sEmptyLocation;
81     }
82     
83     public long getCharacterOffsetLong() { return mCharOffset; }
84
85     @Override
86     public int getCharacterOffset() { return (int)mCharOffset; }
87     @Override
88     public int getColumnNumber() { return mCol; }
89     @Override
90     public int getLineNumber() { return mRow; }
91     
92     @Override
93     public String getPublicId() { return mPublicId; }
94     @Override
95     public String getSystemId() { return mSystemId; }
96
97     /*
98     ////////////////////////////////////////////////////////
99     // StAX 2 API:
100     ////////////////////////////////////////////////////////
101      */

102
103     @Override
104     public XMLStreamLocation2 getContext() { return mContext; }
105
106     /*
107     ////////////////////////////////////////////////////////
108     // Overridden standard methods
109     ////////////////////////////////////////////////////////
110      */

111     
112     @Override
113     public String toString()
114     {
115         if (mDesc == null) {
116             StringBuilder sb;
117             if (mContext != null) {
118                 sb = new StringBuilder(200);
119             } else {
120                 sb = new StringBuilder(80);
121             }
122             appendDesc(sb);
123             mDesc = sb.toString();
124         }
125         return mDesc;
126     }
127     
128     @Override
129     public int hashCode() {
130         return ((int)mCharOffset) ^ (int)(0xffffffff & mCharOffset >> 32) ^ mRow ^ mCol + (mCol << 3);
131     }
132     
133     @Override
134     public boolean equals(Object o) {
135         if (!(o instanceof WstxInputLocation)) {
136             return false;
137         }
138         WstxInputLocation other = (WstxInputLocation) o;
139         // char offset should be good enough, without row/col:
140         if (other.getCharacterOffsetLong() != getCharacterOffsetLong()) {
141             return false;
142         }
143         String otherPub = other.getPublicId();
144         if (otherPub == null) {
145             otherPub = "";
146         }
147         if (!otherPub.equals(mPublicId)) {
148             return false;
149         }
150         String otherSys = other.getSystemId();
151         if (otherSys == null) {
152             otherSys = "";
153         }
154         return otherSys.equals(mSystemId);
155     }
156
157     /*
158     ////////////////////////////////////////////////////////
159     // Internal methods:
160     ////////////////////////////////////////////////////////
161      */

162
163     private void appendDesc(StringBuilder sb)
164     {
165         String srcId;
166
167         if (mSystemId != null) {
168             sb.append("[row,col,system-id]: ");
169             srcId = mSystemId;
170         } else if (mPublicId != null) {
171             sb.append("[row,col,public-id]: ");
172             srcId = mPublicId;
173         } else {
174             sb.append("[row,col {unknown-source}]: ");
175             srcId = null;
176         }
177         sb.append('[');
178         sb.append(mRow);
179         sb.append(',');
180         sb.append(mCol);
181
182         // Uncomment for testing, to see the char offset:
183         //sb.append(" #").append(mCharOffset);
184         //sb.append("{").append(System.identityHashCode(this)).append("}");
185
186         if (srcId != null) {
187             sb.append(',');
188             sb.append('"');
189             sb.append(srcId);
190             sb.append('"');
191         }
192         sb.append(']');
193         if (mContext != null) {
194             StringUtil.appendLF(sb);
195             sb.append(" from ");
196             mContext.appendDesc(sb);
197         }
198     }
199 }
200