Added XML output mode for dexdump.

This adds an output mode that looks similar to the "current.xml" we
generate for our public APIs.  There are a number of differences in
content.  The original ("plain") output has not been altered.

I pulled in the bad checksum handling change (internal 142686) since
it's small, has turned out to be useful, and might make the merge of
this to master slightly easier.

This also renames a buffer in the ongoing temp file variable saga.
diff --git a/dexdump/DexDump.c b/dexdump/DexDump.c
index a4d97eb..c5714ea 100644
--- a/dexdump/DexDump.c
+++ b/dexdump/DexDump.c
@@ -13,11 +13,21 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 /*
  * The "dexdump" tool is intended to mimic "objdump".  When possible, use
  * similar command-line arguments.
  *
- * TODO: rework the output format to be more regexp-friendly
+ * TODO: rework the "plain" output format to be more regexp-friendly
+ *
+ * Differences between XML output and the "current.xml" file:
+ * - classes in same package are not all grouped together; generally speaking
+ *   nothing is sorted
+ * - no "deprecated" on fields and methods
+ * - no "value" on fields
+ * - no parameter names
+ * - no generic signatures on parameters, e.g. type="java.lang.Class<?>"
+ * - class shows declared fields and methods; does not show inherited fields
  */
 #include "libdex/DexFile.h"
 #include "libdex/DexCatch.h"
@@ -43,12 +53,21 @@
 static InstructionWidth* gInstrWidth;
 static InstructionFormat* gInstrFormat;
 
+typedef enum OutputFormat {
+    OUTPUT_PLAIN = 0,               /* default */
+    OUTPUT_XML,                     /* fancy */
+} OutputFormat;
+
 /* command-line options */
 struct {
     bool disassemble;
     bool showFileHeaders;
     bool showSectionHeaders;
+    bool ignoreBadChecksum;
+    OutputFormat outputFormat;
     const char* tempFileName;
+    bool exportsOnly;
+    bool verbose;
 } gOptions;
 
 /* basic info about a field or method */
