Added ResXmlEncoders class and use it instead of encoding methods in AndrolibResources.

This commit is contained in:
Ryszard Wiśniewski 2011-05-09 11:23:16 +02:00
parent 30add278d5
commit e23bf8e70d
5 changed files with 148 additions and 101 deletions

View File

@ -27,7 +27,6 @@ import brut.androlib.res.util.*;
import brut.common.BrutException;
import brut.directory.*;
import brut.util.*;
import java.awt.event.KeyEvent;
import java.io.*;
import java.util.*;
import java.util.logging.Logger;
@ -485,98 +484,6 @@ final public class AndrolibResources {
}
}
public static String escapeTextForResXml(String value) {
return escapeTextForResXml(value, true);
}
public static String escapeTextForResXml(String value,
boolean escapeChars) {
if (value.isEmpty()) {
return value;
}
if (escapeChars) {
value = escapeCharsForResXml(value);
}
StringBuilder out = new StringBuilder(value.length() + 10);
char[] chars = value.toCharArray();
switch (chars[0]) {
case '@':
case '#':
case '?':
out.append('\\');
}
boolean space = true;
for (char c : chars) {
if (c == ' ') {
if (space) {
out.append("\\u0020");
} else {
out.append(c);
space = true;
}
continue;
}
space = false;
out.append(c);
}
if (space && out.charAt(out.length() - 1) == ' ') {
out.deleteCharAt(out.length() - 1);
out.append("\\u0020");
}
return out.toString();
}
public static String escapeCharsForResXml(String value) {
if (value.isEmpty()) {
return value;
}
StringBuilder out = new StringBuilder(value.length() + 10);
for (char c : value.toCharArray()) {
switch (c) {
case '\\':
case '\'':
out.append('\\');
break;
case '"':
out.append("\\"");
continue;
case '\n':
out.append("\\n");
continue;
case '&':
out.append("&");
continue;
case '<':
out.append("&lt;");
continue;
default:
if (! isPrintableChar(c)) {
out.append(String.format("\\u%04x", (int)c));
continue;
}
}
out.append(c);
}
return out.toString();
}
public static boolean isPrintableChar(char c) {
Character.UnicodeBlock block = Character.UnicodeBlock.of(c);
return ! Character.isISOControl(c)
&& c != KeyEvent.CHAR_UNDEFINED
&& block != null
&& block != Character.UnicodeBlock.SPECIALS;
}
// TODO: dirty static hack. I have to refactor decoding mechanisms.
public static boolean sKeepBroken = false;

View File

@ -17,6 +17,7 @@
package brut.androlib.res.data.value;
import brut.androlib.AndrolibException;
import brut.androlib.res.xml.ResXmlEncoders;
/**
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
@ -33,12 +34,12 @@ public class ResStringValue extends ResScalarValue {
@Override
public String encodeAsResXmlAttr() {
return mRawValue;
return ResXmlEncoders.encodeAsResXmlAttr(mRawValue);
}
@Override
public String encodeAsResXmlValue() {
return mRawValue;
return ResXmlEncoders.encodeAsXmlValue(mRawValue);
}
@Override

View File

@ -23,6 +23,7 @@ import java.io.Reader;
import org.xmlpull.v1.XmlPullParserException;
import android.util.TypedValue;
import brut.androlib.AndrolibException;
import brut.androlib.res.xml.ResXmlEncoders;
import brut.util.ExtDataInput;
import com.mindprod.ledatastream.LEDataInputStream;
import java.util.logging.Level;
@ -312,7 +313,8 @@ public class AXmlResourceParser implements XmlResourceParser {
if (mAttrDecoder != null) {
try {
return mAttrDecoder.decode(valueType, valueData,
valueRaw == -1 ? null : m_strings.getString(valueRaw),
valueRaw == -1 ? null : ResXmlEncoders.escapeXmlChars(
m_strings.getString(valueRaw)),
getAttributeNameResource(index));
} catch (AndrolibException ex) {
setFirstError(ex);

View File

@ -17,6 +17,7 @@
package brut.androlib.res.decoder;
import brut.androlib.res.AndrolibResources;
import brut.androlib.res.xml.ResXmlEncoders;
import brut.util.ExtDataInput;
import java.io.IOException;
import java.nio.ByteBuffer;
@ -126,7 +127,7 @@ public class StringBlock {
}
int[] style = getStyle(index);
if (style == null) {
return AndrolibResources.escapeTextForResXml(raw);
return ResXmlEncoders.escapeXmlChars(raw);
}
StringBuilder html = new StringBuilder(raw.length() + 32);
int[] opened = new int[style.length / 3];
@ -149,7 +150,7 @@ public class StringBlock {
break;
}
if (offset <= end) {
html.append(AndrolibResources.escapeCharsForResXml(
html.append(ResXmlEncoders.escapeXmlChars(
raw.substring(offset, end + 1)));
offset = end + 1;
}
@ -157,7 +158,7 @@ public class StringBlock {
}
depth = j + 1;
if (offset < start) {
html.append(AndrolibResources.escapeCharsForResXml(
html.append(ResXmlEncoders.escapeXmlChars(
raw.substring(offset, start)));
offset = start;
}
@ -168,7 +169,7 @@ public class StringBlock {
style[i + 1] = -1;
opened[depth++] = i;
}
return AndrolibResources.escapeTextForResXml(html.toString(), false);
return html.toString();
}
private void outputStyleTag(String tag, StringBuilder builder,
@ -199,7 +200,7 @@ public class StringBlock {
val = tag.substring(pos2 + 1);
}
builder.append(AndrolibResources.escapeCharsForResXml(val))
builder.append(ResXmlEncoders.escapeXmlChars(val))
.append('"');
}
}

View File

@ -0,0 +1,136 @@
/**
* Copyright 2011 Ryszard Wiśniewski <brut.alll@gmail.com>
*
* 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 brut.androlib.res.xml;
import java.awt.event.KeyEvent;
/**
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
*/
public final class ResXmlEncoders {
public static String escapeXmlChars(String str) {
return str.replace("&", "&amp;").replace("<", "&lt;");
}
public static String encodeAsResXmlAttr(String str) {
if (str.isEmpty()) {
return str;
}
char[] chars = str.toCharArray();
StringBuilder out = new StringBuilder(str.length() + 10);
switch (chars[0]) {
case '#':
case '@':
case '?':
out.append('\\');
}
for (char c : chars) {
switch (c) {
case '\\':
out.append('\\');
break;
case '"':
out.append("&quot;");
continue;
case '\n':
out.append("\\n");
continue;
default:
if (!isPrintableChar(c)) {
out.append(String.format("\\u%04x", (int) c));
continue;
}
}
out.append(c);
}
return out.toString();
}
public static String encodeAsXmlValue(String str) {
if (str.isEmpty()) {
return str;
}
char[] chars = str.toCharArray();
StringBuilder out = new StringBuilder(str.length() + 10);
switch (chars[0]) {
case '#':
case '@':
case '?':
out.append('\\');
}
boolean isInStyleTag = false;
boolean enclose = false;
boolean wasSpace = true;
for (char c : chars) {
if (isInStyleTag) {
if (c == '>') {
isInStyleTag = false;
}
} else if (c == ' ') {
if (wasSpace) {
enclose = true;
}
wasSpace = true;
} else {
wasSpace = false;
switch (c) {
case '\\':
out.append('\\');
break;
case '\'':
case '\n':
enclose = true;
break;
case '"':
out.append('\\');
break;
case '<':
isInStyleTag = true;
break;
default:
if (!isPrintableChar(c)) {
out.append(String.format("\\u%04x", (int) c));
continue;
}
}
}
out.append(c);
}
if (enclose || wasSpace) {
out.insert(0, '"').append('"');
}
return out.toString();
}
private static boolean isPrintableChar(char c) {
Character.UnicodeBlock block = Character.UnicodeBlock.of(c);
return !Character.isISOControl(c)
&& c != KeyEvent.CHAR_UNDEFINED
&& block != null
&& block != Character.UnicodeBlock.SPECIALS;
}
}