/* * Copyright (C) 2020 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.commands.abx; import android.util.Xml; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlSerializer; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.StandardCharsets; /** * Utility that offers to convert between human-readable XML and a custom binary * XML protocol. * * @see Xml#newSerializer() * @see Xml#newBinarySerializer() */ public class Abx { private static final String USAGE = "" + "usage: abx2xml [-i] input [output]\n" + "usage: xml2abx [-i] input [output]\n\n" + "Converts between human-readable XML and Android Binary XML.\n\n" + "When invoked with the '-i' argument, the output of a successful conversion\n" + "will overwrite the original input file. Input can be '-' to use stdin, and\n" + "output can be '-' to use stdout.\n"; private static InputStream openInput(String arg) throws IOException { if ("-".equals(arg)) { return System.in; } else { return new FileInputStream(arg); } } private static OutputStream openOutput(String arg) throws IOException { if ("-".equals(arg)) { return System.out; } else { return new FileOutputStream(arg); } } private static void mainInternal(String[] args) { if (args.length < 2) { throw new IllegalArgumentException("Missing arguments"); } final XmlPullParser in; final XmlSerializer out; if (args[0].endsWith("abx2xml")) { in = Xml.newBinaryPullParser(); out = Xml.newSerializer(); } else if (args[0].endsWith("xml2abx")) { in = Xml.newPullParser(); out = Xml.newBinarySerializer(); } else { throw new IllegalArgumentException("Unsupported conversion"); } final boolean inPlace = "-i".equals(args[1]); final String inputArg = inPlace ? args[2] : args[1]; final String outputArg = inPlace ? args[2] + ".tmp" : args[2]; try (InputStream is = openInput(inputArg); OutputStream os = openOutput(outputArg)) { in.setInput(is, StandardCharsets.UTF_8.name()); out.setOutput(os, StandardCharsets.UTF_8.name()); out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); Xml.copy(in, out); out.flush(); } catch (Exception e) { // Clean up failed output before throwing if (inPlace) { new File(outputArg).delete(); } throw new IllegalStateException(e); } // Successful in-place conversion of a file requires a rename if (inPlace) { if (!new File(outputArg).renameTo(new File(inputArg))) { throw new IllegalStateException("Failed rename"); } } } public static void main(String[] args) { try { mainInternal(args); System.exit(0); } catch (Exception e) { System.err.println(e.toString()); System.err.println(); System.err.println(USAGE); System.exit(1); } } }