My favorites | Sign in
Project Home Downloads Wiki Issues Source
Checkout   Browse   Changes    
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
/*
* Copyright 2008 Android4ME
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android4me.res;

import java.io.IOException;
import java.io.InputStream;

/**
* @author Dmitry Skiba
*
* Parser for Android's binary xml files (axml).
*
* TODO:
* * understand ? values
*/
public final class AXMLParser {

/**
* Types of returned tags.
* Values are compatible to those in XmlPullParser.
*/
public static final int
START_DOCUMENT =0,
END_DOCUMENT =1,
START_TAG =2,
END_TAG =3,
TEXT =4;

/**
* Creates object and reads file info.
* Call next() to read first tag.
*/
public AXMLParser(InputStream stream) throws IOException {
m_stream=stream;
doStart();
}

/**
* Closes parser:
* * closes (and nulls) underlying stream
* * nulls dynamic data
* * moves object to 'closed' state, where methods
* return invalid values and next() throws IOException.
*/
public final void close() {
if (m_stream==null) {
return;
}
try {
m_stream.close();
}
catch (IOException e) {
}
if (m_nextException==null) {
m_nextException=new IOException("Closed.");
}
m_stream=null;
resetState();
}

/**
* Advances to the next tag.
* Once method returns END_DOCUMENT, it always returns END_DOCUMENT.
* Once method throws an exception, it always throws the same exception.
*
*/
public final int next() throws IOException {
if (m_nextException!=null) {
throw m_nextException;
}
try {
return doNext();
}
catch (IOException e) {
m_nextException=e;
resetState();
throw e;
}
}

/**
* Returns current tag type.
*/
public final int getType() {
return m_tagType;
}

/**
* Returns name for the current tag.
*/
public final String getName() {
if (m_tagName==-1) {
return null;
}
return getString(m_tagName);
}

/**
* Returns line number in the original XML where the current tag was.
*/
public final int getLineNumber() {
return m_tagSourceLine;
}

/**
* Returns count of attributes for the current tag.
*/
public final int getAttributeCount() {
if (m_tagAttributes==null) {
return -1;
}
return m_tagAttributes.length;
}

/**
* Returns attribute namespace.
*/
public final String getAttributeNamespace(int index) {
return getString(getAttribute(index).namespace);
}

/**
* Returns attribute name.
*/
public final String getAttributeName(int index) {
return getString(getAttribute(index).name);
}

/**
* Returns attribute resource ID.
*/
public final int getAttributeResourceID(int index) {
int resourceIndex=getAttribute(index).name;
if (m_resourceIDs==null ||
resourceIndex<0 || resourceIndex>=m_resourceIDs.length)
{
return 0;
}
return m_resourceIDs[resourceIndex];
}

/**
* Returns type of attribute value.
* See TypedValue.TYPE_ values.
*/
public final int getAttributeValueType(int index) {
return getAttribute(index).valueType;
}

/**
* For attributes of type TypedValue.TYPE_STRING returns
* string value. For other types returns empty string.
*/
public final String getAttributeValueString(int index) {
return getString(getAttribute(index).valueString);
}

/**
* Returns integer attribute value.
* This integer interpreted according to attribute type.
*/
public final int getAttributeValue(int index) {
return getAttribute(index).value;
}

///////////////////////////////////////////// implementation

private static final class TagAttribute {
public int namespace;
public int name;
public int valueString;
public int valueType;
public int value;
}

private final void resetState() {
m_tagType=-1;
m_tagSourceLine=-1;
m_tagName=-1;
m_tagAttributes=null;
}

private final void doStart() throws IOException {
ReadUtil.readCheckType(m_stream,AXML_CHUNK_TYPE);
/*chunk size*/ReadUtil.readInt(m_stream);

m_strings=StringBlock.read(new IntReader(m_stream,false));

ReadUtil.readCheckType(m_stream,RESOURCEIDS_CHUNK_TYPE);
int chunkSize=ReadUtil.readInt(m_stream);
if (chunkSize<8 || (chunkSize%4)!=0) {
throw new IOException("Invalid resource ids size ("+chunkSize+").");
}
m_resourceIDs=ReadUtil.readIntArray(m_stream,chunkSize/4-2);

resetState();
}

private final int doNext() throws IOException {
if (m_tagType==END_DOCUMENT) {
return END_DOCUMENT;
}

m_tagType=(ReadUtil.readInt(m_stream) & 0xFF);/*other 3 bytes?*/
/*some source length*/ReadUtil.readInt(m_stream);
m_tagSourceLine=ReadUtil.readInt(m_stream);
/*0xFFFFFFFF*/ReadUtil.readInt(m_stream);

m_tagName=-1;
m_tagAttributes=null;

switch (m_tagType) {
case START_DOCUMENT:
{
/*namespace?*/ReadUtil.readInt(m_stream);
/*name?*/ReadUtil.readInt(m_stream);
break;
}
case START_TAG:
{
/*0xFFFFFFFF*/ReadUtil.readInt(m_stream);
m_tagName=ReadUtil.readInt(m_stream);
/*flags?*/ReadUtil.readInt(m_stream);
int attributeCount=ReadUtil.readInt(m_stream);
/*?*/ReadUtil.readInt(m_stream);
m_tagAttributes=new TagAttribute[attributeCount];
for (int i=0;i!=attributeCount;++i) {
TagAttribute attribute=new TagAttribute();
attribute.namespace=ReadUtil.readInt(m_stream);
attribute.name=ReadUtil.readInt(m_stream);
attribute.valueString=ReadUtil.readInt(m_stream);
attribute.valueType=(ReadUtil.readInt(m_stream)>>>24);/*other 3 bytes?*/
attribute.value=ReadUtil.readInt(m_stream);
m_tagAttributes[i]=attribute;
}
break;
}
case END_TAG:
{
/*0xFFFFFFFF*/ReadUtil.readInt(m_stream);
m_tagName=ReadUtil.readInt(m_stream);
break;
}
case TEXT:
{
m_tagName=ReadUtil.readInt(m_stream);
/*?*/ReadUtil.readInt(m_stream);
/*?*/ReadUtil.readInt(m_stream);
break;
}
case END_DOCUMENT:
{
/*namespace?*/ReadUtil.readInt(m_stream);
/*name?*/ReadUtil.readInt(m_stream);
break;
}
default:
{
throw new IOException("Invalid tag type ("+m_tagType+").");
}
}
return m_tagType;
}

private final TagAttribute getAttribute(int index) {
if (m_tagAttributes==null) {
throw new IndexOutOfBoundsException("Attributes are not available.");
}
if (index>=m_tagAttributes.length) {
throw new IndexOutOfBoundsException("Invalid attribute index ("+index+").");
}
return m_tagAttributes[index];
}

private final String getString(int index) {
if (index==-1) {
return "";
}
return m_strings.getRaw(index);
}

/////////////////////////////////// data

private InputStream m_stream;

private StringBlock m_strings;
private int[] m_resourceIDs;

private IOException m_nextException;

private int m_tagType;
private int m_tagSourceLine;
private int m_tagName;
private TagAttribute[] m_tagAttributes;

private static final int
AXML_CHUNK_TYPE =0x00080003,
RESOURCEIDS_CHUNK_TYPE =0x00080180;
}

Change log

r28 by Dmitry.Skiba on Sep 20, 2008   Diff
work goes on
Go to: 
Project members, sign in to write a code review

Older revisions

r20 by Dmitry.Skiba on Aug 27, 2008   Diff
[No log message]
r19 by Dmitry.Skiba on Aug 26, 2008   Diff
initial android4me.res commit
All revisions of this file

File info

Size: 7694 bytes, 312 lines
Powered by Google Project Hosting