aboutsummaryrefslogtreecommitdiffstats
path: root/layoutlib_utils/src/com/android/ide/common/layoutlib/ValueResourceParser.java
diff options
context:
space:
mode:
Diffstat (limited to 'layoutlib_utils/src/com/android/ide/common/layoutlib/ValueResourceParser.java')
-rw-r--r--layoutlib_utils/src/com/android/ide/common/layoutlib/ValueResourceParser.java227
1 files changed, 227 insertions, 0 deletions
diff --git a/layoutlib_utils/src/com/android/ide/common/layoutlib/ValueResourceParser.java b/layoutlib_utils/src/com/android/ide/common/layoutlib/ValueResourceParser.java
new file mode 100644
index 0000000..c784f1f
--- /dev/null
+++ b/layoutlib_utils/src/com/android/ide/common/layoutlib/ValueResourceParser.java
@@ -0,0 +1,227 @@
+/*
+ * 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.layoutlib;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * SAX handler to parser value resource files.
+ */
+public final class ValueResourceParser extends DefaultHandler {
+
+ // TODO: reuse definitions from somewhere else.
+ private final static String NODE_RESOURCES = "resources";
+ private final static String NODE_ITEM = "item";
+ private final static String ATTR_NAME = "name";
+ private final static String ATTR_TYPE = "type";
+ private final static String ATTR_PARENT = "parent";
+
+ // Resource type definition
+ private final static String RES_STYLE = "style";
+ private final static String RES_ATTR = "attr";
+
+ private final static String DEFAULT_NS_PREFIX = "android:";
+ private final static int DEFAULT_NS_PREFIX_LEN = DEFAULT_NS_PREFIX.length();
+
+ public interface IValueResourceRepository {
+ void addResourceValue(String resType, ResourceValue value);
+ }
+
+ private boolean inResources = false;
+ private int mDepth = 0;
+ private StyleResourceValue mCurrentStyle = null;
+ private ResourceValue mCurrentValue = null;
+ 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) {
+ mCurrentValue.setValue(trimXmlWhitespaces(mCurrentValue.getValue()));
+ }
+
+ if (inResources && qName.equals(NODE_RESOURCES)) {
+ inResources = false;
+ } else if (mDepth == 2) {
+ mCurrentValue = null;
+ mCurrentStyle = null;
+ } else if (mDepth == 3) {
+ mCurrentValue = 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) {
+ String type;
+
+ // if the node is <item>, we get the type from the attribute "type"
+ if (NODE_ITEM.equals(qName)) {
+ type = attributes.getValue(ATTR_TYPE);
+ } else {
+ // the type is the name of the node.
+ type = qName;
+ }
+
+ if (type != null) {
+ if (RES_ATTR.equals(type) == false) {
+ // get the resource name
+ String name = attributes.getValue(ATTR_NAME);
+ if (name != null) {
+ if (RES_STYLE.equals(type)) {
+ String parent = attributes.getValue(ATTR_PARENT);
+ mCurrentStyle = new StyleResourceValue(type, name, parent, mIsFramework);
+ mRepository.addResourceValue(type, mCurrentStyle);
+ } else {
+ mCurrentValue = new ResourceValue(type, name, mIsFramework);
+ mRepository.addResourceValue(type, mCurrentValue);
+ }
+ }
+ }
+ }
+ } else if (mDepth == 3 && mCurrentStyle != null) {
+ // get the resource name
+ String name = attributes.getValue(ATTR_NAME);
+ if (name != null) {
+ // the name can, in some cases, contain a prefix! we remove it.
+ if (name.startsWith(DEFAULT_NS_PREFIX)) {
+ name = name.substring(DEFAULT_NS_PREFIX_LEN);
+ }
+
+ mCurrentValue = new ResourceValue(null, name, mIsFramework);
+ mCurrentStyle.addItem(mCurrentValue);
+ }
+ }
+ } finally {
+ super.startElement(uri, localName, qName, attributes);
+ }
+ }
+
+ @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));
+ }
+ }
+ }
+
+ public static String trimXmlWhitespaces(String value) {
+ if (value == null) {
+ return null;
+ }
+
+ // look for carriage return and replace all whitespace around it by just 1 space.
+ int index;
+
+ while ((index = value.indexOf('\n')) != -1) {
+ // look for whitespace on each side
+ int left = index - 1;
+ while (left >= 0) {
+ if (Character.isWhitespace(value.charAt(left))) {
+ left--;
+ } else {
+ break;
+ }
+ }
+
+ int right = index + 1;
+ int count = value.length();
+ while (right < count) {
+ if (Character.isWhitespace(value.charAt(right))) {
+ right++;
+ } else {
+ break;
+ }
+ }
+
+ // remove all between left and right (non inclusive) and replace by a single space.
+ String leftString = null;
+ if (left >= 0) {
+ leftString = value.substring(0, left + 1);
+ }
+ String rightString = null;
+ if (right < count) {
+ rightString = value.substring(right);
+ }
+
+ if (leftString != null) {
+ value = leftString;
+ if (rightString != null) {
+ value += " " + rightString;
+ }
+ } else {
+ value = rightString != null ? rightString : "";
+ }
+ }
+
+ // now we un-escape the string
+ int length = value.length();
+ char[] buffer = value.toCharArray();
+
+ for (int i = 0 ; i < length ; i++) {
+ if (buffer[i] == '\\' && i + 1 < length) {
+ if (buffer[i+1] == 'u') {
+ if (i + 5 < length) {
+ // this is unicode char \u1234
+ int unicodeChar = Integer.parseInt(new String(buffer, i+2, 4), 16);
+
+ // put the unicode char at the location of the \
+ buffer[i] = (char)unicodeChar;
+
+ // offset the rest of the buffer since we go from 6 to 1 char
+ if (i + 6 < buffer.length) {
+ System.arraycopy(buffer, i+6, buffer, i+1, length - i - 6);
+ }
+ length -= 5;
+ }
+ } else {
+ if (buffer[i+1] == 'n') {
+ // replace the 'n' char with \n
+ buffer[i+1] = '\n';
+ }
+
+ // offset the buffer to erase the \
+ System.arraycopy(buffer, i+1, buffer, i, length - i - 1);
+ length--;
+ }
+ }
+ }
+
+ return new String(buffer, 0, length);
+ }
+}