@@ -67,34 +86,134 @@
 }   
 
 /*
- * Return a newly-allocated string for the "dot version" of the class
- * name for the given type descriptor. That is, The initial "L" and
- * final ";" (if any) have been removed and all occurrences of '/'
- * have been changed to '.'.
+ * Converts a single-character primitive type into its human-readable
+ * equivalent.
+ */
+static const char* primitiveTypeLabel(char typeChar)
+{
+    switch (typeChar) {
+    case 'B':   return "byte";
+    case 'C':   return "char";
+    case 'D':   return "double";
+    case 'F':   return "float";
+    case 'I':   return "int";
+    case 'J':   return "long";
+    case 'S':   return "short";
+    case 'V':   return "void";
+    case 'Z':   return "boolean";
+    default:
+                return "UNKNOWN";
+    }
+}
+
+/*
+ * Converts a type descriptor to human-readable "dotted" form.  For
+ * example, "Ljava/lang/String;" becomes "java.lang.String", and
+ * "[I" becomes "int[]".  Also converts '$' to '.', which means this
+ * form can't be converted back to a descriptor.
  */
 static char* descriptorToDot(const char* str)
 {
-    size_t at = strlen(str);
+    int targetLen = strlen(str);
+    int offset = 0;
+    int arrayDepth = 0;
     char* newStr;
 
-    if (str[0] == 'L') {
-        assert(str[at - 1] == ';');
-        at -= 2; /* Two fewer chars to copy. */
-        str++; /* Skip the 'L'. */
+    /* strip leading [s; will be added to end */
+    while (targetLen > 1 && str[offset] == '[') {
+        offset++;
+        targetLen--;
+    }
+    arrayDepth = offset;
+
+    if (targetLen == 1) {
+        /* primitive type */
+        str = primitiveTypeLabel(str[offset]);
+        offset = 0;
+        targetLen = strlen(str);
+    } else {
+        /* account for leading 'L' and trailing ';' */
+        if (targetLen >= 2 && str[offset] == 'L' &&
+            str[offset+targetLen-1] == ';')
+        {
+            targetLen -= 2;
+            offset++;
+        }
     }
 
-    newStr = malloc(at + 1); /* Add one for the '\0'. */
-    newStr[at] = '\0';
+    newStr = malloc(targetLen + arrayDepth * 2 +1);
 
-    while (at > 0) {
-        at--;
-        newStr[at] = (str[at] == '/') ? '.' : str[at];
+    /* copy class name over */
+    int i;
+    for (i = 0; i < targetLen; i++) {
+        char ch = str[offset + i];
+        newStr[i] = (ch == '/' || ch == '$') ? '.' : ch;
+    }
+
+    /* add the appropriate number of brackets for arrays */
+    while (arrayDepth-- > 0) {
+        newStr[i++] = '[';
+        newStr[i++] = ']';
+    }
+    newStr[i] = '\0';
+    assert(i == targetLen + arrayDepth * 2);
+
+    return newStr;
+}
+
+/*
+ * Converts the class name portion of a type descriptor to human-readable
+ * "dotted" form.
+ *
+ * Returns a newly-allocated string.
+ */
+static char* descriptorClassToDot(const char* str)
+{
+    const char* lastSlash;
+    char* newStr;
+    char* cp;
+
+    /* reduce to just the class name, trimming trailing ';' */
+    lastSlash = strrchr(str, '/');
+    if (lastSlash == NULL)
+        lastSlash = str + 1;        /* start past 'L' */
+    else
+        lastSlash++;                /* start past '/' */
+
+    newStr = strdup(lastSlash);
+    newStr[strlen(lastSlash)-1] = '\0';
+    for (cp = newStr; *cp != '\0'; cp++) {
+        if (*cp == '$')
+            *cp = '.';
     }
 
     return newStr;
 }
 
 /*
+ * Returns a quoted string representing the boolean value.
+ */
+static const char* quotedBool(bool val)
+{
+    if (val)
+        return "\"true\"";
+    else
+        return "\"false\"";
+}
+
+static const char* quotedVisibility(u4 accessFlags)
+{
+    if ((accessFlags & ACC_PUBLIC) != 0)
+        return "\"public\"";
+    else if ((accessFlags & ACC_PROTECTED) != 0)
+        return "\"protected\"";
+    else if ((accessFlags & ACC_PRIVATE) != 0)
+        return "\"private\"";
+    else
+        return "\"package\"";
+}
+
+/*
  * Count the number of '1' bits in a word.
  *
  * Having completed this, I'm ready for an interview at Google.
@@ -114,7 +233,6 @@
     return count;
 }
 
-
 /*
  * Flag for use with createAccessFlagStr().
  */
@@ -310,7 +428,7 @@
 }
 
 /*
- * Dump an interface.
+ * Dump an interface that a class declares to implement.
  */
 void dumpInterface(const DexFile* pDexFile, const DexTypeItem* pTypeItem,
     int i)
@@ -318,7 +436,13 @@
     const char* interfaceName =
         dexStringByTypeIdx(pDexFile, pTypeItem->typeIdx);
 
-    printf("    #%d              : '%s'\n", i, interfaceName);
+    if (gOptions.outputFormat == OUTPUT_PLAIN) {
+        printf("    #%d              : '%s'\n", i, interfaceName);
+    } else {
+        char* dotted = descriptorToDot(interfaceName);
+        printf("<implements name=\"%s\">\n</implements>\n", dotted);
+        free(dotted);
+    }
 }
 
 /*
@@ -870,8 +994,14 @@
     const DexMethodId* pMethodId;
     const char* backDescriptor;
     const char* name;
-    char* typeDescriptor;
-    char* accessStr;
+    char* typeDescriptor = NULL;
+    char* accessStr = NULL;
+
+    if (gOptions.exportsOnly &&
+        (pDexMethod->accessFlags & (ACC_PUBLIC | ACC_PROTECTED)) == 0)
+    {
+        return;
+    }
 
     pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
     name = dexStringById(pDexFile, pMethodId->nameIdx);
@@ -882,22 +1012,119 @@
     accessStr = createAccessFlagStr(pDexMethod->accessFlags,
                     kAccessForMethod);
 
-    printf("    #%d              : (in %s)\n", i, backDescriptor);
-    printf("      name          : '%s'\n", name);
-    printf("      type          : '%s'\n", typeDescriptor);
-    printf("      access        : 0x%04x (%s)\n",
-        pDexMethod->accessFlags, accessStr);
+    if (gOptions.outputFormat == OUTPUT_PLAIN) {
+        printf("    #%d              : (in %s)\n", i, backDescriptor);
+        printf("      name          : '%s'\n", name);
+        printf("      type          : '%s'\n", typeDescriptor);
+        printf("      access        : 0x%04x (%s)\n",
+            pDexMethod->accessFlags, accessStr);
 
-    if (pDexMethod->codeOff == 0) {
-        printf("      code          : (none)\n");
-    } else {
-        printf("      code          -\n");
-        dumpCode(pDexFile, pDexMethod);
+        if (pDexMethod->codeOff == 0) {
+            printf("      code          : (none)\n");
+        } else {
+            printf("      code          -\n");
+            dumpCode(pDexFile, pDexMethod);
+        }
+
+        if (gOptions.disassemble)
+            putchar('\n');
+    } else if (gOptions.outputFormat == OUTPUT_XML) {
+        bool constructor = (name[0] == '<');
+
+        if (constructor) {
+            char* tmp;
+
+            tmp = descriptorClassToDot(backDescriptor);
+            printf("<constructor name=\"%s\"\n", tmp);
+            free(tmp);
+
+            tmp = descriptorToDot(backDescriptor);
+            printf(" type=\"%s\"\n", tmp);
+            free(tmp);
+        } else {
+            printf("<method name=\"%s\"\n", name);
+
+            const char* returnType = strrchr(typeDescriptor, ')');
+            if (returnType == NULL) {
+                fprintf(stderr, "bad method type descriptor '%s'\n",
+                    typeDescriptor);
+                goto bail;
+            }
+
+            char* tmp = descriptorToDot(returnType+1);
+            printf(" return=\"%s\"\n", tmp);
+            free(tmp);
+
+            printf(" abstract=%s\n",
+                quotedBool((pDexMethod->accessFlags & ACC_ABSTRACT) != 0));
+            printf(" native=%s\n",
+                quotedBool((pDexMethod->accessFlags & ACC_NATIVE) != 0));
+
+            bool isSync =
+                (pDexMethod->accessFlags & ACC_SYNCHRONIZED) != 0 ||
+                (pDexMethod->accessFlags & ACC_DECLARED_SYNCHRONIZED) != 0;
+            printf(" synchronized=%s\n", quotedBool(isSync));
+        }
+
+        printf(" static=%s\n",
+            quotedBool((pDexMethod->accessFlags & ACC_STATIC) != 0));
+        printf(" final=%s\n",
+            quotedBool((pDexMethod->accessFlags & ACC_FINAL) != 0));
+        // "deprecated=" not knowable w/o parsing annotations
+        printf(" visibility=%s\n",
+            quotedVisibility(pDexMethod->accessFlags));
+
+        printf(">\n");
+
+        /*
+         * Parameters.
+         */
+        if (typeDescriptor[0] != '(') {
+            fprintf(stderr, "ERROR: bad descriptor '%s'\n", typeDescriptor);
+            goto bail;
+        }
+
+        char tmpBuf[strlen(typeDescriptor)+1];      /* more than big enough */
+        int argNum = 0;
+
+        const char* base = typeDescriptor+1;
+
+        while (*base != ')') {
+            char* cp = tmpBuf;
+
+            while (*base == '[')
+                *cp++ = *base++;
+
+            if (*base == 'L') {
+                /* copy through ';' */
+                do {
+                    *cp = *base++;
+                } while (*cp++ != ';');
+            } else {
+                /* primitive char, copy it */
+                if (strchr("ZBCSIFJD", *base) == NULL) {
+                    fprintf(stderr, "ERROR: bad method signature '%s'\n", base);
+                    goto bail;
+                }
+                *cp++ = *base++;
+            }
+
+            /* null terminate and display */
+            *cp++ = '\0';
+
+            char* tmp = descriptorToDot(tmpBuf);
+            printf("<parameter name=\"arg%d\" type=\"%s\">\n</parameter>\n",
+                argNum++, tmp);
+            free(tmp);
+        }
+
+        if (constructor)
+            printf("</constructor>\n");
+        else
+            printf("</method>\n");
     }
 
