112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden/*
212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * Copyright (C) 2009 The Android Open Source Project
312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden *
412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * Licensed under the Apache License, Version 2.0 (the "License");
512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * you may not use this file except in compliance with the License.
612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * You may obtain a copy of the License at
712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden *
812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden *      http://www.apache.org/licenses/LICENSE-2.0
912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden *
1012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * Unless required by applicable law or agreed to in writing, software
1112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * distributed under the License is distributed on an "AS IS" BASIS,
1212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * See the License for the specific language governing permissions and
1412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * limitations under the License.
1512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden */
1612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
1712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFaddenpackage com.android.dexdeps;
1812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
1912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFaddenimport java.io.File;
2012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFaddenimport java.io.FileNotFoundException;
2112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFaddenimport java.io.IOException;
2212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFaddenimport java.io.InputStream;
2312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFaddenimport java.io.RandomAccessFile;
2412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFaddenimport java.util.zip.ZipEntry;
2512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFaddenimport java.util.zip.ZipException;
2612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFaddenimport java.util.zip.ZipFile;
2712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFaddenimport java.util.zip.ZipInputStream;
2838e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstromimport java.util.ArrayList;
2938e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstromimport java.util.Collections;
3038e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstromimport java.util.List;
3112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
3212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFaddenpublic class Main {
3306d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein    private String[] mInputFileNames;
3400da1fe5d42693f2bcf5351a459db1fb32b9ca9cAndy McFadden    private String mOutputFormat = "xml";
3512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
3612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
3706d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein     * whether to only emit info about classes used; when {@code false},
3806d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein     * info about fields and methods is also emitted
3906d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein     */
4006d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein    private boolean mJustClasses = false;
4106d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein
4206d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein    /**
4312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Entry point.
4412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
4512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    public static void main(String[] args) {
4612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        Main main = new Main();
4712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        main.run(args);
4812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
4912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
5012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
5112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Start things up.
5212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
5312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    void run(String[] args) {
5412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        try {
5512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            parseArgs(args);
5606d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein            boolean first = true;
5706d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein
5806d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein            for (String fileName : mInputFileNames) {
5906d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein                if (first) {
6006d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein                    first = false;
6106d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein                    Output.generateFirstHeader(fileName, mOutputFormat);
6206d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein                } else {
6306d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein                    Output.generateHeader(fileName, mOutputFormat);
6406d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein                }
6538e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom                List<RandomAccessFile> rafs = openInputFiles(fileName);
6638e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom                for (RandomAccessFile raf : rafs) {
6738e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom                    DexData dexData = new DexData(raf);
6838e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom                    dexData.load();
6938e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom                    Output.generate(dexData, mOutputFormat, mJustClasses);
7038e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom                    raf.close();
7138e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom                }
7206d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein                Output.generateFooter(mOutputFormat);
7306d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein            }
7412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        } catch (UsageException ue) {
7512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            usage();
7612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            System.exit(2);
7712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        } catch (IOException ioe) {
7806d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein            if (ioe.getMessage() != null) {
79753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden                System.err.println("Failed: " + ioe);
8006d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein            }
8112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            System.exit(1);
8212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        } catch (DexDataException dde) {
8312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            /* a message was already reported, just bail quietly */
8412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            System.exit(1);
8512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
8612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
8712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
8812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
8906d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein     * Opens an input file, which could be a .dex or a .jar/.apk with a
9012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * classes.dex inside.  If the latter, we extract the contents to a
9112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * temporary file.
9206d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein     *
9306d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein     * @param fileName the name of the file to open
9412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
9538e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom    List<RandomAccessFile> openInputFiles(String fileName) throws IOException {
9638e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom        List<RandomAccessFile> rafs = openInputFileAsZip(fileName);
9712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
9838e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom        if (rafs == null) {
9906d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein            File inputFile = new File(fileName);
10038e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom            RandomAccessFile raf = new RandomAccessFile(inputFile, "r");
10138e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom            rafs = Collections.singletonList(raf);
10212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
10312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
10438e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom        return rafs;
10512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
10612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
10712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
10838e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom     * Tries to open an input file as a Zip archive (jar/apk) with dex files inside.
10912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     *
11006d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein     * @param fileName the name of the file to open
11138e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom     * @return a list of RandomAccessFile for classes.dex,
11238e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom     *         classes2.dex, etc., or null if the input file is not a
11338e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom     *         zip archive
11412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * @throws IOException if the file isn't found, or it's a zip and
11538e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom     *         no classes.dex isn't found inside
11612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
11738e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom    List<RandomAccessFile> openInputFileAsZip(String fileName) throws IOException {
11812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        /*
11912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden         * Try it as a zip file.
12012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden         */
12138e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom        ZipFile zipFile;
12212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        try {
12306d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein            zipFile = new ZipFile(fileName);
12412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        } catch (FileNotFoundException fnfe) {
12512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            /* not found, no point in retrying as non-zip */
12606d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein            System.err.println("Unable to open '" + fileName + "': " +
12712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                fnfe.getMessage());
12812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            throw fnfe;
12912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        } catch (ZipException ze) {
13012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            /* not a zip */
13112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            return null;
13212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
13312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
13438e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom        List<RandomAccessFile> result = new ArrayList<RandomAccessFile>();
13538e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom        try {
13638e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom            int classesDexNumber = 1;
13738e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom            while (true) {
13838e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom                result.add(openClassesDexZipFileEntry(zipFile, classesDexNumber));
13938e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom                classesDexNumber++;
14038e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom            }
14138e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom        } catch (IOException ioe) {
14238e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom            // We didn't find any of the expected dex files in the zip.
14338e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom            if (result.isEmpty()) {
14438e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom                throw ioe;
14538e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom            }
14638e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom            return result;
14738e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom        }
14838e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom    }
14938e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom
15038e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom    RandomAccessFile openClassesDexZipFileEntry(ZipFile zipFile, int classesDexNumber)
15138e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom            throws IOException {
15212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        /*
15312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden         * We know it's a zip; see if there's anything useful inside.  A
15412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden         * failure here results in some type of IOException (of which
15512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden         * ZipException is a subclass).
15612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden         */
15738e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom        String zipEntryName = ("classes" +
15838e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom                               (classesDexNumber == 1 ? "" : classesDexNumber) +
15938e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom                               ".dex");
16038e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom        ZipEntry entry = zipFile.getEntry(zipEntryName);
16112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        if (entry == null) {
16212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            zipFile.close();
16338e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom            throw new ZipException("Unable to find '" + zipEntryName +
16438e91254a9c5bf51055fc36ac79f4d5dccccc855Brian Carlstrom                "' in '" + zipFile.getName() + "'");
16512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
16612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
16712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        InputStream zis = zipFile.getInputStream(entry);
16812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
16912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        /*
17012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden         * Create a temp file to hold the DEX data, open it, and delete it
17112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden         * to ensure it doesn't hang around if we fail.
17212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden         */
17312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        File tempFile = File.createTempFile("dexdeps", ".dex");
174753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden        //System.out.println("+++ using temp " + tempFile);
17512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        RandomAccessFile raf = new RandomAccessFile(tempFile, "rw");
17612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        tempFile.delete();
17712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
17812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        /*
17912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden         * Copy all data from input stream to output file.
18012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden         */
18112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        byte copyBuf[] = new byte[32768];
18212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        int actual;
18312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
18412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        while (true) {
18512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            actual = zis.read(copyBuf);
18612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            if (actual == -1)
18712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                break;
18812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
18912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            raf.write(copyBuf, 0, actual);
19012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
19112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
19212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        zis.close();
19312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        raf.seek(0);
19412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
19512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        return raf;
19612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
19712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
19812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
19912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
20012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Parses command-line arguments.
20112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     *
20212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * @throws UsageException if arguments are missing or poorly formed
20312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
20412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    void parseArgs(String[] args) {
20512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        int idx;
20612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
20712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        for (idx = 0; idx < args.length; idx++) {
20812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            String arg = args[idx];
20912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
21012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            if (arg.equals("--") || !arg.startsWith("--")) {
21112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                break;
21212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            } else if (arg.startsWith("--format=")) {
21312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                mOutputFormat = arg.substring(arg.indexOf('=') + 1);
21412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                if (!mOutputFormat.equals("brief") &&
21512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                    !mOutputFormat.equals("xml"))
21612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                {
21712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                    System.err.println("Unknown format '" + mOutputFormat +"'");
21812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                    throw new UsageException();
21912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                }
220753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden                //System.out.println("+++ using format " + mOutputFormat);
22106d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein            } else if (arg.equals("--just-classes")) {
22206d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein                mJustClasses = true;
22312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            } else {
22412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                System.err.println("Unknown option '" + arg + "'");
22512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden                throw new UsageException();
22612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            }
22712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
22812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
22906d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein        // We expect at least one more argument (file name).
23006d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein        int fileCount = args.length - idx;
23106d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein        if (fileCount == 0) {
23212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden            throw new UsageException();
23312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden        }
23412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
23506d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein        mInputFileNames = new String[fileCount];
23606d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein        System.arraycopy(args, idx, mInputFileNames, 0, fileCount);
23712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
23812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden
23912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    /**
24012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     * Prints command-line usage info.
24112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden     */
24212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    void usage() {
24306d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein        System.err.print(
24406d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein                "DEX dependency scanner v1.2\n" +
24506d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein                "Copyright (C) 2009 The Android Open Source Project\n\n" +
24606d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein                "Usage: dexdeps [options] <file.{dex,apk,jar}> ...\n" +
24706d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein                "Options:\n" +
24806d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein                "  --format={xml,brief}\n" +
24906d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein                "  --just-classes\n");
25012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden    }
25112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden}
252