package jadx.core.xmlgen; import jadx.core.codegen.CodeWriter; import jadx.core.utils.StringUtils; import jadx.core.xmlgen.entry.RawNamedValue; import jadx.core.xmlgen.entry.ResourceEntry; import jadx.core.xmlgen.entry.ValuesParser; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ResXmlGen { private static final Logger LOG = LoggerFactory.getLogger(ResXmlGen.class); private static final Set<String> SKIP_RES_TYPES = new HashSet<String>(Arrays.asList( "layout", "mipmap", "id" )); private final ResourceStorage resStorage; private final ValuesParser vp; public ResXmlGen(ResourceStorage resStorage, ValuesParser vp) { this.resStorage = resStorage; this.vp = vp; } public List<ResContainer> makeResourcesXml() { Map<String, CodeWriter> contMap = new HashMap<String, CodeWriter>(); for (ResourceEntry ri : resStorage.getResources()) { if (SKIP_RES_TYPES.contains(ri.getTypeName())) { continue; } String fn = getFileName(ri); CodeWriter cw = contMap.get(fn); if (cw == null) { cw = new CodeWriter(); cw.add("<?xml version=\"1.0\" encoding=\"utf-8\"?>"); cw.startLine("<resources>"); cw.incIndent(); contMap.put(fn, cw); } addValue(cw, ri); } List<ResContainer> files = new ArrayList<ResContainer>(contMap.size()); for (Map.Entry<String, CodeWriter> entry : contMap.entrySet()) { String fileName = entry.getKey(); CodeWriter content = entry.getValue(); content.decIndent(); content.startLine("</resources>"); content.finish(); files.add(ResContainer.singleFile(fileName, content)); } Collections.sort(files); return files; } private void addValue(CodeWriter cw, ResourceEntry ri) { if (ri.getSimpleValue() != null) { String valueStr = vp.decodeValue(ri.getSimpleValue()); addSimpleValue(cw, ri.getTypeName(), "name", ri.getKeyName(), valueStr); } else { cw.startLine(); cw.add('<').add(ri.getTypeName()).add(' '); cw.add("name=\"").add(ri.getKeyName()).add("\">"); cw.incIndent(); for (RawNamedValue value : ri.getNamedValues()) { addItem(cw, value); } cw.decIndent(); cw.startLine().add("</").add(ri.getTypeName()).add('>'); } } private void addItem(CodeWriter cw, RawNamedValue value) { String keyName = null; String keyValue = null; int nameRef = value.getNameRef(); if (ParserConstants.isResInternalId(nameRef)) { keyValue = ParserConstants.PLURALS_MAP.get(nameRef); if (keyValue != null) { keyName = "quantity"; } } String valueStr = vp.decodeValue(value.getRawValue()); addSimpleValue(cw, "item", keyName, keyValue, valueStr); } private void addSimpleValue(CodeWriter cw, String typeName, String attrName, String attrValue, String valueStr) { cw.startLine(); cw.add('<').add(typeName); if (attrName != null && attrValue != null) { cw.add(' ').add(attrName).add("=\"").add(attrValue).add('"'); } cw.add('>'); if (typeName.equals("string")) { cw.add(StringUtils.escapeResStrValue(valueStr)); } else { cw.add(StringUtils.escapeResValue(valueStr)); } cw.add("</").add(typeName).add('>'); } private String getFileName(ResourceEntry ri) { StringBuilder sb = new StringBuilder(); String locale = ri.getConfig().getLocale(); sb.append("res/values"); if (!locale.isEmpty()) { sb.append('-').append(locale); } sb.append('/'); sb.append(ri.getTypeName()); if (!ri.getTypeName().endsWith("s")) { sb.append('s'); } sb.append(".xml"); return sb.toString(); } }