-    if (gOptions.disassemble)
-        putchar('\n');
-
+bail:
     free(typeDescriptor);
     free(accessStr);
 }
@@ -913,6 +1140,12 @@
     const char* typeDescriptor;
     char* accessStr;
 
+    if (gOptions.exportsOnly &&
+        (pSField->accessFlags & (ACC_PUBLIC | ACC_PROTECTED)) == 0)
+    {
+        return;
+    }
+
     pFieldId = dexGetFieldId(pDexFile, pSField->fieldIdx);
     name = dexStringById(pDexFile, pFieldId->nameIdx);
     typeDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
@@ -920,11 +1153,35 @@
 
     accessStr = createAccessFlagStr(pSField->accessFlags, kAccessForField);
 
-    printf("    #%d              : (in %s)\n", i, backDescriptor);
-    printf("      name          : '%s'\n", name);
-    printf("      type          : '%s'\n", typeDescriptor);
-    printf("      access        : 0x%04x (%s)\n",
-        pSField->accessFlags, accessStr);
+    if (gOptions.outputFormat == OUTPUT_PLAIN) {
+        printf("    #%d              : (in %s)\n", i, backDescriptor);
+        printf("      name          : '%s'\n", name);
+        printf("      type          : '%s'\n", typeDescriptor);
+        printf("      access        : 0x%04x (%s)\n",
+            pSField->accessFlags, accessStr);
+    } else if (gOptions.outputFormat == OUTPUT_XML) {
+        char* tmp;
+
+        printf("<field name=\"%s\"\n", name);
+
+        tmp = descriptorToDot(typeDescriptor);
+        printf(" type=\"%s\"\n", tmp);
+        free(tmp);
+
+        printf(" transient=%s\n",
+            quotedBool((pSField->accessFlags & ACC_TRANSIENT) != 0));
+        printf(" volatile=%s\n",
+            quotedBool((pSField->accessFlags & ACC_VOLATILE) != 0));
+        // "value=" not knowable w/o parsing annotations
+        printf(" static=%s\n",
+            quotedBool((pSField->accessFlags & ACC_STATIC) != 0));
+        printf(" final=%s\n",
+            quotedBool((pSField->accessFlags & ACC_FINAL) != 0));
+        // "deprecated=" not knowable w/o parsing annotations
+        printf(" visibility=%s\n",
+            quotedVisibility(pSField->accessFlags));
+        printf(">\n</field>\n");
+    }
 
     free(accessStr);
 }
