1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.commands.abx; 18 19 import android.util.Xml; 20 21 import org.xmlpull.v1.XmlPullParser; 22 import org.xmlpull.v1.XmlSerializer; 23 24 import java.io.File; 25 import java.io.FileInputStream; 26 import java.io.FileOutputStream; 27 import java.io.IOException; 28 import java.io.InputStream; 29 import java.io.OutputStream; 30 import java.nio.charset.StandardCharsets; 31 32 /** 33 * Utility that offers to convert between human-readable XML and a custom binary 34 * XML protocol. 35 * 36 * @see Xml#newSerializer() 37 * @see Xml#newBinarySerializer() 38 */ 39 public class Abx { 40 private static final String USAGE = "" + 41 "usage: abx2xml [-i] input [output]\n" + 42 "usage: xml2abx [-i] input [output]\n\n" + 43 "Converts between human-readable XML and Android Binary XML.\n\n" + 44 "When invoked with the '-i' argument, the output of a successful conversion\n" + 45 "will overwrite the original input file. Input can be '-' to use stdin, and\n" + 46 "output can be '-' to use stdout.\n"; 47 openInput(String arg)48 private static InputStream openInput(String arg) throws IOException { 49 if ("-".equals(arg)) { 50 return System.in; 51 } else { 52 return new FileInputStream(arg); 53 } 54 } 55 openOutput(String arg)56 private static OutputStream openOutput(String arg) throws IOException { 57 if ("-".equals(arg)) { 58 return System.out; 59 } else { 60 return new FileOutputStream(arg); 61 } 62 } 63 mainInternal(String[] args)64 private static void mainInternal(String[] args) { 65 if (args.length < 2) { 66 throw new IllegalArgumentException("Missing arguments"); 67 } 68 69 final XmlPullParser in; 70 final XmlSerializer out; 71 if (args[0].endsWith("abx2xml")) { 72 in = Xml.newBinaryPullParser(); 73 out = Xml.newSerializer(); 74 } else if (args[0].endsWith("xml2abx")) { 75 in = Xml.newPullParser(); 76 out = Xml.newBinarySerializer(); 77 } else { 78 throw new IllegalArgumentException("Unsupported conversion"); 79 } 80 81 final boolean inPlace = "-i".equals(args[1]); 82 final String inputArg = inPlace ? args[2] : args[1]; 83 final String outputArg = inPlace ? args[2] + ".tmp" : args[2]; 84 85 try (InputStream is = openInput(inputArg); 86 OutputStream os = openOutput(outputArg)) { 87 in.setInput(is, StandardCharsets.UTF_8.name()); 88 out.setOutput(os, StandardCharsets.UTF_8.name()); 89 out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); 90 Xml.copy(in, out); 91 out.flush(); 92 } catch (Exception e) { 93 // Clean up failed output before throwing 94 if (inPlace) { 95 new File(outputArg).delete(); 96 } 97 throw new IllegalStateException(e); 98 } 99 100 // Successful in-place conversion of a file requires a rename 101 if (inPlace) { 102 if (!new File(outputArg).renameTo(new File(inputArg))) { 103 throw new IllegalStateException("Failed rename"); 104 } 105 } 106 } 107 main(String[] args)108 public static void main(String[] args) { 109 try { 110 mainInternal(args); 111 System.exit(0); 112 } catch (Exception e) { 113 System.err.println(e.toString()); 114 System.err.println(); 115 System.err.println(USAGE); 116 System.exit(1); 117 } 118 } 119 } 120