com.android.resources.aar.ProtoStyledStringDecoder Maven / Gradle / Ivy
The newest version!
/*
* Copyright (C) 2018 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.resources.aar;
import com.android.aapt.Resources;
import com.android.utils.XmlUtils;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
/**
* Static methods for converting {@link Resources.StyledString} proto message back to the original XML string.
*/
class ProtoStyledStringDecoder {
/**
* Decodes the given {@link Resources.StyledString} proto message to obtain the original XML string.
*
* @param styledStringMsg the proto message to decode
* @return the original XML string
*/
@NotNull
public static String getRawXmlValue(@NotNull Resources.StyledString styledStringMsg) {
String text = styledStringMsg.getValue();
StringBuilder xmlValue = new StringBuilder(text.length() * 2);
List spanList = styledStringMsg.getSpanList();
List spanStack = new ArrayList<>(spanList.size());
int offset = 0;
for (int i = 0; i <= styledStringMsg.getSpanCount(); i++) {
int oldOffset = offset;
Resources.StyledString.Span spanMsg;
if (i < styledStringMsg.getSpanCount()) {
spanMsg = styledStringMsg.getSpan(i);
offset = spanMsg.getFirstChar();
} else {
spanMsg = null;
offset = text.length();
}
// Check if there are any tags that need to be closed.
while (!spanStack.isEmpty() && spanStack.get(spanStack.size() - 1).getLastChar() < offset) {
Resources.StyledString.Span span = spanStack.remove(spanStack.size() - 1);
int spanEnd = span.getLastChar() + 1;
if (spanEnd > oldOffset) {
XmlUtils.appendXmlTextValue(xmlValue, text, oldOffset, spanEnd);
oldOffset = spanEnd;
}
String tagText = span.getTag();
int tagEnd = indexOfOrEnd(tagText, ';', 0);
// Write the closing tag.
xmlValue.append("").append(tagText, 0, tagEnd).append('>');
}
if (offset >= oldOffset) {
// Copy text between tags.
XmlUtils.appendXmlTextValue(xmlValue, text, oldOffset, offset);
// Start a new tag.
if (spanMsg != null) {
String tagText = spanMsg.getTag();
int pos = indexOfOrEnd(tagText, ';', 0);
if (pos != 0) {
spanStack.add(spanMsg);
xmlValue.append('<').append(tagText, 0, pos);
while (pos < tagText.length()) {
pos++;
int nextPos = indexOfOrEnd(tagText, ';', pos);
int nameEnd = tagText.indexOf('=', pos);
if (nameEnd > pos && nameEnd < nextPos) {
xmlValue.append(' ');
xmlValue.append(tagText, pos, nameEnd + 1);
xmlValue.append('"');
// Attribute values in the proto message are not escaped. Append with escaping.
XmlUtils.appendXmlAttributeValue(xmlValue, tagText, nameEnd + 1, nextPos);
xmlValue.append('"');
}
pos = nextPos;
}
xmlValue.append('>');
}
}
}
}
return xmlValue.toString();
}
private static int indexOfOrEnd(@NotNull String str, char ch, int fromIndex) {
int index = str.indexOf(ch, fromIndex);
return index >= 0 ? index : str.length();
}
/** Do not instantiate. All methods are static. */
private ProtoStyledStringDecoder() {}
}