@@ -934,92 +1191,158 @@
  */
 void dumpIField(const DexFile* pDexFile, const DexField* pIField, int i)
 {
-    const DexFieldId* pFieldId;
-    const char* backDescriptor;
-    const char* name;
-    const char* typeDescriptor;
-    char* accessStr;
-
-    pFieldId = dexGetFieldId(pDexFile, pIField->fieldIdx);
-    name = dexStringById(pDexFile, pFieldId->nameIdx);
-    typeDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
-    backDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->classIdx);
-
-    accessStr = createAccessFlagStr(pIField->accessFlags, kAccessForField);
-
-    printf("    #%d              : (in %s)\n", i, backDescriptor);
-    printf("      name          : '%s'\n", name);
-    printf("      type          : '%s'\n", typeDescriptor);
-    printf("      access        : 0x%04x (%s)\n",
-        pIField->accessFlags, accessStr);
-
-    free(accessStr);
+    dumpSField(pDexFile, pIField, i);
 }
 
 /*
  * Dump the class.
+ *
+ * If "*pLastPackage" is NULL or does not match the current class' package,
+ * the value will be replaced with a newly-allocated string.
  */
-void dumpClass(DexFile* pDexFile, int idx)
+void dumpClass(DexFile* pDexFile, int idx, char** pLastPackage)
 {
     const DexTypeList* pInterfaces;
     const DexClassDef* pClassDef;
-    DexClassData* pClassData;
+    DexClassData* pClassData = NULL;
     const u1* pEncodedData;
     const char* fileName;
     const char* classDescriptor;
     const char* superclassDescriptor;
-    char* accessStr;
+    char* accessStr = NULL;
     int i;
 
     pClassDef = dexGetClassDef(pDexFile, idx);
-    printf("Class #%d            -\n", idx);
+
+    if (gOptions.exportsOnly && (pClassDef->accessFlags & ACC_PUBLIC) == 0) {
+        //printf("<!-- omitting non-public class %s -->\n",
+        //    classDescriptor);
+        goto bail;
+    }
 
     pEncodedData = dexGetClassData(pDexFile, pClassDef);
     pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
 
     if (pClassData == NULL) {
-        printf("Trouble reading class data\n");
-        return;
+        printf("Trouble reading class data (#%d)\n", idx);
+        goto bail;
     }
     
     classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
-    printf("  Class descriptor  : '%s'\n", classDescriptor);
 
-    accessStr = createAccessFlagStr(pClassDef->accessFlags, kAccessForClass);
-    printf("  Access flags      : 0x%04x (%s)\n",
-        pClassDef->accessFlags, accessStr);
+    /*
+     * For the XML output, show the package name.  Ideally we'd gather
+     * up the classes, sort them, and dump them alphabetically so the
+     * package name wouldn't jump around, but that's not a great plan
+     * for something that needs to run on the device.
+     */
+    if (!(classDescriptor[0] == 'L' &&
+          classDescriptor[strlen(classDescriptor)-1] == ';'))
+    {
+        /* arrays and primitives should not be defined explicitly */
+        fprintf(stderr, "Malformed class name '%s'\n", classDescriptor);
+        /* keep going? */
+    } else if (gOptions.outputFormat == OUTPUT_XML) {
+        char* mangle;
+        char* lastSlash;
+        char* cp;
 
-    if (pClassDef->superclassIdx == kDexNoIndex)
-        superclassDescriptor = "(none)";
-    else {
-        superclassDescriptor =
-            dexStringByTypeIdx(pDexFile, pClassDef->superclassIdx);
-        printf("  Superclass        : '%s'\n", superclassDescriptor);
+        mangle = strdup(classDescriptor + 1);
+        mangle[strlen(mangle)-1] = '\0';
+
+        /* reduce to just the package name */
+        lastSlash = strrchr(mangle, '/');
+        if (lastSlash != NULL) {
+            *lastSlash = '\0';
+        } else {
+            *mangle = '\0';
+        }
+
+        for (cp = mangle; *cp != '\0'; cp++) {
+            if (*cp == '/')
+                *cp = '.';
+        }
+
+        if (*pLastPackage == NULL || strcmp(mangle, *pLastPackage) != 0) {
+            /* start of a new package */
+            if (*pLastPackage != NULL)
+                printf("</package>\n");
+            printf("<package name=\"%s\"\n>\n", mangle);
+            free(*pLastPackage);
+            *pLastPackage = mangle;
+        } else {
+            free(mangle);
+        }
     }
 
-    printf("  Interfaces        -\n");
+    accessStr = createAccessFlagStr(pClassDef->accessFlags, kAccessForClass);
+
+    if (pClassDef->superclassIdx == kDexNoIndex) {
+        superclassDescriptor = NULL;
+    } else {
+        superclassDescriptor =
+            dexStringByTypeIdx(pDexFile, pClassDef->superclassIdx);
+    }
+
+    if (gOptions.outputFormat == OUTPUT_PLAIN) {
+        printf("Class #%d            -\n", idx);
+        printf("  Class descriptor  : '%s'\n", classDescriptor);
+        printf("  Access flags      : 0x%04x (%s)\n",
+            pClassDef->accessFlags, accessStr);
+
+        if (superclassDescriptor != NULL)
+            printf("  Superclass        : '%s'\n", superclassDescriptor);
+
+        printf("  Interfaces        -\n");
+    } else {
+        char* tmp;
+
+        tmp = descriptorClassToDot(classDescriptor);
+        printf("<class name=\"%s\"\n", tmp);
+        free(tmp);
+
+        if (superclassDescriptor != NULL) {
+            tmp = descriptorToDot(superclassDescriptor);
+            printf(" extends=\"%s\"\n", tmp);
+            free(tmp);
+        }
+        printf(" abstract=%s\n",
+            quotedBool((pClassDef->accessFlags & ACC_ABSTRACT) != 0));
+        printf(" static=%s\n",
+            quotedBool((pClassDef->accessFlags & ACC_STATIC) != 0));
+        printf(" final=%s\n",
+            quotedBool((pClassDef->accessFlags & ACC_FINAL) != 0));
+        // "deprecated=" not knowable w/o parsing annotations
+        printf(" visibility=%s\n",
+            quotedVisibility(pClassDef->accessFlags));
+        printf(">\n");
+    }
     pInterfaces = dexGetInterfacesList(pDexFile, pClassDef);
     if (pInterfaces != NULL) {
         for (i = 0; i < (int) pInterfaces->size; i++)
             dumpInterface(pDexFile, dexGetTypeItem(pInterfaces, i), i);
     }
 
-    printf("  Static fields     -\n");
+    if (gOptions.outputFormat == OUTPUT_PLAIN)
+        printf("  Static fields     -\n");
     for (i = 0; i < (int) pClassData->header.staticFieldsSize; i++) {
         dumpSField(pDexFile, &pClassData->staticFields[i], i);
     }
 
-    printf("  Instance fields   -\n");
+    if (gOptions.outputFormat == OUTPUT_PLAIN)
+        printf("  Instance fields   -\n");
     for (i = 0; i < (int) pClassData->header.instanceFieldsSize; i++) {
         dumpIField(pDexFile, &pClassData->instanceFields[i], i);
     }
 
-    printf("  Direct methods    -\n");
+    if (gOptions.outputFormat == OUTPUT_PLAIN)
+        printf("  Direct methods    -\n");
     for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) {
         dumpMethod(pDexFile, &pClassData->directMethods[i], i);
     }
 
-    printf("  Virtual methods   -\n");
+    if (gOptions.outputFormat == OUTPUT_PLAIN)
+        printf("  Virtual methods   -\n");
     for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) {
         dumpMethod(pDexFile, &pClassData->virtualMethods[i], i);
     }
