@Override public String encodeAsResXmlItemValue() { return ResXmlEncoders.enumerateNonPositionalSubstitutionsIfRequired(ResXmlEncoders.encodeAsXmlValue(mRawValue)); }
@Override public String encodeAsResXmlValue() { return ResXmlEncoders.encodeAsXmlValue(mRawValue); }
public boolean hasMultipleNonPositionalSubstitutions() throws AndrolibException { return ResXmlEncoders.hasMultipleNonPositionalSubstitutions(mRawValue); }
/** * Replaces package value with passed packageOriginal string * * @param file File for AndroidManifest.xml * @param packageOriginal Package name to replace * @throws AndrolibException */ public static void renameManifestPackage(File file, String packageOriginal) throws AndrolibException { try { Document doc = loadDocument(file); // Get the manifest line Node manifest = doc.getFirstChild(); // update package attribute NamedNodeMap attr = manifest.getAttributes(); Node nodeAttr = attr.getNamedItem("package"); nodeAttr.setNodeValue(packageOriginal); saveDocument(file, doc); } catch (SAXException | ParserConfigurationException | IOException | TransformerException ignored) { } }
/** * Checks if the replacement was properly made to a node. * * @param file File we are searching for value * @param saved boolean on whether we need to save * @param provider Node we are attempting to replace * @return boolean * @throws AndrolibException setting node value failed */ private static boolean isSaved(File file, boolean saved, Node provider) throws AndrolibException { String reference = provider.getNodeValue(); String replacement = pullValueFromStrings(file.getParentFile(), reference); if (replacement != null) { provider.setNodeValue(replacement); saved = true; } return saved; }
public static boolean hasMultipleNonPositionalSubstitutions(String str) { Duo<List<Integer>, List<Integer>> tuple = findSubstitutions(str, 4); return ! tuple.m1.isEmpty() && tuple.m1.size() + tuple.m2.size() > 1; }
continue; default: if (!isPrintableChar(c)) { out.append(String.format("\\u%04x", (int) c)); continue;
builder.append(ResXmlEncoders.escapeXmlChars(val)).append('"'); } else { loop = false;
@Override public String encodeAsResXmlAttr() { return checkIfStringIsNumeric(ResXmlEncoders.encodeAsResXmlAttr(mRawValue)); }
private void buildManifestFile(File appDir, File manifest, File manifestOriginal) throws AndrolibException { // If we decoded in "raw", we cannot patch AndroidManifest if (new File(appDir, "resources.arsc").exists()) { return; } if (manifest.isFile() && manifest.exists()) { try { if (manifestOriginal.exists()) { manifestOriginal.delete(); } FileUtils.copyFile(manifest, manifestOriginal); ResXmlPatcher.fixingPublicAttrsInProviderAttributes(manifest); } catch (IOException ex) { throw new AndrolibException(ex.getMessage()); } } }
/** * Finds key in strings.xml file and returns text value * * @param directory Root directory of apk * @param key String reference (ie @string/foo) * @return String|null * @throws AndrolibException */ public static String pullValueFromStrings(File directory, String key) throws AndrolibException { if (key == null || ! key.contains("@")) { return null; } File file = new File(directory, "/res/values/strings.xml"); key = key.replace("@string/", ""); if (file.exists()) { try { Document doc = loadDocument(file); XPath xPath = XPathFactory.newInstance().newXPath(); XPathExpression expression = xPath.compile("/resources/string[@name=" + '"' + key + "\"]/text()"); Object result = expression.evaluate(doc, XPathConstants.STRING); if (result != null) { return (String) result; } } catch (SAXException | ParserConfigurationException | IOException | XPathExpressionException ignored) { } } return null; }
@Override public void serializeToResValuesXml(XmlSerializer serializer, ResResource res) throws IOException, AndrolibException { serializer.startTag(null, "plurals"); serializer.attribute(null, "name", res.getResSpec().getName()); for (int i = 0; i < mItems.length; i++) { ResScalarValue item = mItems[i]; if (item == null) { continue; } serializer.startTag(null, "item"); serializer.attribute(null, "quantity", QUANTITY_MAP[i]); serializer.text(ResXmlEncoders.enumerateNonPositionalSubstitutionsIfRequired(item.encodeAsResXmlNonEscapedItemValue())); serializer.endTag(null, "item"); } serializer.endTag(null, "plurals"); }
private void generateValuesFile(ResValuesFile valuesFile, Directory out, ExtXmlSerializer serial) throws AndrolibException { try { OutputStream outStream = out.getFileOutput(valuesFile.getPath()); serial.setOutput((outStream), null); serial.startDocument(null, null); serial.startTag(null, "resources"); for (ResResource res : valuesFile.listResources()) { if (valuesFile.isSynthesized(res)) { continue; } ((ResValuesXmlSerializable) res.getValue()).serializeToResValuesXml(serial, res); } serial.endTag(null, "resources"); serial.newLine(); serial.endDocument(); serial.flush(); outStream.close(); } catch (IOException | DirectoryException ex) { throw new AndrolibException("Could not generate: " + valuesFile.getPath(), ex); } }
/** * Removes "debug" tag from file * * @param file AndroidManifest file * @throws AndrolibException */ public static void removeApplicationDebugTag(File file) throws AndrolibException { if (file.exists()) { try { Document doc = loadDocument(file); Node application = doc.getElementsByTagName("application").item(0); // load attr NamedNodeMap attr = application.getAttributes(); Node debugAttr = attr.getNamedItem("android:debuggable"); // remove application:debuggable if (debugAttr != null) { attr.removeNamedItem("android:debuggable"); } saveDocument(file, doc); } catch (SAXException | ParserConfigurationException | IOException | TransformerException ignored) { } } }
private void putVersionInfo(MetaInfo meta) throws AndrolibException { VersionInfo info = getResTable().getVersionInfo(); String refValue = ResXmlPatcher.pullValueFromStrings(mOutDir, info.versionName); if (refValue != null) { info.versionName = refValue; } meta.versionInfo = info; }
@Override protected void serializeExtraXmlAttrs(XmlSerializer serializer, ResResource res) throws IOException { if (ResXmlEncoders.hasMultipleNonPositionalSubstitutions(mRawValue)) { serializer.attribute(null, "formatted", "false"); } }
public static String enumerateNonPositionalSubstitutionsIfRequired(String str) { Duo<List<Integer>, List<Integer>> tuple = findSubstitutions(str, 4); if (tuple.m1.isEmpty() || tuple.m1.size() + tuple.m2.size() < 2) { return str; } List<Integer> subs = tuple.m1; StringBuilder out = new StringBuilder(); int pos = 0; int count = 0; for (Integer sub : subs) { out.append(str.substring(pos, ++sub)).append(++count).append('$'); pos = sub; } out.append(str.substring(pos)); return out.toString(); }
if (!isPrintableChar(c)) {
return ResXmlEncoders.escapeXmlChars(raw); return ResXmlEncoders.escapeXmlChars(raw); html.append(ResXmlEncoders.escapeXmlChars(raw.substring(offset, end + 1))); offset = end + 1; html.append(ResXmlEncoders.escapeXmlChars(raw.substring(offset, start))); if (j >= 0 && unclosed.length >= j && unclosed[j]) { if (unclosed.length > (j + 1) && unclosed[j + 1] || unclosed.length == 1) {
/** * Removes attributes like "versionCode" and "versionName" from file. * * @param file File representing AndroidManifest.xml * @throws AndrolibException */ public static void removeManifestVersions(File file) throws AndrolibException { if (file.exists()) { try { Document doc = loadDocument(file); Node manifest = doc.getFirstChild(); NamedNodeMap attr = manifest.getAttributes(); Node vCode = attr.getNamedItem("android:versionCode"); Node vName = attr.getNamedItem("android:versionName"); if (vCode != null) { attr.removeNamedItem("android:versionCode"); } if (vName != null) { attr.removeNamedItem("android:versionName"); } saveDocument(file, doc); } catch (SAXException | ParserConfigurationException | IOException | TransformerException ignored) { } } }