Fixing Manifest Parsing - Shifting from axmlprinter to axmlparser (#180)
**Description:** Some apps were failing with reason `Failed to parse Manifest file` Turns out that `AxmlResourceParser` from `android4Me` is very outdated and does not work well in all cases. Hence have removed `axmlprinter` and migrated code to use `AxmlParser` from `ManifestEditor` by `WindySha`.
This commit is contained in:
parent
7cf2178381
commit
5d8645d201
|
|
@ -1 +0,0 @@
|
|||
/build
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
val androidSourceCompatibility: JavaVersion by rootProject.extra
|
||||
val androidTargetCompatibility: JavaVersion by rootProject.extra
|
||||
|
||||
description = "android manifest content parser"
|
||||
|
||||
plugins {
|
||||
id("java-library")
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = androidSourceCompatibility
|
||||
targetCompatibility = androidTargetCompatibility
|
||||
}
|
||||
|
|
@ -1,932 +0,0 @@
|
|||
/*
|
||||
* 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 wind.android.content.res;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import wind.v1.XmlPullParserException;
|
||||
|
||||
import wind.android.content.res.ChunkUtil;
|
||||
import wind.android.content.res.IntReader;
|
||||
import wind.android.content.res.StringBlock;
|
||||
import wind.android.content.res.XmlResourceParser;
|
||||
import wind.android.util.TypedValue;
|
||||
|
||||
/**
|
||||
* @author Dmitry Skiba
|
||||
*
|
||||
* Binary xml files parser.
|
||||
*
|
||||
* Parser has only two states:
|
||||
* (1) Operational state, which parser obtains after first successful call
|
||||
* to next() and retains until open(), close(), or failed call to next().
|
||||
* (2) Closed state, which parser obtains after open(), close(), or failed
|
||||
* call to next(). In this state methods return invalid values or throw exceptions.
|
||||
*
|
||||
* TODO:
|
||||
* * check all methods in closed state
|
||||
*
|
||||
*/
|
||||
public class AXmlResourceParser implements XmlResourceParser {
|
||||
|
||||
public AXmlResourceParser() {
|
||||
resetEventInfo();
|
||||
}
|
||||
|
||||
public void open(InputStream stream) {
|
||||
close();
|
||||
if (stream!=null) {
|
||||
m_reader=new wind.android.content.res.IntReader(stream,false);
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (!m_operational) {
|
||||
return;
|
||||
}
|
||||
m_operational=false;
|
||||
m_reader.close();
|
||||
m_reader=null;
|
||||
m_strings=null;
|
||||
m_resourceIDs=null;
|
||||
m_namespaces.reset();
|
||||
resetEventInfo();
|
||||
}
|
||||
|
||||
/////////////////////////////////// iteration
|
||||
|
||||
public int next() throws XmlPullParserException,IOException {
|
||||
if (m_reader==null) {
|
||||
throw new XmlPullParserException("Parser is not opened.",this,null);
|
||||
}
|
||||
try {
|
||||
doNext();
|
||||
return m_event;
|
||||
}
|
||||
catch (IOException e) {
|
||||
close();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public int nextToken() throws XmlPullParserException,IOException {
|
||||
return next();
|
||||
}
|
||||
|
||||
public int nextTag() throws XmlPullParserException,IOException {
|
||||
int eventType=next();
|
||||
if (eventType==TEXT && isWhitespace()) {
|
||||
eventType=next();
|
||||
}
|
||||
if (eventType!=START_TAG && eventType!=END_TAG) {
|
||||
throw new XmlPullParserException("Expected start or end tag.",this,null);
|
||||
}
|
||||
return eventType;
|
||||
}
|
||||
|
||||
public String nextText() throws XmlPullParserException,IOException {
|
||||
if(getEventType()!=START_TAG) {
|
||||
throw new XmlPullParserException("Parser must be on START_TAG to read next text.",this,null);
|
||||
}
|
||||
int eventType=next();
|
||||
if (eventType==TEXT) {
|
||||
String result=getText();
|
||||
eventType=next();
|
||||
if (eventType!=END_TAG) {
|
||||
throw new XmlPullParserException("Event TEXT must be immediately followed by END_TAG.",this,null);
|
||||
}
|
||||
return result;
|
||||
} else if (eventType==END_TAG) {
|
||||
return "";
|
||||
} else {
|
||||
throw new XmlPullParserException("Parser must be on START_TAG or TEXT to read text.",this,null);
|
||||
}
|
||||
}
|
||||
|
||||
public void require(int type,String namespace,String name) throws XmlPullParserException,IOException {
|
||||
if (type!=getEventType() ||
|
||||
(namespace!=null && !namespace.equals(getNamespace())) ||
|
||||
(name!=null && !name.equals(getName())))
|
||||
{
|
||||
throw new XmlPullParserException(TYPES[type]+" is expected.",this,null);
|
||||
}
|
||||
}
|
||||
|
||||
public int getDepth() {
|
||||
return m_namespaces.getDepth()-1;
|
||||
}
|
||||
|
||||
public int getEventType() throws XmlPullParserException {
|
||||
return m_event;
|
||||
}
|
||||
|
||||
public int getLineNumber() {
|
||||
return m_lineNumber;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
if (m_name==-1 || (m_event!=START_TAG && m_event!=END_TAG)) {
|
||||
return null;
|
||||
}
|
||||
return m_strings.getString(m_name);
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
if (m_name==-1 || m_event!=TEXT) {
|
||||
return null;
|
||||
}
|
||||
return m_strings.getString(m_name);
|
||||
}
|
||||
|
||||
public char[] getTextCharacters(int[] holderForStartAndLength) {
|
||||
String text=getText();
|
||||
if (text==null) {
|
||||
return null;
|
||||
}
|
||||
holderForStartAndLength[0]=0;
|
||||
holderForStartAndLength[1]=text.length();
|
||||
char[] chars=new char[text.length()];
|
||||
text.getChars(0,text.length(),chars,0);
|
||||
return chars;
|
||||
}
|
||||
|
||||
public String getNamespace() {
|
||||
return m_strings.getString(m_namespaceUri);
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
int prefix=m_namespaces.findPrefix(m_namespaceUri);
|
||||
return m_strings.getString(prefix);
|
||||
}
|
||||
|
||||
public String getPositionDescription() {
|
||||
return "XML line #"+getLineNumber();
|
||||
}
|
||||
|
||||
public int getNamespaceCount(int depth) throws XmlPullParserException {
|
||||
return m_namespaces.getAccumulatedCount(depth);
|
||||
}
|
||||
|
||||
public String getNamespacePrefix(int pos) throws XmlPullParserException {
|
||||
int prefix=m_namespaces.getPrefix(pos);
|
||||
return m_strings.getString(prefix);
|
||||
}
|
||||
|
||||
public String getNamespaceUri(int pos) throws XmlPullParserException {
|
||||
int uri=m_namespaces.getUri(pos);
|
||||
return m_strings.getString(uri);
|
||||
}
|
||||
|
||||
/////////////////////////////////// attributes
|
||||
|
||||
public String getClassAttribute() {
|
||||
if (m_classAttribute==-1) {
|
||||
return null;
|
||||
}
|
||||
int offset=getAttributeOffset(m_classAttribute);
|
||||
int value=m_attributes[offset+ATTRIBUTE_IX_VALUE_STRING];
|
||||
return m_strings.getString(value);
|
||||
}
|
||||
|
||||
public String getIdAttribute() {
|
||||
if (m_idAttribute==-1) {
|
||||
return null;
|
||||
}
|
||||
int offset=getAttributeOffset(m_idAttribute);
|
||||
int value=m_attributes[offset+ATTRIBUTE_IX_VALUE_STRING];
|
||||
return m_strings.getString(value);
|
||||
}
|
||||
|
||||
public int getIdAttributeResourceValue(int defaultValue) {
|
||||
if (m_idAttribute==-1) {
|
||||
return defaultValue;
|
||||
}
|
||||
int offset=getAttributeOffset(m_idAttribute);
|
||||
int valueType=m_attributes[offset+ATTRIBUTE_IX_VALUE_TYPE];
|
||||
if (valueType!=TypedValue.TYPE_REFERENCE) {
|
||||
return defaultValue;
|
||||
}
|
||||
return m_attributes[offset+ATTRIBUTE_IX_VALUE_DATA];
|
||||
}
|
||||
|
||||
public int getStyleAttribute() {
|
||||
if (m_styleAttribute==-1) {
|
||||
return 0;
|
||||
}
|
||||
int offset=getAttributeOffset(m_styleAttribute);
|
||||
return m_attributes[offset+ATTRIBUTE_IX_VALUE_DATA];
|
||||
}
|
||||
|
||||
public int getAttributeCount() {
|
||||
if (m_event!=START_TAG) {
|
||||
return -1;
|
||||
}
|
||||
return m_attributes.length/ATTRIBUTE_LENGHT;
|
||||
}
|
||||
|
||||
public String getAttributeNamespace(int index) {
|
||||
int offset=getAttributeOffset(index);
|
||||
int namespace=m_attributes[offset+ATTRIBUTE_IX_NAMESPACE_URI];
|
||||
if (namespace==-1) {
|
||||
return "";
|
||||
}
|
||||
return m_strings.getString(namespace);
|
||||
}
|
||||
|
||||
public String getAttributePrefix(int index) {
|
||||
int offset=getAttributeOffset(index);
|
||||
int uri=m_attributes[offset+ATTRIBUTE_IX_NAMESPACE_URI];
|
||||
int prefix=m_namespaces.findPrefix(uri);
|
||||
if (prefix==-1) {
|
||||
return "";
|
||||
}
|
||||
return m_strings.getString(prefix);
|
||||
}
|
||||
|
||||
public String getAttributeName(int index) {
|
||||
int offset=getAttributeOffset(index);
|
||||
int name=m_attributes[offset+ATTRIBUTE_IX_NAME];
|
||||
if (name==-1) {
|
||||
return "";
|
||||
}
|
||||
return m_strings.getString(name);
|
||||
}
|
||||
|
||||
public int getAttributeNameResource(int index) {
|
||||
int offset=getAttributeOffset(index);
|
||||
int name=m_attributes[offset+ATTRIBUTE_IX_NAME];
|
||||
if (m_resourceIDs==null ||
|
||||
name<0 || name>=m_resourceIDs.length)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return m_resourceIDs[name];
|
||||
}
|
||||
|
||||
public int getAttributeValueType(int index) {
|
||||
int offset=getAttributeOffset(index);
|
||||
return m_attributes[offset+ATTRIBUTE_IX_VALUE_TYPE];
|
||||
}
|
||||
|
||||
public int getAttributeValueData(int index) {
|
||||
int offset=getAttributeOffset(index);
|
||||
return m_attributes[offset+ATTRIBUTE_IX_VALUE_DATA];
|
||||
}
|
||||
|
||||
public String getAttributeValue(int index) {
|
||||
int offset=getAttributeOffset(index);
|
||||
int valueType=m_attributes[offset+ATTRIBUTE_IX_VALUE_TYPE];
|
||||
if (valueType==TypedValue.TYPE_STRING) {
|
||||
int valueString=m_attributes[offset+ATTRIBUTE_IX_VALUE_STRING];
|
||||
return m_strings.getString(valueString);
|
||||
}
|
||||
int valueData=m_attributes[offset+ATTRIBUTE_IX_VALUE_DATA];
|
||||
return "";//TypedValue.coerceToString(valueType,valueData);
|
||||
}
|
||||
|
||||
public boolean getAttributeBooleanValue(int index,boolean defaultValue) {
|
||||
return getAttributeIntValue(index,defaultValue?1:0)!=0;
|
||||
}
|
||||
|
||||
public float getAttributeFloatValue(int index,float defaultValue) {
|
||||
int offset=getAttributeOffset(index);
|
||||
int valueType=m_attributes[offset+ATTRIBUTE_IX_VALUE_TYPE];
|
||||
if (valueType==TypedValue.TYPE_FLOAT) {
|
||||
int valueData=m_attributes[offset+ATTRIBUTE_IX_VALUE_DATA];
|
||||
return Float.intBitsToFloat(valueData);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public int getAttributeIntValue(int index,int defaultValue) {
|
||||
int offset=getAttributeOffset(index);
|
||||
int valueType=m_attributes[offset+ATTRIBUTE_IX_VALUE_TYPE];
|
||||
if (valueType>=TypedValue.TYPE_FIRST_INT &&
|
||||
valueType<=TypedValue.TYPE_LAST_INT)
|
||||
{
|
||||
return m_attributes[offset+ATTRIBUTE_IX_VALUE_DATA];
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public int getAttributeUnsignedIntValue(int index,int defaultValue) {
|
||||
return getAttributeIntValue(index,defaultValue);
|
||||
}
|
||||
|
||||
public int getAttributeResourceValue(int index,int defaultValue) {
|
||||
int offset=getAttributeOffset(index);
|
||||
int valueType=m_attributes[offset+ATTRIBUTE_IX_VALUE_TYPE];
|
||||
if (valueType==TypedValue.TYPE_REFERENCE) {
|
||||
return m_attributes[offset+ATTRIBUTE_IX_VALUE_DATA];
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public String getAttributeValue(String namespace,String attribute) {
|
||||
int index=findAttribute(namespace,attribute);
|
||||
if (index==-1) {
|
||||
return null;
|
||||
}
|
||||
return getAttributeValue(index);
|
||||
}
|
||||
|
||||
public boolean getAttributeBooleanValue(String namespace,String attribute,boolean defaultValue) {
|
||||
int index=findAttribute(namespace,attribute);
|
||||
if (index==-1) {
|
||||
return defaultValue;
|
||||
}
|
||||
return getAttributeBooleanValue(index,defaultValue);
|
||||
}
|
||||
|
||||
public float getAttributeFloatValue(String namespace,String attribute,float defaultValue) {
|
||||
int index=findAttribute(namespace,attribute);
|
||||
if (index==-1) {
|
||||
return defaultValue;
|
||||
}
|
||||
return getAttributeFloatValue(index,defaultValue);
|
||||
}
|
||||
|
||||
public int getAttributeIntValue(String namespace,String attribute,int defaultValue) {
|
||||
int index=findAttribute(namespace,attribute);
|
||||
if (index==-1) {
|
||||
return defaultValue;
|
||||
}
|
||||
return getAttributeIntValue(index,defaultValue);
|
||||
}
|
||||
|
||||
public int getAttributeUnsignedIntValue(String namespace,String attribute,int defaultValue) {
|
||||
int index=findAttribute(namespace,attribute);
|
||||
if (index==-1) {
|
||||
return defaultValue;
|
||||
}
|
||||
return getAttributeUnsignedIntValue(index,defaultValue);
|
||||
}
|
||||
|
||||
public int getAttributeResourceValue(String namespace,String attribute,int defaultValue) {
|
||||
int index=findAttribute(namespace,attribute);
|
||||
if (index==-1) {
|
||||
return defaultValue;
|
||||
}
|
||||
return getAttributeResourceValue(index,defaultValue);
|
||||
}
|
||||
|
||||
public int getAttributeListValue(int index,String[] options,int defaultValue) {
|
||||
// TODO implement
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getAttributeListValue(String namespace,String attribute,String[] options,int defaultValue) {
|
||||
// TODO implement
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String getAttributeType(int index) {
|
||||
return "CDATA";
|
||||
}
|
||||
|
||||
public boolean isAttributeDefault(int index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/////////////////////////////////// dummies
|
||||
|
||||
public void setInput(InputStream stream,String inputEncoding) throws XmlPullParserException {
|
||||
throw new XmlPullParserException(E_NOT_SUPPORTED);
|
||||
}
|
||||
public void setInput(Reader reader) throws XmlPullParserException {
|
||||
throw new XmlPullParserException(E_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
public String getInputEncoding() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getColumnNumber() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public boolean isEmptyElementTag() throws XmlPullParserException {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isWhitespace() throws XmlPullParserException {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void defineEntityReplacementText(String entityName,String replacementText) throws XmlPullParserException {
|
||||
throw new XmlPullParserException(E_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
public String getNamespace(String prefix) {
|
||||
throw new RuntimeException(E_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
public Object getProperty(String name) {
|
||||
return null;
|
||||
}
|
||||
public void setProperty(String name,Object value) throws XmlPullParserException {
|
||||
throw new XmlPullParserException(E_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
public boolean getFeature(String feature) {
|
||||
return false;
|
||||
}
|
||||
public void setFeature(String name,boolean value) throws XmlPullParserException {
|
||||
throw new XmlPullParserException(E_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////// implementation
|
||||
|
||||
/**
|
||||
* Namespace stack, holds prefix+uri pairs, as well as
|
||||
* depth information.
|
||||
* All information is stored in one int[] array.
|
||||
* Array consists of depth frames:
|
||||
* Data=DepthFrame*;
|
||||
* DepthFrame=Count+[Prefix+Uri]*+Count;
|
||||
* Count='count of Prefix+Uri pairs';
|
||||
* Yes, count is stored twice, to enable bottom-up traversal.
|
||||
* increaseDepth adds depth frame, decreaseDepth removes it.
|
||||
* push/pop operations operate only in current depth frame.
|
||||
* decreaseDepth removes any remaining (not pop'ed) namespace pairs.
|
||||
* findXXX methods search all depth frames starting
|
||||
* from the last namespace pair of current depth frame.
|
||||
* All functions that operate with int, use -1 as 'invalid value'.
|
||||
*
|
||||
* !! functions expect 'prefix'+'uri' pairs, not 'uri'+'prefix' !!
|
||||
*
|
||||
*/
|
||||
private static final class NamespaceStack {
|
||||
public NamespaceStack() {
|
||||
m_data=new int[32];
|
||||
}
|
||||
|
||||
public final void reset() {
|
||||
m_dataLength=0;
|
||||
m_count=0;
|
||||
m_depth=0;
|
||||
}
|
||||
|
||||
public final int getTotalCount() {
|
||||
return m_count;
|
||||
}
|
||||
|
||||
public final int getCurrentCount() {
|
||||
if (m_dataLength==0) {
|
||||
return 0;
|
||||
}
|
||||
int offset=m_dataLength-1;
|
||||
return m_data[offset];
|
||||
}
|
||||
|
||||
public final int getAccumulatedCount(int depth) {
|
||||
if (m_dataLength==0 || depth<0) {
|
||||
return 0;
|
||||
}
|
||||
if (depth>m_depth) {
|
||||
depth=m_depth;
|
||||
}
|
||||
int accumulatedCount=0;
|
||||
int offset=0;
|
||||
for (;depth!=0;--depth) {
|
||||
int count=m_data[offset];
|
||||
accumulatedCount+=count;
|
||||
offset+=(2+count*2);
|
||||
}
|
||||
return accumulatedCount;
|
||||
}
|
||||
|
||||
public final void push(int prefix,int uri) {
|
||||
if (m_depth==0) {
|
||||
increaseDepth();
|
||||
}
|
||||
ensureDataCapacity(2);
|
||||
int offset=m_dataLength-1;
|
||||
int count=m_data[offset];
|
||||
m_data[offset-1-count*2]=count+1;
|
||||
m_data[offset]=prefix;
|
||||
m_data[offset+1]=uri;
|
||||
m_data[offset+2]=count+1;
|
||||
m_dataLength+=2;
|
||||
m_count+=1;
|
||||
}
|
||||
|
||||
public final boolean pop(int prefix,int uri) {
|
||||
if (m_dataLength==0) {
|
||||
return false;
|
||||
}
|
||||
int offset=m_dataLength-1;
|
||||
int count=m_data[offset];
|
||||
for (int i=0,o=offset-2;i!=count;++i,o-=2) {
|
||||
if (m_data[o]!=prefix || m_data[o+1]!=uri) {
|
||||
continue;
|
||||
}
|
||||
count-=1;
|
||||
if (i==0) {
|
||||
m_data[o]=count;
|
||||
o-=(1+count*2);
|
||||
m_data[o]=count;
|
||||
} else {
|
||||
m_data[offset]=count;
|
||||
offset-=(1+2+count*2);
|
||||
m_data[offset]=count;
|
||||
System.arraycopy(
|
||||
m_data,o+2,
|
||||
m_data,o,
|
||||
m_dataLength-o);
|
||||
}
|
||||
m_dataLength-=2;
|
||||
m_count-=1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public final boolean pop() {
|
||||
if (m_dataLength==0) {
|
||||
return false;
|
||||
}
|
||||
int offset=m_dataLength-1;
|
||||
int count=m_data[offset];
|
||||
if (count==0) {
|
||||
return false;
|
||||
}
|
||||
count-=1;
|
||||
offset-=2;
|
||||
m_data[offset]=count;
|
||||
offset-=(1+count*2);
|
||||
m_data[offset]=count;
|
||||
m_dataLength-=2;
|
||||
m_count-=1;
|
||||
return true;
|
||||
}
|
||||
|
||||
public final int getPrefix(int index) {
|
||||
return get(index,true);
|
||||
}
|
||||
|
||||
public final int getUri(int index) {
|
||||
return get(index,false);
|
||||
}
|
||||
|
||||
public final int findPrefix(int uri) {
|
||||
return find(uri,false);
|
||||
}
|
||||
|
||||
public final int findUri(int prefix) {
|
||||
return find(prefix,true);
|
||||
}
|
||||
|
||||
public final int getDepth() {
|
||||
return m_depth;
|
||||
}
|
||||
|
||||
public final void increaseDepth() {
|
||||
ensureDataCapacity(2);
|
||||
int offset=m_dataLength;
|
||||
m_data[offset]=0;
|
||||
m_data[offset+1]=0;
|
||||
m_dataLength+=2;
|
||||
m_depth+=1;
|
||||
}
|
||||
public final void decreaseDepth() {
|
||||
if (m_dataLength==0) {
|
||||
return;
|
||||
}
|
||||
int offset=m_dataLength-1;
|
||||
int count=m_data[offset];
|
||||
if ((offset-1-count*2)==0) {
|
||||
return;
|
||||
}
|
||||
m_dataLength-=2+count*2;
|
||||
m_count-=count;
|
||||
m_depth-=1;
|
||||
}
|
||||
|
||||
private void ensureDataCapacity(int capacity) {
|
||||
int available=(m_data.length-m_dataLength);
|
||||
if (available>capacity) {
|
||||
return;
|
||||
}
|
||||
int newLength=(m_data.length+available)*2;
|
||||
int[] newData=new int[newLength];
|
||||
System.arraycopy(m_data,0,newData,0,m_dataLength);
|
||||
m_data=newData;
|
||||
}
|
||||
|
||||
private final int find(int prefixOrUri,boolean prefix) {
|
||||
if (m_dataLength==0) {
|
||||
return -1;
|
||||
}
|
||||
int offset=m_dataLength-1;
|
||||
for (int i=m_depth;i!=0;--i) {
|
||||
int count=m_data[offset];
|
||||
offset-=2;
|
||||
for (;count!=0;--count) {
|
||||
if (prefix) {
|
||||
if (m_data[offset]==prefixOrUri) {
|
||||
return m_data[offset+1];
|
||||
}
|
||||
} else {
|
||||
if (m_data[offset+1]==prefixOrUri) {
|
||||
return m_data[offset];
|
||||
}
|
||||
}
|
||||
offset-=2;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private final int get(int index,boolean prefix) {
|
||||
if (m_dataLength==0 || index<0) {
|
||||
return -1;
|
||||
}
|
||||
int offset=0;
|
||||
for (int i=m_depth;i!=0;--i) {
|
||||
int count=m_data[offset];
|
||||
if (index>=count) {
|
||||
index-=count;
|
||||
offset+=(2+count*2);
|
||||
continue;
|
||||
}
|
||||
offset+=(1+index*2);
|
||||
if (!prefix) {
|
||||
offset+=1;
|
||||
}
|
||||
return m_data[offset];
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private int[] m_data;
|
||||
private int m_dataLength;
|
||||
private int m_count;
|
||||
private int m_depth;
|
||||
}
|
||||
|
||||
/////////////////////////////////// package-visible
|
||||
|
||||
// final void fetchAttributes(int[] styleableIDs,TypedArray result) {
|
||||
// result.resetIndices();
|
||||
// if (m_attributes==null || m_resourceIDs==null) {
|
||||
// return;
|
||||
// }
|
||||
// boolean needStrings=false;
|
||||
// for (int i=0,e=styleableIDs.length;i!=e;++i) {
|
||||
// int id=styleableIDs[i];
|
||||
// for (int o=0;o!=m_attributes.length;o+=ATTRIBUTE_LENGHT) {
|
||||
// int name=m_attributes[o+ATTRIBUTE_IX_NAME];
|
||||
// if (name>=m_resourceIDs.length ||
|
||||
// m_resourceIDs[name]!=id)
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
// int valueType=m_attributes[o+ATTRIBUTE_IX_VALUE_TYPE];
|
||||
// int valueData;
|
||||
// int assetCookie;
|
||||
// if (valueType==TypedValue.TYPE_STRING) {
|
||||
// valueData=m_attributes[o+ATTRIBUTE_IX_VALUE_STRING];
|
||||
// assetCookie=-1;
|
||||
// needStrings=true;
|
||||
// } else {
|
||||
// valueData=m_attributes[o+ATTRIBUTE_IX_VALUE_DATA];
|
||||
// assetCookie=0;
|
||||
// }
|
||||
// result.addValue(i,valueType,valueData,assetCookie,id,0);
|
||||
// }
|
||||
// }
|
||||
// if (needStrings) {
|
||||
// result.setStrings(m_strings);
|
||||
// }
|
||||
// }
|
||||
|
||||
final wind.android.content.res.StringBlock getStrings() {
|
||||
return m_strings;
|
||||
}
|
||||
|
||||
///////////////////////////////////
|
||||
|
||||
private final int getAttributeOffset(int index) {
|
||||
if (m_event!=START_TAG) {
|
||||
throw new IndexOutOfBoundsException("Current event is not START_TAG.");
|
||||
}
|
||||
int offset=index*5;
|
||||
if (offset>=m_attributes.length) {
|
||||
throw new IndexOutOfBoundsException("Invalid attribute index ("+index+").");
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
private final int findAttribute(String namespace,String attribute) {
|
||||
if (m_strings==null || attribute==null) {
|
||||
return -1;
|
||||
}
|
||||
int name=m_strings.find(attribute);
|
||||
if (name==-1) {
|
||||
return -1;
|
||||
}
|
||||
int uri=(namespace!=null)?
|
||||
m_strings.find(namespace):
|
||||
-1;
|
||||
for (int o=0;o!=m_attributes.length;++o) {
|
||||
if (name==m_attributes[o+ATTRIBUTE_IX_NAME] &&
|
||||
(uri==-1 || uri==m_attributes[o+ATTRIBUTE_IX_NAMESPACE_URI]))
|
||||
{
|
||||
return o/ATTRIBUTE_LENGHT;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private final void resetEventInfo() {
|
||||
m_event=-1;
|
||||
m_lineNumber=-1;
|
||||
m_name=-1;
|
||||
m_namespaceUri=-1;
|
||||
m_attributes=null;
|
||||
m_idAttribute=-1;
|
||||
m_classAttribute=-1;
|
||||
m_styleAttribute=-1;
|
||||
}
|
||||
|
||||
private final void doNext() throws IOException {
|
||||
// Delayed initialization.
|
||||
if (m_strings==null) {
|
||||
wind.android.content.res.ChunkUtil.readCheckType(m_reader,CHUNK_AXML_FILE);
|
||||
/*chunkSize*/m_reader.skipInt();
|
||||
m_strings= wind.android.content.res.StringBlock.read(m_reader);
|
||||
m_namespaces.increaseDepth();
|
||||
m_operational=true;
|
||||
}
|
||||
|
||||
if (m_event==END_DOCUMENT) {
|
||||
return;
|
||||
}
|
||||
|
||||
int event=m_event;
|
||||
resetEventInfo();
|
||||
|
||||
while (true) {
|
||||
if (m_decreaseDepth) {
|
||||
m_decreaseDepth=false;
|
||||
m_namespaces.decreaseDepth();
|
||||
}
|
||||
|
||||
// Fake END_DOCUMENT event.
|
||||
if (event==END_TAG &&
|
||||
m_namespaces.getDepth()==1 &&
|
||||
m_namespaces.getCurrentCount()==0)
|
||||
{
|
||||
m_event=END_DOCUMENT;
|
||||
break;
|
||||
}
|
||||
|
||||
int chunkType;
|
||||
if (event==START_DOCUMENT) {
|
||||
// Fake event, see CHUNK_XML_START_TAG handler.
|
||||
chunkType=CHUNK_XML_START_TAG;
|
||||
} else {
|
||||
chunkType=m_reader.readInt();
|
||||
}
|
||||
|
||||
if (chunkType==CHUNK_RESOURCEIDS) {
|
||||
int chunkSize=m_reader.readInt();
|
||||
if (chunkSize<8 || (chunkSize%4)!=0) {
|
||||
throw new IOException("Invalid resource ids size ("+chunkSize+").");
|
||||
}
|
||||
m_resourceIDs=m_reader.readIntArray(chunkSize/4-2);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (chunkType<CHUNK_XML_FIRST || chunkType>CHUNK_XML_LAST) {
|
||||
throw new IOException("Invalid chunk type ("+chunkType+").");
|
||||
}
|
||||
|
||||
// Fake START_DOCUMENT event.
|
||||
if (chunkType==CHUNK_XML_START_TAG && event==-1) {
|
||||
m_event=START_DOCUMENT;
|
||||
break;
|
||||
}
|
||||
|
||||
// Common header.
|
||||
/*chunkSize*/m_reader.skipInt();
|
||||
int lineNumber=m_reader.readInt();
|
||||
/*0xFFFFFFFF*/m_reader.skipInt();
|
||||
|
||||
if (chunkType==CHUNK_XML_START_NAMESPACE ||
|
||||
chunkType==CHUNK_XML_END_NAMESPACE)
|
||||
{
|
||||
if (chunkType==CHUNK_XML_START_NAMESPACE) {
|
||||
int prefix=m_reader.readInt();
|
||||
int uri=m_reader.readInt();
|
||||
m_namespaces.push(prefix,uri);
|
||||
} else {
|
||||
/*prefix*/m_reader.skipInt();
|
||||
/*uri*/m_reader.skipInt();
|
||||
m_namespaces.pop();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
m_lineNumber=lineNumber;
|
||||
|
||||
if (chunkType==CHUNK_XML_START_TAG) {
|
||||
m_namespaceUri=m_reader.readInt();
|
||||
m_name=m_reader.readInt();
|
||||
/*flags?*/m_reader.skipInt();
|
||||
int attributeCount=m_reader.readInt();
|
||||
m_idAttribute=(attributeCount>>>16)-1;
|
||||
attributeCount&=0xFFFF;
|
||||
m_classAttribute=m_reader.readInt();
|
||||
m_styleAttribute=(m_classAttribute>>>16)-1;
|
||||
m_classAttribute=(m_classAttribute & 0xFFFF)-1;
|
||||
m_attributes=m_reader.readIntArray(attributeCount*ATTRIBUTE_LENGHT);
|
||||
for (int i=ATTRIBUTE_IX_VALUE_TYPE;i<m_attributes.length;) {
|
||||
m_attributes[i]=(m_attributes[i]>>>24);
|
||||
i+=ATTRIBUTE_LENGHT;
|
||||
}
|
||||
m_namespaces.increaseDepth();
|
||||
m_event=START_TAG;
|
||||
break;
|
||||
}
|
||||
|
||||
if (chunkType==CHUNK_XML_END_TAG) {
|
||||
m_namespaceUri=m_reader.readInt();
|
||||
m_name=m_reader.readInt();
|
||||
m_event=END_TAG;
|
||||
m_decreaseDepth=true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (chunkType==CHUNK_XML_TEXT) {
|
||||
m_name=m_reader.readInt();
|
||||
/*?*/m_reader.skipInt();
|
||||
/*?*/m_reader.skipInt();
|
||||
m_event=TEXT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////// data
|
||||
|
||||
/*
|
||||
* All values are essentially indices, e.g. m_name is
|
||||
* an index of name in m_strings.
|
||||
*/
|
||||
|
||||
private IntReader m_reader;
|
||||
private boolean m_operational=false;
|
||||
|
||||
private StringBlock m_strings;
|
||||
private int[] m_resourceIDs;
|
||||
private NamespaceStack m_namespaces=new NamespaceStack();
|
||||
|
||||
private boolean m_decreaseDepth;
|
||||
|
||||
private int m_event;
|
||||
private int m_lineNumber;
|
||||
private int m_name;
|
||||
private int m_namespaceUri;
|
||||
private int[] m_attributes;
|
||||
private int m_idAttribute;
|
||||
private int m_classAttribute;
|
||||
private int m_styleAttribute;
|
||||
|
||||
private static final String
|
||||
E_NOT_SUPPORTED ="Method is not supported.";
|
||||
|
||||
private static final int
|
||||
ATTRIBUTE_IX_NAMESPACE_URI =0,
|
||||
ATTRIBUTE_IX_NAME =1,
|
||||
ATTRIBUTE_IX_VALUE_STRING =2,
|
||||
ATTRIBUTE_IX_VALUE_TYPE =3,
|
||||
ATTRIBUTE_IX_VALUE_DATA =4,
|
||||
ATTRIBUTE_LENGHT =5;
|
||||
|
||||
private static final int
|
||||
CHUNK_AXML_FILE =0x00080003,
|
||||
CHUNK_RESOURCEIDS =0x00080180,
|
||||
CHUNK_XML_FIRST =0x00100100,
|
||||
CHUNK_XML_START_NAMESPACE =0x00100100,
|
||||
CHUNK_XML_END_NAMESPACE =0x00100101,
|
||||
CHUNK_XML_START_TAG =0x00100102,
|
||||
CHUNK_XML_END_TAG =0x00100103,
|
||||
CHUNK_XML_TEXT =0x00100104,
|
||||
CHUNK_XML_LAST =0x00100104;
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* 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 wind.android.content.res;
|
||||
|
||||
import wind.android.content.res.IntReader;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Dmitry Skiba
|
||||
*
|
||||
*/
|
||||
class ChunkUtil {
|
||||
|
||||
public static final void readCheckType(IntReader reader, int expectedType) throws IOException {
|
||||
int type=reader.readInt();
|
||||
if (type!=expectedType) {
|
||||
throw new IOException(
|
||||
"Expected chunk of type 0x"+Integer.toHexString(expectedType)+
|
||||
", read 0x"+Integer.toHexString(type)+".");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,159 +0,0 @@
|
|||
/*
|
||||
* 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 wind.android.content.res;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* @author Dmitry Skiba
|
||||
*
|
||||
* Simple helper class that allows reading of integers.
|
||||
*
|
||||
* TODO:
|
||||
* * implement buffering
|
||||
*
|
||||
*/
|
||||
public final class IntReader {
|
||||
|
||||
public IntReader() {
|
||||
}
|
||||
public IntReader(InputStream stream,boolean bigEndian) {
|
||||
reset(stream,bigEndian);
|
||||
}
|
||||
|
||||
public final void reset(InputStream stream,boolean bigEndian) {
|
||||
m_stream=stream;
|
||||
m_bigEndian=bigEndian;
|
||||
m_position=0;
|
||||
}
|
||||
|
||||
public final void close() {
|
||||
if (m_stream==null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
m_stream.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
}
|
||||
reset(null,false);
|
||||
}
|
||||
|
||||
public final InputStream getStream() {
|
||||
return m_stream;
|
||||
}
|
||||
|
||||
public final boolean isBigEndian() {
|
||||
return m_bigEndian;
|
||||
}
|
||||
public final void setBigEndian(boolean bigEndian) {
|
||||
m_bigEndian=bigEndian;
|
||||
}
|
||||
|
||||
public final int readByte() throws IOException {
|
||||
return readInt(1);
|
||||
}
|
||||
public final int readShort() throws IOException {
|
||||
return readInt(2);
|
||||
}
|
||||
public final int readInt() throws IOException {
|
||||
return readInt(4);
|
||||
}
|
||||
public final void readFully(byte[] b) throws IOException {
|
||||
new DataInputStream(m_stream).readFully(b);
|
||||
}
|
||||
public final int readInt(int length) throws IOException {
|
||||
if (length<0 || length>4) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
int result=0;
|
||||
if (m_bigEndian) {
|
||||
for (int i=(length-1)*8;i>=0;i-=8) {
|
||||
int b=m_stream.read();
|
||||
if (b==-1) {
|
||||
throw new EOFException();
|
||||
}
|
||||
m_position+=1;
|
||||
result|=(b<<i);
|
||||
}
|
||||
} else {
|
||||
length*=8;
|
||||
for (int i=0;i!=length;i+=8) {
|
||||
int b=m_stream.read();
|
||||
if (b==-1) {
|
||||
throw new EOFException();
|
||||
}
|
||||
m_position+=1;
|
||||
result|=(b<<i);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public final int[] readIntArray(int length) throws IOException {
|
||||
int[] array=new int[length];
|
||||
readIntArray(array,0,length);
|
||||
return array;
|
||||
}
|
||||
|
||||
public final void readIntArray(int[] array,int offset,int length) throws IOException {
|
||||
for (;length>0;length-=1) {
|
||||
array[offset++]=readInt();
|
||||
}
|
||||
}
|
||||
|
||||
public final byte[] readByteArray(int length) throws IOException {
|
||||
byte[] array=new byte[length];
|
||||
int read=m_stream.read(array);
|
||||
m_position+=read;
|
||||
if (read!=length) {
|
||||
throw new EOFException();
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public final void skip(int bytes) throws IOException {
|
||||
if (bytes<=0) {
|
||||
return;
|
||||
}
|
||||
long skipped=m_stream.skip(bytes);
|
||||
m_position+=skipped;
|
||||
if (skipped!=bytes) {
|
||||
throw new EOFException();
|
||||
}
|
||||
}
|
||||
|
||||
public final void skipInt() throws IOException {
|
||||
skip(4);
|
||||
}
|
||||
|
||||
public final int available() throws IOException {
|
||||
return m_stream.available();
|
||||
}
|
||||
|
||||
public final int getPosition() {
|
||||
return m_position;
|
||||
}
|
||||
|
||||
/////////////////////////////////// data
|
||||
|
||||
private InputStream m_stream;
|
||||
private boolean m_bigEndian;
|
||||
private int m_position;
|
||||
}
|
||||
|
|
@ -1,303 +0,0 @@
|
|||
/*
|
||||
* 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 wind.android.content.res;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.CharacterCodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
|
||||
/**
|
||||
* @author Dmitry Skiba
|
||||
*
|
||||
* Block of strings, used in binary xml and arsc.
|
||||
*
|
||||
* TODO:
|
||||
* - implement get()
|
||||
*
|
||||
*/
|
||||
public class StringBlock {
|
||||
|
||||
private int[] m_stringOffsets;
|
||||
private byte[] m_strings;
|
||||
private int[] m_styleOffsets;
|
||||
private int[] m_styles;
|
||||
private boolean m_isUTF8;
|
||||
private static final int CHUNK_TYPE = 0x001C0001;
|
||||
private static final int UTF8_FLAG = 0x00000100;
|
||||
|
||||
private final CharsetDecoder UTF8_DECODER = Charset.forName("UTF-8").newDecoder();
|
||||
private final CharsetDecoder UTF16LE_DECODER = Charset.forName("UTF-16LE").newDecoder();
|
||||
|
||||
/**
|
||||
* Reads whole (including chunk type) string block from stream.
|
||||
* Stream must be at the chunk type.
|
||||
*/
|
||||
public static StringBlock read(IntReader reader) throws IOException {
|
||||
ChunkUtil.readCheckType(reader, CHUNK_TYPE);
|
||||
int chunkSize = reader.readInt();
|
||||
int stringCount = reader.readInt();
|
||||
int styleOffsetCount = reader.readInt();
|
||||
int flags = reader.readInt();
|
||||
int stringsOffset = reader.readInt();
|
||||
int stylesOffset = reader.readInt();
|
||||
|
||||
StringBlock block = new StringBlock();
|
||||
block.m_isUTF8 = (flags & UTF8_FLAG) != 0;
|
||||
block.m_stringOffsets = reader.readIntArray(stringCount);
|
||||
if (styleOffsetCount != 0) {
|
||||
block.m_styleOffsets = reader.readIntArray(styleOffsetCount);
|
||||
}
|
||||
|
||||
int size = ((stylesOffset == 0) ? chunkSize : stylesOffset) - stringsOffset;
|
||||
block.m_strings = new byte[size];
|
||||
reader.readFully(block.m_strings);
|
||||
|
||||
if (stylesOffset != 0) {
|
||||
size = (chunkSize - stylesOffset);
|
||||
block.m_styles = reader.readIntArray(size / 4);
|
||||
|
||||
int remaining = size % 4;
|
||||
if (remaining >= 1) {
|
||||
while (remaining-- > 0) {
|
||||
reader.readByte();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of strings in block.
|
||||
*/
|
||||
public int getCount() {
|
||||
return m_stringOffsets != null ?
|
||||
m_stringOffsets.length :
|
||||
0;
|
||||
}
|
||||
|
||||
|
||||
public String getString(int index) {
|
||||
if (index < 0 || m_stringOffsets == null || index >= m_stringOffsets.length) {
|
||||
return null;
|
||||
}
|
||||
int offset = m_stringOffsets[index];
|
||||
int length;
|
||||
if (m_isUTF8) {
|
||||
int[] val = getUtf8(m_strings, offset);
|
||||
offset = val[0];
|
||||
length = val[1];
|
||||
} else {
|
||||
int[] val = getUtf16(m_strings, offset);
|
||||
offset += val[0];
|
||||
length = val[1];
|
||||
}
|
||||
return decodeString(offset, length);
|
||||
}
|
||||
|
||||
private String decodeString(int offset, int length) {
|
||||
try {
|
||||
return (m_isUTF8 ? UTF8_DECODER : UTF16LE_DECODER).decode(
|
||||
ByteBuffer.wrap(m_strings, offset, length)).toString();
|
||||
} catch (CharacterCodingException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final int getShort(byte[] array, int offset) {
|
||||
return (array[offset + 1] & 0xff) << 8 | array[offset] & 0xff;
|
||||
}
|
||||
|
||||
private static final int[] getUtf8(byte[] array, int offset) {
|
||||
int val = array[offset];
|
||||
int length;
|
||||
if ((val & 0x80) != 0) {
|
||||
offset += 2;
|
||||
} else {
|
||||
offset += 1;
|
||||
}
|
||||
val = array[offset];
|
||||
if ((val & 0x80) != 0) {
|
||||
offset += 2;
|
||||
} else {
|
||||
offset += 1;
|
||||
}
|
||||
length = 0;
|
||||
while (array[offset + length] != 0) {
|
||||
length++;
|
||||
}
|
||||
return new int[]{offset, length};
|
||||
}
|
||||
|
||||
private static final int[] getUtf16(byte[] array, int offset) {
|
||||
int val = (array[offset + 1] & 0xff) << 8 | array[offset] & 0xff;
|
||||
if (val == 0x8000) {
|
||||
int heigh = (array[offset + 3] & 0xFF) << 8;
|
||||
int low = (array[offset + 2] & 0xFF);
|
||||
return new int[]{4, (heigh + low) * 2};
|
||||
}
|
||||
return new int[]{2, val * 2};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Not yet implemented.
|
||||
* <p>
|
||||
* Returns string with style information (if any).
|
||||
*/
|
||||
public CharSequence get(int index) {
|
||||
return getString(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns string with style tags (html-like).
|
||||
*/
|
||||
public String getHTML(int index) {
|
||||
String raw=getString(index);
|
||||
if (raw==null) {
|
||||
return raw;
|
||||
}
|
||||
int[] style=getStyle(index);
|
||||
if (style==null) {
|
||||
return raw;
|
||||
}
|
||||
StringBuilder html=new StringBuilder(raw.length()+32);
|
||||
int offset=0;
|
||||
while (true) {
|
||||
int i=-1;
|
||||
for (int j=0;j!=style.length;j+=3) {
|
||||
if (style[j+1]==-1) {
|
||||
continue;
|
||||
}
|
||||
if (i==-1 || style[i+1]>style[j+1]) {
|
||||
i=j;
|
||||
}
|
||||
}
|
||||
int start=((i!=-1)?style[i+1]:raw.length());
|
||||
for (int j=0;j!=style.length;j+=3) {
|
||||
int end=style[j+2];
|
||||
if (end==-1 || end>=start) {
|
||||
continue;
|
||||
}
|
||||
if (offset<=end) {
|
||||
html.append(raw,offset,end+1);
|
||||
offset=end+1;
|
||||
}
|
||||
style[j+2]=-1;
|
||||
html.append('<');
|
||||
html.append('/');
|
||||
html.append(getString(style[j]));
|
||||
html.append('>');
|
||||
}
|
||||
if (offset<start) {
|
||||
html.append(raw,offset,start);
|
||||
offset=start;
|
||||
}
|
||||
if (i==-1) {
|
||||
break;
|
||||
}
|
||||
html.append('<');
|
||||
html.append(getString(style[i]));
|
||||
html.append('>');
|
||||
style[i+1]=-1;
|
||||
}
|
||||
return html.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds index of the string.
|
||||
* Returns -1 if the string was not found.
|
||||
*/
|
||||
public int find(String string) {
|
||||
if (string==null) {
|
||||
return -1;
|
||||
}
|
||||
for (int i=0;i!=m_stringOffsets.length;++i) {
|
||||
int offset=m_stringOffsets[i];
|
||||
int length=getShort(m_strings,offset);
|
||||
if (length!=string.length()) {
|
||||
continue;
|
||||
}
|
||||
int j=0;
|
||||
for (;j!=length;++j) {
|
||||
offset+=2;
|
||||
if (string.charAt(j)!=getShort(m_strings,offset)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j==length) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////// implementation
|
||||
|
||||
private StringBlock() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns style information - array of int triplets,
|
||||
* where in each triplet:
|
||||
* * first int is index of tag name ('b','i', etc.)
|
||||
* * second int is tag start index in string
|
||||
* * third int is tag end index in string
|
||||
*/
|
||||
private int[] getStyle(int index) {
|
||||
if (m_styleOffsets==null || m_styles==null ||
|
||||
index>=m_styleOffsets.length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
int offset=m_styleOffsets[index]/4;
|
||||
int style[];
|
||||
{
|
||||
int count=0;
|
||||
for (int i=offset;i<m_styles.length;++i) {
|
||||
if (m_styles[i]==-1) {
|
||||
break;
|
||||
}
|
||||
count+=1;
|
||||
}
|
||||
if (count==0 || (count%3)!=0) {
|
||||
return null;
|
||||
}
|
||||
style=new int[count];
|
||||
}
|
||||
for (int i=offset,j=0;i<m_styles.length;) {
|
||||
if (m_styles[i]==-1) {
|
||||
break;
|
||||
}
|
||||
style[j++]=m_styles[i++];
|
||||
}
|
||||
return style;
|
||||
}
|
||||
|
||||
private static final int getShort(int[] array,int offset) {
|
||||
int value=array[offset/4];
|
||||
if ((offset%4)/2==0) {
|
||||
return (value & 0xFFFF);
|
||||
} else {
|
||||
return (value >>> 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* 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 wind.android.content.res;
|
||||
|
||||
import wind.v1.XmlPullParser;
|
||||
import wind.android.util.AttributeSet;
|
||||
|
||||
/**
|
||||
* @author Dmitry Skiba
|
||||
*
|
||||
*/
|
||||
public interface XmlResourceParser extends XmlPullParser, AttributeSet {
|
||||
void close();
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* 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 wind.android.util;
|
||||
|
||||
/**
|
||||
* @author Dmitry Skiba
|
||||
*
|
||||
*/
|
||||
public interface AttributeSet {
|
||||
int getAttributeCount();
|
||||
String getAttributeName(int index);
|
||||
String getAttributeValue(int index);
|
||||
String getPositionDescription();
|
||||
int getAttributeNameResource(int index);
|
||||
int getAttributeListValue(int index, String options[], int defaultValue);
|
||||
boolean getAttributeBooleanValue(int index, boolean defaultValue);
|
||||
int getAttributeResourceValue(int index, int defaultValue);
|
||||
int getAttributeIntValue(int index, int defaultValue);
|
||||
int getAttributeUnsignedIntValue(int index, int defaultValue);
|
||||
float getAttributeFloatValue(int index, float defaultValue);
|
||||
String getIdAttribute();
|
||||
String getClassAttribute();
|
||||
int getIdAttributeResourceValue(int index);
|
||||
int getStyleAttribute();
|
||||
String getAttributeValue(String namespace, String attribute);
|
||||
int getAttributeListValue(String namespace, String attribute, String options[], int defaultValue);
|
||||
boolean getAttributeBooleanValue(String namespace, String attribute, boolean defaultValue);
|
||||
int getAttributeResourceValue(String namespace, String attribute, int defaultValue);
|
||||
int getAttributeIntValue(String namespace, String attribute, int defaultValue);
|
||||
int getAttributeUnsignedIntValue(String namespace, String attribute, int defaultValue);
|
||||
float getAttributeFloatValue(String namespace, String attribute, float defaultValue);
|
||||
|
||||
//TODO: remove
|
||||
int getAttributeValueType(int index);
|
||||
int getAttributeValueData(int index);
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* 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 wind.android.util;
|
||||
|
||||
/**
|
||||
* @author Dmitry Skiba
|
||||
*
|
||||
*/
|
||||
public class TypedValue {
|
||||
|
||||
public int type;
|
||||
public CharSequence string;
|
||||
public int data;
|
||||
public int assetCookie;
|
||||
public int resourceId;
|
||||
public int changingConfigurations;
|
||||
|
||||
public static final int
|
||||
TYPE_NULL =0,
|
||||
TYPE_REFERENCE =1,
|
||||
TYPE_ATTRIBUTE =2,
|
||||
TYPE_STRING =3,
|
||||
TYPE_FLOAT =4,
|
||||
TYPE_DIMENSION =5,
|
||||
TYPE_FRACTION =6,
|
||||
TYPE_FIRST_INT =16,
|
||||
TYPE_INT_DEC =16,
|
||||
TYPE_INT_HEX =17,
|
||||
TYPE_INT_BOOLEAN =18,
|
||||
TYPE_FIRST_COLOR_INT =28,
|
||||
TYPE_INT_COLOR_ARGB8 =28,
|
||||
TYPE_INT_COLOR_RGB8 =29,
|
||||
TYPE_INT_COLOR_ARGB4 =30,
|
||||
TYPE_INT_COLOR_RGB4 =31,
|
||||
TYPE_LAST_COLOR_INT =31,
|
||||
TYPE_LAST_INT =31;
|
||||
|
||||
public static final int
|
||||
COMPLEX_UNIT_PX =0,
|
||||
COMPLEX_UNIT_DIP =1,
|
||||
COMPLEX_UNIT_SP =2,
|
||||
COMPLEX_UNIT_PT =3,
|
||||
COMPLEX_UNIT_IN =4,
|
||||
COMPLEX_UNIT_MM =5,
|
||||
COMPLEX_UNIT_SHIFT =0,
|
||||
COMPLEX_UNIT_MASK =15,
|
||||
COMPLEX_UNIT_FRACTION =0,
|
||||
COMPLEX_UNIT_FRACTION_PARENT=1,
|
||||
COMPLEX_RADIX_23p0 =0,
|
||||
COMPLEX_RADIX_16p7 =1,
|
||||
COMPLEX_RADIX_8p15 =2,
|
||||
COMPLEX_RADIX_0p23 =3,
|
||||
COMPLEX_RADIX_SHIFT =4,
|
||||
COMPLEX_RADIX_MASK =3,
|
||||
COMPLEX_MANTISSA_SHIFT =8,
|
||||
COMPLEX_MANTISSA_MASK =0xFFFFFF;
|
||||
|
||||
}
|
||||
|
|
@ -1,170 +0,0 @@
|
|||
/*
|
||||
* 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 wind.test;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import wind.v1.XmlPullParser;
|
||||
import wind.android.content.res.AXmlResourceParser;
|
||||
//import android.util.TypedValue;
|
||||
|
||||
/**
|
||||
* @author Dmitry Skiba
|
||||
*
|
||||
* This is example usage of AXMLParser class.
|
||||
*
|
||||
* Prints xml document from Android's binary xml file.
|
||||
*/
|
||||
public class AXMLPrinter {
|
||||
|
||||
public static void main(String[] arguments) {
|
||||
if (arguments.length<1) {
|
||||
log("Usage: AXMLPrinter <binary xml file>");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
AXmlResourceParser parser=new AXmlResourceParser();
|
||||
parser.open(new FileInputStream(arguments[0]));
|
||||
StringBuilder indent=new StringBuilder(10);
|
||||
final String indentStep=" ";
|
||||
while (true) {
|
||||
int type=parser.next();
|
||||
if (type==XmlPullParser.END_DOCUMENT) {
|
||||
break;
|
||||
}
|
||||
switch (type) {
|
||||
case XmlPullParser.START_DOCUMENT:
|
||||
{
|
||||
log("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
|
||||
break;
|
||||
}
|
||||
case XmlPullParser.START_TAG:
|
||||
{
|
||||
log("%s<%s%s",indent,
|
||||
getNamespacePrefix(parser.getPrefix()),parser.getName());
|
||||
indent.append(indentStep);
|
||||
|
||||
int namespaceCountBefore=parser.getNamespaceCount(parser.getDepth()-1);
|
||||
int namespaceCount=parser.getNamespaceCount(parser.getDepth());
|
||||
for (int i=namespaceCountBefore;i!=namespaceCount;++i) {
|
||||
log("%sxmlns:%s=\"%s\"",
|
||||
indent,
|
||||
parser.getNamespacePrefix(i),
|
||||
parser.getNamespaceUri(i));
|
||||
}
|
||||
|
||||
for (int i=0;i!=parser.getAttributeCount();++i) {
|
||||
log("%s%s%s=\"%s\"",indent,
|
||||
getNamespacePrefix(parser.getAttributePrefix(i)),
|
||||
parser.getAttributeName(i),
|
||||
getAttributeValue(parser,i));
|
||||
}
|
||||
log("%s>",indent);
|
||||
break;
|
||||
}
|
||||
case XmlPullParser.END_TAG:
|
||||
{
|
||||
indent.setLength(indent.length()-indentStep.length());
|
||||
log("%s</%s%s>",indent,
|
||||
getNamespacePrefix(parser.getPrefix()),
|
||||
parser.getName());
|
||||
break;
|
||||
}
|
||||
case XmlPullParser.TEXT:
|
||||
{
|
||||
log("%s%s",indent,parser.getText());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static String getNamespacePrefix(String prefix) {
|
||||
if (prefix==null || prefix.length()==0) {
|
||||
return "";
|
||||
}
|
||||
return prefix+":";
|
||||
}
|
||||
|
||||
private static String getAttributeValue(AXmlResourceParser parser,int index) {
|
||||
int type=parser.getAttributeValueType(index);
|
||||
int data=parser.getAttributeValueData(index);
|
||||
// if (type==TypedValue.TYPE_STRING) {
|
||||
// return parser.getAttributeValue(index);
|
||||
// }
|
||||
// if (type==TypedValue.TYPE_ATTRIBUTE) {
|
||||
// return String.format("?%s%08X",getPackage(data),data);
|
||||
// }
|
||||
// if (type==TypedValue.TYPE_REFERENCE) {
|
||||
// return String.format("@%s%08X",getPackage(data),data);
|
||||
// }
|
||||
// if (type==TypedValue.TYPE_FLOAT) {
|
||||
// return String.valueOf(Float.intBitsToFloat(data));
|
||||
// }
|
||||
// if (type==TypedValue.TYPE_INT_HEX) {
|
||||
// return String.format("0x%08X",data);
|
||||
// }
|
||||
// if (type==TypedValue.TYPE_INT_BOOLEAN) {
|
||||
// return data!=0?"true":"false";
|
||||
// }
|
||||
// if (type==TypedValue.TYPE_DIMENSION) {
|
||||
// return Float.toString(complexToFloat(data))+
|
||||
// DIMENSION_UNITS[data & TypedValue.COMPLEX_UNIT_MASK];
|
||||
// }
|
||||
// if (type==TypedValue.TYPE_FRACTION) {
|
||||
// return Float.toString(complexToFloat(data))+
|
||||
// FRACTION_UNITS[data & TypedValue.COMPLEX_UNIT_MASK];
|
||||
// }
|
||||
// if (type>=TypedValue.TYPE_FIRST_COLOR_INT && type<=TypedValue.TYPE_LAST_COLOR_INT) {
|
||||
// return String.format("#%08X",data);
|
||||
// }
|
||||
// if (type>=TypedValue.TYPE_FIRST_INT && type<=TypedValue.TYPE_LAST_INT) {
|
||||
// return String.valueOf(data);
|
||||
// }
|
||||
return String.format("<0x%X, type 0x%02X>",data,type);
|
||||
}
|
||||
|
||||
private static String getPackage(int id) {
|
||||
if (id>>>24==1) {
|
||||
return "android:";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private static void log(String format,Object...arguments) {
|
||||
System.out.printf(format,arguments);
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
/////////////////////////////////// ILLEGAL STUFF, DONT LOOK :)
|
||||
|
||||
public static float complexToFloat(int complex) {
|
||||
return (float)(complex & 0xFFFFFF00)*RADIX_MULTS[(complex>>4) & 3];
|
||||
}
|
||||
|
||||
private static final float RADIX_MULTS[]={
|
||||
0.00390625F,3.051758E-005F,1.192093E-007F,4.656613E-010F
|
||||
};
|
||||
private static final String DIMENSION_UNITS[]={
|
||||
"px","dip","sp","pt","in","mm","",""
|
||||
};
|
||||
private static final String FRACTION_UNITS[]={
|
||||
"%","%p","","","","","",""
|
||||
};
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,78 +0,0 @@
|
|||
/* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- //------100-columns-wide------>|*/
|
||||
// for license please see accompanying LICENSE.txt file (available also at http://www.xmlpull.org/)
|
||||
|
||||
package wind.v1;
|
||||
|
||||
import wind.v1.XmlPullParser;
|
||||
|
||||
/**
|
||||
* This exception is thrown to signal XML Pull Parser related faults.
|
||||
*
|
||||
* @author <a href="http://www.extreme.indiana.edu/~aslom/">Aleksander Slominski</a>
|
||||
*/
|
||||
public class XmlPullParserException extends Exception {
|
||||
protected Throwable detail;
|
||||
protected int row = -1;
|
||||
protected int column = -1;
|
||||
|
||||
/* public XmlPullParserException() {
|
||||
}*/
|
||||
|
||||
public XmlPullParserException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
/*
|
||||
public XmlPullParserException(String s, Throwable thrwble) {
|
||||
super(s);
|
||||
this.detail = thrwble;
|
||||
}
|
||||
|
||||
public XmlPullParserException(String s, int row, int column) {
|
||||
super(s);
|
||||
this.row = row;
|
||||
this.column = column;
|
||||
}
|
||||
*/
|
||||
|
||||
public XmlPullParserException(String msg, XmlPullParser parser, Throwable chain) {
|
||||
super ((msg == null ? "" : msg+" ")
|
||||
+ (parser == null ? "" : "(position:"+parser.getPositionDescription()+") ")
|
||||
+ (chain == null ? "" : "caused by: "+chain));
|
||||
|
||||
if (parser != null) {
|
||||
this.row = parser.getLineNumber();
|
||||
this.column = parser.getColumnNumber();
|
||||
}
|
||||
this.detail = chain;
|
||||
}
|
||||
|
||||
public Throwable getDetail() { return detail; }
|
||||
// public void setDetail(Throwable cause) { this.detail = cause; }
|
||||
public int getLineNumber() { return row; }
|
||||
public int getColumnNumber() { return column; }
|
||||
|
||||
/*
|
||||
public String getMessage() {
|
||||
if(detail == null)
|
||||
return super.getMessage();
|
||||
else
|
||||
return super.getMessage() + "; nested exception is: \n\t"
|
||||
+ detail.getMessage();
|
||||
}
|
||||
*/
|
||||
|
||||
//NOTE: code that prints this and detail is difficult in J2ME
|
||||
public void printStackTrace() {
|
||||
if (detail == null) {
|
||||
super.printStackTrace();
|
||||
} else {
|
||||
synchronized(System.err) {
|
||||
System.err.println(super.getMessage() + "; nested exception is:");
|
||||
detail.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,360 +0,0 @@
|
|||
/* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- //------100-columns-wide------>|*/
|
||||
// for license please see accompanying LICENSE.txt file (available also at http://www.xmlpull.org/)
|
||||
|
||||
package wind.v1;
|
||||
|
||||
import wind.v1.XmlPullParser;
|
||||
import wind.v1.XmlPullParserException;
|
||||
import wind.v1.XmlSerializer;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* This class is used to create implementations of XML Pull Parser defined in XMPULL V1 API.
|
||||
* The name of actual factory class will be determined based on several parameters.
|
||||
* It works similar to JAXP but tailored to work in J2ME environments
|
||||
* (no access to system properties or file system) so name of parser class factory to use
|
||||
* and its class used for loading (no class loader - on J2ME no access to context class loaders)
|
||||
* must be passed explicitly. If no name of parser factory was passed (or is null)
|
||||
* it will try to find name by searching in CLASSPATH for
|
||||
* META-INF/services/wind.v1.XmlPullParserFactory resource that should contain
|
||||
* a comma separated list of class names of factories or parsers to try (in order from
|
||||
* left to the right). If none found, it will throw an exception.
|
||||
*
|
||||
* <br /><strong>NOTE:</strong>In J2SE or J2EE environments, you may want to use
|
||||
* <code>newInstance(property, classLoaderCtx)</code>
|
||||
* where first argument is
|
||||
* <code>System.getProperty(XmlPullParserFactory.PROPERTY_NAME)</code>
|
||||
* and second is <code>Thread.getContextClassLoader().getClass()</code> .
|
||||
*
|
||||
* @see wind.v1.XmlPullParser
|
||||
*
|
||||
* @author <a href="http://www.extreme.indiana.edu/~aslom/">Aleksander Slominski</a>
|
||||
* @author Stefan Haustein
|
||||
*/
|
||||
|
||||
public class XmlPullParserFactory {
|
||||
/** used as default class to server as context class in newInstance() */
|
||||
final static Class referenceContextClass;
|
||||
|
||||
static {
|
||||
XmlPullParserFactory f = new XmlPullParserFactory();
|
||||
referenceContextClass = f.getClass();
|
||||
}
|
||||
|
||||
/** Name of the system or midlet property that should be used for
|
||||
a system property containing a comma separated list of factory
|
||||
or parser class names (value:
|
||||
wind.v1.XmlPullParserFactory). */
|
||||
|
||||
|
||||
public static final String PROPERTY_NAME =
|
||||
"org.xmlpull.v1.XmlPullParserFactory";
|
||||
|
||||
private static final String RESOURCE_NAME =
|
||||
"/META-INF/services/" + PROPERTY_NAME;
|
||||
|
||||
|
||||
// public static final String DEFAULT_PROPERTY =
|
||||
// "wind.xpp3.XmlPullParser,org.kxml2.io.KXmlParser";
|
||||
|
||||
|
||||
protected Vector parserClasses;
|
||||
protected String classNamesLocation;
|
||||
|
||||
protected Vector serializerClasses;
|
||||
|
||||
|
||||
// features are kept there
|
||||
protected Hashtable features = new Hashtable();
|
||||
|
||||
|
||||
/**
|
||||
* Protected constructor to be called by factory implementations.
|
||||
*/
|
||||
|
||||
protected XmlPullParserFactory() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set the features to be set when XML Pull Parser is created by this factory.
|
||||
* <p><b>NOTE:</b> factory features are not used for XML Serializer.
|
||||
*
|
||||
* @param name string with URI identifying feature
|
||||
* @param state if true feature will be set; if false will be ignored
|
||||
*/
|
||||
|
||||
public void setFeature(String name,
|
||||
boolean state) throws XmlPullParserException {
|
||||
|
||||
features.put(name, new Boolean(state));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the current value of the feature with given name.
|
||||
* <p><b>NOTE:</b> factory features are not used for XML Serializer.
|
||||
*
|
||||
* @param name The name of feature to be retrieved.
|
||||
* @return The value of named feature.
|
||||
* Unknown features are <string>always</strong> returned as false
|
||||
*/
|
||||
|
||||
public boolean getFeature (String name) {
|
||||
Boolean value = (Boolean) features.get(name);
|
||||
return value != null ? value.booleanValue() : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that the parser produced by this factory will provide
|
||||
* support for XML namespaces.
|
||||
* By default the value of this is set to false.
|
||||
*
|
||||
* @param awareness true if the parser produced by this code
|
||||
* will provide support for XML namespaces; false otherwise.
|
||||
*/
|
||||
|
||||
public void setNamespaceAware(boolean awareness) {
|
||||
features.put (wind.v1.XmlPullParser.FEATURE_PROCESS_NAMESPACES, new Boolean (awareness));
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether or not the factory is configured to produce
|
||||
* parsers which are namespace aware
|
||||
* (it simply set feature XmlPullParser.FEATURE_PROCESS_NAMESPACES to true or false).
|
||||
*
|
||||
* @return true if the factory is configured to produce parsers
|
||||
* which are namespace aware; false otherwise.
|
||||
*/
|
||||
|
||||
public boolean isNamespaceAware() {
|
||||
return getFeature (wind.v1.XmlPullParser.FEATURE_PROCESS_NAMESPACES);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specifies that the parser produced by this factory will be validating
|
||||
* (it simply set feature XmlPullParser.FEATURE_VALIDATION to true or false).
|
||||
*
|
||||
* By default the value of this is set to false.
|
||||
*
|
||||
* @param validating - if true the parsers created by this factory must be validating.
|
||||
*/
|
||||
|
||||
public void setValidating(boolean validating) {
|
||||
features.put (wind.v1.XmlPullParser.FEATURE_VALIDATION, new Boolean (validating));
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether or not the factory is configured to produce parsers
|
||||
* which validate the XML content during parse.
|
||||
*
|
||||
* @return true if the factory is configured to produce parsers
|
||||
* which validate the XML content during parse; false otherwise.
|
||||
*/
|
||||
|
||||
public boolean isValidating() {
|
||||
return getFeature (wind.v1.XmlPullParser.FEATURE_VALIDATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of a XML Pull Parser
|
||||
* using the currently configured factory features.
|
||||
*
|
||||
* @return A new instance of a XML Pull Parser.
|
||||
* @throws XmlPullParserException if a parser cannot be created which satisfies the
|
||||
* requested configuration.
|
||||
*/
|
||||
|
||||
public wind.v1.XmlPullParser newPullParser() throws XmlPullParserException {
|
||||
|
||||
if (parserClasses == null) throw new XmlPullParserException
|
||||
("Factory initialization was incomplete - has not tried "+classNamesLocation);
|
||||
|
||||
if (parserClasses.size() == 0) throw new XmlPullParserException
|
||||
("No valid parser classes found in "+classNamesLocation);
|
||||
|
||||
final StringBuffer issues = new StringBuffer ();
|
||||
|
||||
for (int i = 0; i < parserClasses.size (); i++) {
|
||||
final Class ppClass = (Class) parserClasses.elementAt (i);
|
||||
try {
|
||||
final wind.v1.XmlPullParser pp = (wind.v1.XmlPullParser) ppClass.newInstance();
|
||||
// if( ! features.isEmpty() ) {
|
||||
//Enumeration keys = features.keys();
|
||||
// while(keys.hasMoreElements()) {
|
||||
|
||||
for (Enumeration e = features.keys (); e.hasMoreElements ();) {
|
||||
final String key = (String) e.nextElement();
|
||||
final Boolean value = (Boolean) features.get(key);
|
||||
if(value != null && value.booleanValue()) {
|
||||
pp.setFeature(key, true);
|
||||
}
|
||||
}
|
||||
return pp;
|
||||
|
||||
} catch(Exception ex) {
|
||||
issues.append (ppClass.getName () + ": "+ ex.toString ()+"; ");
|
||||
}
|
||||
}
|
||||
|
||||
throw new XmlPullParserException ("could not create parser: "+issues);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance of a XML Serializer.
|
||||
*
|
||||
* <p><b>NOTE:</b> factory features are not used for XML Serializer.
|
||||
*
|
||||
* @return A new instance of a XML Serializer.
|
||||
* @throws XmlPullParserException if a parser cannot be created which satisfies the
|
||||
* requested configuration.
|
||||
*/
|
||||
|
||||
public wind.v1.XmlSerializer newSerializer() throws XmlPullParserException {
|
||||
|
||||
if (serializerClasses == null) {
|
||||
throw new XmlPullParserException
|
||||
("Factory initialization incomplete - has not tried "+classNamesLocation);
|
||||
}
|
||||
if(serializerClasses.size() == 0) {
|
||||
throw new XmlPullParserException
|
||||
("No valid serializer classes found in "+classNamesLocation);
|
||||
}
|
||||
|
||||
final StringBuffer issues = new StringBuffer ();
|
||||
|
||||
for (int i = 0; i < serializerClasses.size (); i++) {
|
||||
final Class ppClass = (Class) serializerClasses.elementAt (i);
|
||||
try {
|
||||
final wind.v1.XmlSerializer ser = (wind.v1.XmlSerializer) ppClass.newInstance();
|
||||
|
||||
// for (Enumeration e = features.keys (); e.hasMoreElements ();) {
|
||||
// String key = (String) e.nextElement();
|
||||
// Boolean value = (Boolean) features.get(key);
|
||||
// if(value != null && value.booleanValue()) {
|
||||
// ser.setFeature(key, true);
|
||||
// }
|
||||
// }
|
||||
return ser;
|
||||
|
||||
} catch(Exception ex) {
|
||||
issues.append (ppClass.getName () + ": "+ ex.toString ()+"; ");
|
||||
}
|
||||
}
|
||||
|
||||
throw new XmlPullParserException ("could not create serializer: "+issues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of a PullParserFactory that can be used
|
||||
* to create XML pull parsers (see class description for more
|
||||
* details).
|
||||
*
|
||||
* @return a new instance of a PullParserFactory, as returned by newInstance (null, null);
|
||||
*/
|
||||
public static XmlPullParserFactory newInstance () throws XmlPullParserException {
|
||||
return newInstance(null, null);
|
||||
}
|
||||
|
||||
public static XmlPullParserFactory newInstance (String classNames, Class context)
|
||||
throws XmlPullParserException {
|
||||
|
||||
if (context == null) {
|
||||
//NOTE: make sure context uses the same class loader as API classes
|
||||
// this is the best we can do without having access to context classloader in J2ME
|
||||
// if API is in the same classloader as implementation then this will work
|
||||
context = referenceContextClass;
|
||||
}
|
||||
|
||||
String classNamesLocation = null;
|
||||
|
||||
if (classNames == null || classNames.length() == 0 || "DEFAULT".equals(classNames)) {
|
||||
try {
|
||||
InputStream is = context.getResourceAsStream (RESOURCE_NAME);
|
||||
|
||||
if (is == null) throw new XmlPullParserException
|
||||
("resource not found: "+RESOURCE_NAME
|
||||
+" make sure that parser implementing XmlPull API is available");
|
||||
final StringBuffer sb = new StringBuffer();
|
||||
|
||||
while (true) {
|
||||
final int ch = is.read();
|
||||
if (ch < 0) break;
|
||||
else if (ch > ' ')
|
||||
sb.append((char) ch);
|
||||
}
|
||||
is.close ();
|
||||
|
||||
classNames = sb.toString ();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new XmlPullParserException (null, null, e);
|
||||
}
|
||||
classNamesLocation = "resource "+RESOURCE_NAME+" that contained '"+classNames+"'";
|
||||
} else {
|
||||
classNamesLocation =
|
||||
"parameter classNames to newInstance() that contained '"+classNames+"'";
|
||||
}
|
||||
|
||||
XmlPullParserFactory factory = null;
|
||||
final Vector parserClasses = new Vector ();
|
||||
final Vector serializerClasses = new Vector ();
|
||||
int pos = 0;
|
||||
|
||||
while (pos < classNames.length ()) {
|
||||
int cut = classNames.indexOf (',', pos);
|
||||
|
||||
if (cut == -1) cut = classNames.length ();
|
||||
final String name = classNames.substring (pos, cut);
|
||||
|
||||
Class candidate = null;
|
||||
Object instance = null;
|
||||
|
||||
try {
|
||||
candidate = Class.forName (name);
|
||||
// necessary because of J2ME .class issue
|
||||
instance = candidate.newInstance ();
|
||||
}
|
||||
catch (Exception e) {}
|
||||
|
||||
if (candidate != null) {
|
||||
boolean recognized = false;
|
||||
if (instance instanceof XmlPullParser) {
|
||||
parserClasses.addElement (candidate);
|
||||
recognized = true;
|
||||
}
|
||||
if (instance instanceof XmlSerializer) {
|
||||
serializerClasses.addElement (candidate);
|
||||
recognized = true;
|
||||
}
|
||||
if (instance instanceof XmlPullParserFactory) {
|
||||
if (factory == null) {
|
||||
factory = (XmlPullParserFactory) instance;
|
||||
}
|
||||
recognized = true;
|
||||
}
|
||||
if (!recognized) {
|
||||
throw new XmlPullParserException ("incompatible class: "+name);
|
||||
}
|
||||
}
|
||||
pos = cut + 1;
|
||||
}
|
||||
|
||||
if (factory == null) {
|
||||
factory = new XmlPullParserFactory ();
|
||||
}
|
||||
factory.parserClasses = parserClasses;
|
||||
factory.serializerClasses = serializerClasses;
|
||||
factory.classNamesLocation = classNamesLocation;
|
||||
return factory;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,326 +0,0 @@
|
|||
package wind.v1;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Writer;
|
||||
|
||||
/**
|
||||
* Define an interface to serialziation of XML Infoset.
|
||||
* This interface abstracts away if serialized XML is XML 1.0 comaptible text or
|
||||
* other formats of XML 1.0 serializations (such as binary XML for example with WBXML).
|
||||
*
|
||||
* <p><b>PLEASE NOTE:</b> This interface will be part of XmlPull 1.2 API.
|
||||
* It is included as basis for discussion. It may change in any way.
|
||||
*
|
||||
* <p>Exceptions that may be thrown are: IOException or runtime exception
|
||||
* (more runtime exceptions can be thrown but are not declared and as such
|
||||
* have no semantics defined for this interface):
|
||||
* <ul>
|
||||
* <li><em>IllegalArgumentException</em> - for almost all methods to signal that
|
||||
* argument is illegal
|
||||
* <li><em>IllegalStateException</em> - to signal that call has good arguments but
|
||||
* is not expected here (violation of contract) and for features/properties
|
||||
* when requesting setting unimplemented feature/property
|
||||
* (UnsupportedOperationException would be better but it is not in MIDP)
|
||||
* </ul>
|
||||
*
|
||||
* <p><b>NOTE:</b> writing CDSECT, ENTITY_REF, IGNORABLE_WHITESPACE,
|
||||
* PROCESSING_INSTRUCTION, COMMENT, and DOCDECL in some implementations
|
||||
* may not be supported (for example when serializing to WBXML).
|
||||
* In such case IllegalStateException will be thrown and it is recommened
|
||||
* to use an optional feature to signal that implementation is not
|
||||
* supporting this kind of output.
|
||||
*/
|
||||
|
||||
public interface XmlSerializer {
|
||||
|
||||
/**
|
||||
* Set feature identified by name (recommended to be URI for uniqueness).
|
||||
* Some well known optional features are defined in
|
||||
* <a href="http://www.xmlpull.org/v1/doc/features.html">
|
||||
* http://www.xmlpull.org/v1/doc/features.html</a>.
|
||||
*
|
||||
* If feature is not recocgnized or can not be set
|
||||
* then IllegalStateException MUST be thrown.
|
||||
*
|
||||
* @exception IllegalStateException If the feature is not supported or can not be set
|
||||
*/
|
||||
void setFeature(String name,
|
||||
boolean state)
|
||||
throws IllegalArgumentException, IllegalStateException;
|
||||
|
||||
|
||||
/**
|
||||
* Return the current value of the feature with given name.
|
||||
* <p><strong>NOTE:</strong> unknown properties are <strong>always</strong> returned as null
|
||||
*
|
||||
* @param name The name of feature to be retrieved.
|
||||
* @return The value of named feature.
|
||||
* @exception IllegalArgumentException if feature string is null
|
||||
*/
|
||||
boolean getFeature(String name);
|
||||
|
||||
|
||||
/**
|
||||
* Set the value of a property.
|
||||
* (the property name is recommened to be URI for uniqueness).
|
||||
* Some well known optional properties are defined in
|
||||
* <a href="http://www.xmlpull.org/v1/doc/properties.html">
|
||||
* http://www.xmlpull.org/v1/doc/properties.html</a>.
|
||||
*
|
||||
* If property is not recocgnized or can not be set
|
||||
* then IllegalStateException MUST be thrown.
|
||||
*
|
||||
* @exception IllegalStateException if the property is not supported or can not be set
|
||||
*/
|
||||
void setProperty(String name,
|
||||
Object value)
|
||||
throws IllegalArgumentException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* Look up the value of a property.
|
||||
*
|
||||
* The property name is any fully-qualified URI. I
|
||||
* <p><strong>NOTE:</strong> unknown properties are <string>always</strong> returned as null
|
||||
*
|
||||
* @param name The name of property to be retrieved.
|
||||
* @return The value of named property.
|
||||
*/
|
||||
Object getProperty(String name);
|
||||
|
||||
/**
|
||||
* Set to use binary output stream with given encoding.
|
||||
*/
|
||||
void setOutput(OutputStream os, String encoding)
|
||||
throws IOException, IllegalArgumentException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* Set the output to the given writer.
|
||||
* <p><b>WARNING</b> no information about encoding is available!
|
||||
*/
|
||||
void setOutput(Writer writer)
|
||||
throws IOException, IllegalArgumentException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* Write <?xml declaration with encoding (if encoding not null)
|
||||
* and standalone flag (if standalone not null)
|
||||
* This method can only be called just after setOutput.
|
||||
*/
|
||||
void startDocument(String encoding, Boolean standalone)
|
||||
throws IOException, IllegalArgumentException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* Finish writing. All unclosed start tags will be closed and output
|
||||
* will be flushed. After calling this method no more output can be
|
||||
* serialized until next call to setOutput()
|
||||
*/
|
||||
void endDocument()
|
||||
throws IOException, IllegalArgumentException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* Binds the given prefix to the given namespace.
|
||||
* This call is valid for the next element including child elements.
|
||||
* The prefix and namespace MUST be always declared even if prefix
|
||||
* is not used in element (startTag() or attribute()) - for XML 1.0
|
||||
* it must result in declaring <code>xmlns:prefix='namespace'</code>
|
||||
* (or <code>xmlns:prefix="namespace"</code> depending what character is used
|
||||
* to quote attribute value).
|
||||
*
|
||||
* <p><b>NOTE:</b> this method MUST be called directly before startTag()
|
||||
* and if anything but startTag() or setPrefix() is called next there will be exception.
|
||||
* <p><b>NOTE:</b> prefixes "xml" and "xmlns" are already bound
|
||||
* and can not be redefined see:
|
||||
* <a href="http://www.w3.org/XML/xml-names-19990114-errata#NE05">Namespaces in XML Errata</a>.
|
||||
* <p><b>NOTE:</b> to set default namespace use as prefix empty string.
|
||||
*
|
||||
* @param prefix must be not null (or IllegalArgumentException is thrown)
|
||||
* @param namespace must be not null
|
||||
*/
|
||||
void setPrefix(String prefix, String namespace)
|
||||
throws IOException, IllegalArgumentException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* Return namespace that corresponds to given prefix
|
||||
* If there is no prefix bound to this namespace return null
|
||||
* but if generatePrefix is false then return generated prefix.
|
||||
*
|
||||
* <p><b>NOTE:</b> if the prefix is empty string "" and defualt namespace is bound
|
||||
* to this prefix then empty string ("") is returned.
|
||||
*
|
||||
* <p><b>NOTE:</b> prefixes "xml" and "xmlns" are already bound
|
||||
* will have values as defined
|
||||
* <a href="http://www.w3.org/TR/REC-xml-names/">Namespaces in XML specification</a>
|
||||
*/
|
||||
String getPrefix(String namespace, boolean generatePrefix)
|
||||
throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Returns the current depth of the element.
|
||||
* Outside the root element, the depth is 0. The
|
||||
* depth is incremented by 1 when startTag() is called.
|
||||
* The depth is decremented after the call to endTag()
|
||||
* event was observed.
|
||||
*
|
||||
* <pre>
|
||||
* <!-- outside --> 0
|
||||
* <root> 1
|
||||
* sometext 1
|
||||
* <foobar> 2
|
||||
* </foobar> 2
|
||||
* </root> 1
|
||||
* <!-- outside --> 0
|
||||
* </pre>
|
||||
*/
|
||||
int getDepth();
|
||||
|
||||
/**
|
||||
* Returns the namespace URI of the current element as set by startTag().
|
||||
*
|
||||
* <p><b>NOTE:</b> that measn in particaulr that: <ul>
|
||||
* <li>if there was startTag("", ...) then getNamespace() returns ""
|
||||
* <li>if there was startTag(null, ...) then getNamespace() returns null
|
||||
* </ul>
|
||||
*
|
||||
* @return namespace set by startTag() that is currently in scope
|
||||
*/
|
||||
String getNamespace();
|
||||
|
||||
/**
|
||||
* Returns the name of the current element as set by startTag().
|
||||
* It can only be null before first call to startTag()
|
||||
* or when last endTag() is called to close first startTag().
|
||||
*
|
||||
* @return namespace set by startTag() that is currently in scope
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Writes a start tag with the given namespace and name.
|
||||
* If there is no prefix defined for the given namespace,
|
||||
* a prefix will be defined automatically.
|
||||
* The explicit prefixes for namespaces can be established by calling setPrefix()
|
||||
* immediately before this method.
|
||||
* If namespace is null no namespace prefix is printed but just name.
|
||||
* If namespace is empty string then serialzier will make sure that
|
||||
* default empty namespace is declared (in XML 1.0 xmlns='')
|
||||
* or throw IllegalStateException if default namespace is already bound
|
||||
* to non-empty string.
|
||||
*/
|
||||
XmlSerializer startTag(String namespace, String name)
|
||||
throws IOException, IllegalArgumentException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* Write an attribute. Calls to attribute() MUST follow a call to
|
||||
* startTag() immediately. If there is no prefix defined for the
|
||||
* given namespace, a prefix will be defined automatically.
|
||||
* If namespace is null or empty string
|
||||
* no namespace prefix is printed but just name.
|
||||
*/
|
||||
XmlSerializer attribute(String namespace, String name, String value)
|
||||
throws IOException, IllegalArgumentException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* Write end tag. Repetition of namespace and name is just for avoiding errors.
|
||||
* <p><b>Background:</b> in kXML endTag had no arguments, and non matching tags were
|
||||
* very difficult to find...
|
||||
* If namespace is null no namespace prefix is printed but just name.
|
||||
* If namespace is empty string then serialzier will make sure that
|
||||
* default empty namespace is declared (in XML 1.0 xmlns='').
|
||||
*/
|
||||
XmlSerializer endTag(String namespace, String name)
|
||||
throws IOException, IllegalArgumentException, IllegalStateException;
|
||||
|
||||
|
||||
// /**
|
||||
// * Writes a start tag with the given namespace and name.
|
||||
// * <br />If there is no prefix defined (prefix == null) for the given namespace,
|
||||
// * a prefix will be defined automatically.
|
||||
// * <br />If explicit prefixes is passed (prefix != null) then it will be used
|
||||
// *and namespace declared if not already declared or
|
||||
// * throw IllegalStateException the same prefix was already set on this
|
||||
// * element (setPrefix()) and was bound to different namespace.
|
||||
// * <br />If namespace is null then prefix must be null too or IllegalStateException is thrown.
|
||||
// * <br />If namespace is null then no namespace prefix is printed but just name.
|
||||
// * <br />If namespace is empty string then serializer will make sure that
|
||||
// * default empty namespace is declared (in XML 1.0 xmlns='')
|
||||
// * or throw IllegalStateException if default namespace is already bound
|
||||
// * to non-empty string.
|
||||
// */
|
||||
// XmlSerializer startTag (String prefix, String namespace, String name)
|
||||
// throws IOException, IllegalArgumentException, IllegalStateException;
|
||||
//
|
||||
// /**
|
||||
// * Write an attribute. Calls to attribute() MUST follow a call to
|
||||
// * startTag() immediately.
|
||||
// * <br />If there is no prefix defined (prefix == null) for the given namespace,
|
||||
// * a prefix will be defined automatically.
|
||||
// * <br />If explicit prefixes is passed (prefix != null) then it will be used
|
||||
// * and namespace declared if not already declared or
|
||||
// * throw IllegalStateException the same prefix was already set on this
|
||||
// * element (setPrefix()) and was bound to different namespace.
|
||||
// * <br />If namespace is null then prefix must be null too or IllegalStateException is thrown.
|
||||
// * <br />If namespace is null then no namespace prefix is printed but just name.
|
||||
// * <br />If namespace is empty string then serializer will make sure that
|
||||
// * default empty namespace is declared (in XML 1.0 xmlns='')
|
||||
// * or throw IllegalStateException if default namespace is already bound
|
||||
// * to non-empty string.
|
||||
// */
|
||||
// XmlSerializer attribute (String prefix, String namespace, String name, String value)
|
||||
// throws IOException, IllegalArgumentException, IllegalStateException;
|
||||
//
|
||||
// /**
|
||||
// * Write end tag. Repetition of namespace, prefix, and name is just for avoiding errors.
|
||||
// * <br />If namespace or name arguments are different from corresponding startTag call
|
||||
// * then IllegalArgumentException is thrown, if prefix argument is not null and is different
|
||||
// * from corresponding starTag then IllegalArgumentException is thrown.
|
||||
// * <br />If namespace is null then prefix must be null too or IllegalStateException is thrown.
|
||||
// * <br />If namespace is null then no namespace prefix is printed but just name.
|
||||
// * <br />If namespace is empty string then serializer will make sure that
|
||||
// * default empty namespace is declared (in XML 1.0 xmlns='').
|
||||
// * <p><b>Background:</b> in kXML endTag had no arguments, and non matching tags were
|
||||
// * very difficult to find...</p>
|
||||
// */
|
||||
// ALEK: This is really optional as prefix in end tag MUST correspond to start tag but good for error checking
|
||||
// XmlSerializer endTag (String prefix, String namespace, String name)
|
||||
// throws IOException, IllegalArgumentException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* Writes text, where special XML chars are escaped automatically
|
||||
*/
|
||||
XmlSerializer text(String text)
|
||||
throws IOException, IllegalArgumentException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* Writes text, where special XML chars are escaped automatically
|
||||
*/
|
||||
XmlSerializer text(char[] buf, int start, int len)
|
||||
throws IOException, IllegalArgumentException, IllegalStateException;
|
||||
|
||||
void cdsect(String text)
|
||||
throws IOException, IllegalArgumentException, IllegalStateException;
|
||||
void entityRef(String text) throws IOException,
|
||||
IllegalArgumentException, IllegalStateException;
|
||||
void processingInstruction(String text)
|
||||
throws IOException, IllegalArgumentException, IllegalStateException;
|
||||
void comment(String text)
|
||||
throws IOException, IllegalArgumentException, IllegalStateException;
|
||||
void docdecl(String text)
|
||||
throws IOException, IllegalArgumentException, IllegalStateException;
|
||||
void ignorableWhitespace(String text)
|
||||
throws IOException, IllegalArgumentException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* Write all pending output to the stream.
|
||||
* If method startTag() or attribute() was called then start tag is closed (final >)
|
||||
* before flush() is called on underlying output stream.
|
||||
*
|
||||
* <p><b>NOTE:</b> if there is need to close start tag
|
||||
* (so no more attribute() calls are allowed) but without flushinging output
|
||||
* call method text() with empty string (text("")).
|
||||
*
|
||||
*/
|
||||
void flush()
|
||||
throws IOException;
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -18,7 +18,6 @@ java {
|
|||
|
||||
dependencies {
|
||||
implementation(projects.apkzlib)
|
||||
implementation(projects.axmlprinter)
|
||||
implementation(projects.share.java)
|
||||
|
||||
implementation("commons-io:commons-io:2.11.0")
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
package org.lsposed.patch.util;
|
||||
|
||||
import com.wind.meditor.utils.Utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import wind.android.content.res.AXmlResourceParser;
|
||||
import wind.v1.XmlPullParser;
|
||||
import wind.v1.XmlPullParserException;
|
||||
import pxb.android.axml.AxmlParser;
|
||||
|
||||
/**
|
||||
* Created by Wind
|
||||
|
|
@ -15,40 +15,39 @@ import wind.v1.XmlPullParserException;
|
|||
public class ManifestParser {
|
||||
|
||||
public static Pair parseManifestFile(InputStream is) throws IOException {
|
||||
AXmlResourceParser parser = new AXmlResourceParser();
|
||||
AxmlParser parser = new AxmlParser(Utils.getBytesFromInputStream(is));
|
||||
String packageName = null;
|
||||
String appComponentFactory = null;
|
||||
int minSdkVersion = 0;
|
||||
try {
|
||||
parser.open(is);
|
||||
|
||||
while (true) {
|
||||
int type = parser.next();
|
||||
if (type == XmlPullParser.END_DOCUMENT) {
|
||||
if (type == AxmlParser.END_FILE) {
|
||||
break;
|
||||
}
|
||||
if (type == XmlPullParser.START_TAG) {
|
||||
if (type == AxmlParser.START_TAG) {
|
||||
int attrCount = parser.getAttributeCount();
|
||||
for (int i = 0; i < attrCount; i++) {
|
||||
String attrName = parser.getAttributeName(i);
|
||||
int attrNameRes = parser.getAttributeNameResource(i);
|
||||
String attrName = parser.getAttrName(i);
|
||||
int attrNameRes = parser.getAttrResId(i);
|
||||
|
||||
String name = parser.getName();
|
||||
|
||||
if ("manifest".equals(name)) {
|
||||
if ("package".equals(attrName)) {
|
||||
packageName = parser.getAttributeValue(i);
|
||||
packageName = parser.getAttrValue(i).toString();
|
||||
}
|
||||
}
|
||||
|
||||
if ("uses-sdk".equals(name)) {
|
||||
if ("android:minSdkVersion".equals(attrName)) {
|
||||
minSdkVersion = Integer.parseInt(parser.getAttributeValue(i));
|
||||
if ("minSdkVersion".equals(attrName)) {
|
||||
minSdkVersion = Integer.parseInt(parser.getAttrValue(i).toString());
|
||||
}
|
||||
}
|
||||
|
||||
if ("appComponentFactory".equals(attrName) || attrNameRes == 0x0101057a) {
|
||||
appComponentFactory = parser.getAttributeValue(i);
|
||||
appComponentFactory = parser.getAttrValue(i).toString();
|
||||
}
|
||||
|
||||
if (packageName != null && packageName.length() > 0 &&
|
||||
|
|
@ -58,13 +57,14 @@ public class ManifestParser {
|
|||
return new Pair(packageName, appComponentFactory, minSdkVersion);
|
||||
}
|
||||
}
|
||||
} else if (type == XmlPullParser.END_TAG) {
|
||||
} else if (type == AxmlParser.END_TAG) {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
} catch (XmlPullParserException | IOException e) {
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Pair(packageName, appComponentFactory, minSdkVersion);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ dependencyResolutionManagement {
|
|||
rootProject.name = "LSPatch"
|
||||
include(
|
||||
":apkzlib",
|
||||
":axmlprinter",
|
||||
":core",
|
||||
":hiddenapi:bridge",
|
||||
":hiddenapi:stubs",
|
||||
|
|
|
|||
Loading…
Reference in New Issue