@@ -1030,11 +1353,18 @@
         fileName = dexStringById(pDexFile, pClassDef->sourceFileIdx);
     else
         fileName = "unknown";
-    printf("  source_file_idx   : %d (%s)\n",
-        pClassDef->sourceFileIdx, fileName);
 
-    printf("\n");
+    if (gOptions.outputFormat == OUTPUT_PLAIN) {
+        printf("  source_file_idx   : %d (%s)\n",
+            pClassDef->sourceFileIdx, fileName);
+        printf("\n");
+    }
 
+    if (gOptions.outputFormat == OUTPUT_XML) {
+        printf("</class>\n");
+    }
+
+bail:
     free(pClassData);
     free(accessStr);
 }
@@ -1044,20 +1374,35 @@
  */
 void processDexFile(const char* fileName, DexFile* pDexFile)
 {
+    char* package = NULL;
     int i;
 
-    printf("Opened '%s', DEX version '%.3s'\n", fileName,
-        pDexFile->pHeader->magic +4);
+    if (gOptions.verbose) {
+        printf("Opened '%s', DEX version '%.3s'\n", fileName,
+            pDexFile->pHeader->magic +4);
+    }
 
     if (gOptions.showFileHeaders)
         dumpFileHeader(pDexFile);
 
+    if (gOptions.outputFormat == OUTPUT_XML)
+        printf("<api>\n");
+
     for (i = 0; i < (int) pDexFile->pHeader->classDefsSize; i++) {
         if (gOptions.showSectionHeaders)
             dumpClassDef(pDexFile, i);
 
-        dumpClass(pDexFile, i);
+        dumpClass(pDexFile, i, &package);
     }
+
+    /* free the last one allocated */
+    if (package != NULL) {
+        printf("</package>\n");
+        free(package);
+    }
+
+    if (gOptions.outputFormat == OUTPUT_XML)
+        printf("</api>\n");
 }
 
 
