blob: 936808d16ca9cd781de19fc280e50228668465d1 [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* 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 com.android.ide.common.resources;
import com.android.ide.common.rendering.api.AttrResourceValue;
import com.android.ide.common.rendering.api.DeclareStyleableResourceValue;
import com.android.ide.common.rendering.api.ItemResourceValue;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.ide.common.rendering.api.StyleResourceValue;
import com.android.ide.common.res2.ValueXmlHelper;
import com.android.resources.ResourceType;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* SAX handler to parse value resource files.
*/
public final class ValueResourceParser extends DefaultHandler {
// TODO: reuse definitions from somewhere else.
private static final String NODE_RESOURCES = "resources";
private static final String NODE_ITEM = "item";
private static final String ATTR_NAME = "name";
private static final String ATTR_TYPE = "type";
private static final String ATTR_PARENT = "parent";
private static final String ATTR_VALUE = "value";
private static final String DEFAULT_NS_PREFIX = "android:";
private static final int DEFAULT_NS_PREFIX_LEN = DEFAULT_NS_PREFIX.length();
public interface IValueResourceRepository {
void addResourceValue(ResourceValue value);
boolean hasResourceValue(ResourceType type, String name);
}
private boolean inResources = false;
private int mDepth = 0;
private ResourceValue mCurrentValue = null;
private StyleResourceValue mCurrentStyle = null;
private DeclareStyleableResourceValue mCurrentDeclareStyleable = null;
private AttrResourceValue mCurrentAttr;
private IValueResourceRepository mRepository;
private final boolean mIsFramework;
public ValueResourceParser(IValueResourceRepository repository, boolean isFramework) {
mRepository = repository;
mIsFramework = isFramework;
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (mCurrentValue != null) {
String value = mCurrentValue.getValue();
value = value == null ? "" : ValueXmlHelper.unescapeResourceString(value, false, true);
mCurrentValue.setValue(value);
}
if (inResources && qName.equals(NODE_RESOURCES)) {
inResources = false;
} else if (mDepth == 2) {
mCurrentValue = null;
mCurrentStyle = null;
mCurrentDeclareStyleable = null;
mCurrentAttr = null;
} else if (mDepth == 3) {
mCurrentValue = null;
if (mCurrentDeclareStyleable != null) {
mCurrentAttr = null;
}
}
mDepth--;
super.endElement(uri, localName, qName);
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
try {
mDepth++;
if (inResources == false && mDepth == 1) {
if (qName.equals(NODE_RESOURCES)) {
inResources = true;
}
} else if (mDepth == 2 && inResources == true) {
ResourceType type = getType(qName, attributes);
if (type != null) {
// get the resource name
String name = attributes.getValue(ATTR_NAME);
if (name != null) {
switch (type) {
case STYLE:
String parent = attributes.getValue(ATTR_PARENT);
mCurrentStyle = new StyleResourceValue(type, name, parent,
mIsFramework);
mRepository.addResourceValue(mCurrentStyle);
break;
case DECLARE_STYLEABLE:
mCurrentDeclareStyleable = new DeclareStyleableResourceValue(
type, name, mIsFramework);
mRepository.addResourceValue(mCurrentDeclareStyleable);
break;
case ATTR:
mCurrentAttr = new AttrResourceValue(type, name, mIsFramework);
mRepository.addResourceValue(mCurrentAttr);
break;
default:
mCurrentValue = new ResourceValue(type, name, mIsFramework);
mRepository.addResourceValue(mCurrentValue);
break;
}
}
}
} else if (mDepth == 3) {
// get the resource name
String name = attributes.getValue(ATTR_NAME);
if (name != null) {
if (mCurrentStyle != null) {
// is the attribute in the android namespace?
boolean isFrameworkAttr = mIsFramework;
if (name.startsWith(DEFAULT_NS_PREFIX)) {
name = name.substring(DEFAULT_NS_PREFIX_LEN);
isFrameworkAttr = true;
}
mCurrentValue = new ItemResourceValue(name, isFrameworkAttr, mIsFramework);
mCurrentStyle.addItem((ItemResourceValue)mCurrentValue);
} else if (mCurrentDeclareStyleable != null) {
// is the attribute in the android namespace?
boolean isFramework = mIsFramework;
if (name.startsWith(DEFAULT_NS_PREFIX)) {
name = name.substring(DEFAULT_NS_PREFIX_LEN);
isFramework = true;
}
mCurrentAttr = new AttrResourceValue(ResourceType.ATTR, name, isFramework);
mCurrentDeclareStyleable.addValue(mCurrentAttr);
// also add it to the repository.
mRepository.addResourceValue(mCurrentAttr);
} else if (mCurrentAttr != null) {
// get the enum/flag value
String value = attributes.getValue(ATTR_VALUE);
try {
// Integer.decode/parseInt can't deal with hex value > 0x7FFFFFFF so we
// use Long.decode instead.
mCurrentAttr.addValue(name, (int)(long)Long.decode(value));
} catch (NumberFormatException e) {
// pass, we'll just ignore this value
}
}
}
} else if (mDepth == 4 && mCurrentAttr != null) {
// get the enum/flag name
String name = attributes.getValue(ATTR_NAME);
String value = attributes.getValue(ATTR_VALUE);
try {
// Integer.decode/parseInt can't deal with hex value > 0x7FFFFFFF so we
// use Long.decode instead.
mCurrentAttr.addValue(name, (int)(long)Long.decode(value));
} catch (NumberFormatException e) {
// pass, we'll just ignore this value
}
}
} finally {
super.startElement(uri, localName, qName, attributes);
}
}
private ResourceType getType(String qName, Attributes attributes) {
String typeValue;
// if the node is <item>, we get the type from the attribute "type"
if (NODE_ITEM.equals(qName)) {
typeValue = attributes.getValue(ATTR_TYPE);
} else {
// the type is the name of the node.
typeValue = qName;
}
ResourceType type = ResourceType.getEnum(typeValue);
return type;
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if (mCurrentValue != null) {
String value = mCurrentValue.getValue();
if (value == null) {
mCurrentValue.setValue(new String(ch, start, length));
} else {
mCurrentValue.setValue(value + new String(ch, start, length));
}
}
}
}