@@ -1071,14 +1416,18 @@
     bool mapped = false;
     int result = -1;
 
-    printf("Processing '%s'...\n", fileName);
+    if (gOptions.verbose)
+        printf("Processing '%s'...\n", fileName);
 
     if (dexOpenAndMap(fileName, gOptions.tempFileName, &map, false) != 0)
         goto bail;
     mapped = true;
 
-    pDexFile = dexFileParse(map.addr, map.length,
-        kDexParseVerifyChecksum | kDexParseContinueOnError);
+    int flags = kDexParseVerifyChecksum;
+    if (gOptions.ignoreBadChecksum)
+        flags |= kDexParseContinueOnError;
+
+    pDexFile = dexFileParse(map.addr, map.length, flags);
     if (pDexFile == NULL) {
         fprintf(stderr, "ERROR: DEX parse failed\n");
         goto bail;
@@ -1103,11 +1452,15 @@
 void usage(void)
 {
     fprintf(stderr, "Copyright (C) 2007 The Android Open Source Project\n\n");
-    fprintf(stderr, "%s: [-d] [-f] [-h] [-t tempfile] dexfile...\n", gProgName);
+    fprintf(stderr,
+        "%s: [-d] [-f] [-h] [-i] [-l layout] [-t tempfile] dexfile...\n",
+        gProgName);
     fprintf(stderr, "\n");
     fprintf(stderr, " -d : disassemble code sections\n");
     fprintf(stderr, " -f : display summary information from file header\n");
     fprintf(stderr, " -h : display file header details\n");
+    fprintf(stderr, " -i : ignore checksum failures\n");
+    fprintf(stderr, " -l : output layout, either 'plain' or 'xml'\n");
     fprintf(stderr, " -t : temp file name (defaults to /sdcard/dex-temp-*)\n");
 }
 
@@ -1122,9 +1475,10 @@
     int ic;
 
     memset(&gOptions, 0, sizeof(gOptions));
+    gOptions.verbose = true;
 
     while (1) {
-        ic = getopt(argc, argv, "dfht:");
+        ic = getopt(argc, argv, "dfhil:t:");
         if (ic < 0)
             break;
 
@@ -1138,8 +1492,22 @@
         case 'h':       // dump section headers, i.e. all meta-data
             gOptions.showSectionHeaders = true;
             break;
+        case 'i':       // continue even if checksum is bad
+            gOptions.ignoreBadChecksum = true;
+            break;
+        case 'l':       // layout
+            if (strcmp(optarg, "plain") == 0) {
+                gOptions.outputFormat = OUTPUT_PLAIN;
+            } else if (strcmp(optarg, "xml") == 0) {
+                gOptions.outputFormat = OUTPUT_XML;
+                gOptions.verbose = false;
+                gOptions.exportsOnly = true;
+            } else {
+                wantUsage = true;
+            }
+            break;
         case 't':       // temp file, used when opening compressed Jar
-            gOptions.tempFileName = argv[optind];
+            gOptions.tempFileName = optarg;
             break;
         default:
             wantUsage = true;
@@ -1169,3 +1537,4 @@
 
     return 0;
 }
+
diff --git a/libdex/CmdUtils.c b/libdex/CmdUtils.c
index 35ced14..7dfee87 100644
--- a/libdex/CmdUtils.c
+++ b/libdex/CmdUtils.c
@@ -104,7 +104,7 @@
 {
     UnzipToFileResult result = kUTFRGenericFailure;
     int len = strlen(fileName);
-    char tempName[32];
+    char tempNameBuf[32];
     bool removeTemp = false;
     int fd = -1;
 
@@ -125,17 +125,17 @@
              * data to a temp file, the location of which varies.
              */
             if (access("/tmp", W_OK) == 0)
-                sprintf(tempName, "/tmp/dex-temp-%d", getpid());
+                sprintf(tempNameBuf, "/tmp/dex-temp-%d", getpid());
             else
-                sprintf(tempName, "/sdcard/dex-temp-%d", getpid());
+                sprintf(tempNameBuf, "/sdcard/dex-temp-%d", getpid());
 
-            tempFileName = tempName;
+            tempFileName = tempNameBuf;
         }
 
         result = dexUnzipToFile(fileName, tempFileName, quiet);
         
         if (result == kUTFRSuccess) {
-            //printf("+++ Good unzip to '%s'\n", tempName);
+            //printf("+++ Good unzip to '%s'\n", tempFileName);
             fileName = tempFileName;
             removeTemp = true;
         } else if (result == kUTFRNotZip) {
@@ -177,8 +177,10 @@
     if (fd >= 0)
         close(fd);
     if (removeTemp) {
-        if (unlink(tempName) != 0)
-            fprintf(stderr, "Warning: unable to remove temp '%s'\n", tempName);
+        if (unlink(tempFileName) != 0) {
+            fprintf(stderr, "Warning: unable to remove temp '%s'\n",
+                tempFileName);
+        }
     }
     return result;
 }