checkpoint BackupDatAInput / RestoreHelper
diff --git a/cmds/backup/backup.cpp b/cmds/backup/backup.cpp
index 22dd486..d4e669b 100644
--- a/cmds/backup/backup.cpp
+++ b/cmds/backup/backup.cpp
@@ -64,22 +64,14 @@
     }
 
     BackupDataReader reader(fd);
+    bool done;
     int type;
 
-    while (reader.ReadNextHeader(&type) == 0) {
+    while (reader.ReadNextHeader(&done, &type) == 0) {
+        if (done) {
+            break;
+        }
         switch (type) {
-            case BACKUP_HEADER_APP_V1:
-            {
-                String8 packageName;
-                int cookie;
-                err = reader.ReadAppHeader(&packageName, &cookie);
-                if (err == 0) {
-                    printf("App header: %s 0x%08x (%d)\n", packageName.string(), cookie, cookie);
-                } else {
-                    printf("Error reading app header\n");
-                }
-                break;
-            }
             case BACKUP_HEADER_ENTITY_V1:
             {
                 String8 key;
@@ -92,17 +84,6 @@
                 }
                 break;
             }
-            case BACKUP_FOOTER_APP_V1:
-            {
-                int cookie;
-                err = reader.ReadAppFooter(&cookie);
-                if (err == 0) {
-                    printf("   App footer: 0x%08x (%d)\n", cookie, cookie);
-                } else {
-                    printf("   Error reading entity header\n");
-                }
-                break;
-            }
             default:
             {
                 printf("Unknown chunk type: 0x%08x\n", type);
diff --git a/core/java/android/backup/BackupDataInput.java b/core/java/android/backup/BackupDataInput.java
index 609dd90..69c206c 100644
--- a/core/java/android/backup/BackupDataInput.java
+++ b/core/java/android/backup/BackupDataInput.java
@@ -82,9 +82,9 @@
         }
     }
 
-    public int readEntityData(byte[] data, int size) throws IOException {
+    public int readEntityData(byte[] data, int offset, int size) throws IOException {
         if (mHeaderReady) {
-            int result = readEntityData_native(mBackupReader, data, size);
+            int result = readEntityData_native(mBackupReader, data, offset, size);
             if (result >= 0) {
                 return result;
             } else {
@@ -95,9 +95,23 @@
         }
     }
 
+    public void skipEntityData() throws IOException {
+        if (mHeaderReady) {
+            int result = skipEntityData_native(mBackupReader);
+            if (result >= 0) {
+                return;
+            } else {
+                throw new IOException("result=0x" + Integer.toHexString(result));
+            }
+        } else {
+            throw new IllegalStateException("mHeaderReady=false");
+        }
+    }
+
     private native static int ctor(FileDescriptor fd);
     private native static void dtor(int mBackupReader);
 
     private native int readNextHeader_native(int mBackupReader, EntityHeader entity);
-    private native int readEntityData_native(int mBackupReader, byte[] data, int size);
+    private native int readEntityData_native(int mBackupReader, byte[] data, int offset, int size);
+    private native int skipEntityData_native(int mBackupReader);
 }
diff --git a/core/java/android/backup/BackupDataInputStream.java b/core/java/android/backup/BackupDataInputStream.java
new file mode 100644
index 0000000..52b1675
--- /dev/null
+++ b/core/java/android/backup/BackupDataInputStream.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2009 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 android.backup;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/** @hide */
+public class BackupDataInputStream extends InputStream {
+
+    String key;
+    int dataSize;
+
+    BackupDataInput mData;
+    byte[] mOneByte;
+
+    BackupDataInputStream(BackupDataInput data) {
+        mData = data;
+    }
+
+    public int read() throws IOException {
+        byte[] one = mOneByte;
+        if (mOneByte == null) {
+            one = mOneByte = new byte[1];
+        }
+        mData.readEntityData(one, 0, 1);
+        return one[0];
+    }
+
+    public int read(byte[] b, int offset, int size) throws IOException {
+        return mData.readEntityData(b, offset, size);
+    }
+
+    public int read(byte[] b) throws IOException {
+        return mData.readEntityData(b, 0, b.length);
+    }
+
+    public String getKey() {
+        return this.key;
+    }
+    
+    public int size() {
+        return this.dataSize;
+    }
+}
+
+
diff --git a/core/java/android/backup/RestoreHelper.java b/core/java/android/backup/RestoreHelper.java
index ebd9906..ee8bedd 100644
--- a/core/java/android/backup/RestoreHelper.java
+++ b/core/java/android/backup/RestoreHelper.java
@@ -16,8 +16,16 @@
 
 package android.backup;
 
+import java.io.InputStream;
+
 /** @hide */
 public interface RestoreHelper {
-    public void performRestore();
+    /**
+     * Called by RestoreHelperDispatcher to dispatch one entity of data.
+     * <p class=note>
+     * Do not close the <code>data</code> stream.  Do not read more than
+     * <code>dataSize</code> bytes from <code>data</code>.
+     */
+    public void performRestore(BackupDataInputStream data);
 }
 
diff --git a/core/java/android/backup/RestoreHelperDispatcher.java b/core/java/android/backup/RestoreHelperDispatcher.java
new file mode 100644
index 0000000..cbfefdc
--- /dev/null
+++ b/core/java/android/backup/RestoreHelperDispatcher.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2009 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 android.backup;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+/** @hide */
+public class RestoreHelperDispatcher {
+    HashMap<String,RestoreHelper> mHelpers;
+
+    public void addHelper(String keyPrefix, RestoreHelper helper) {
+        mHelpers.put(keyPrefix, helper);
+    }
+
+    public void dispatch(BackupDataInput input) throws IOException {
+        BackupDataInputStream stream = new BackupDataInputStream(input);
+        while (input.readNextHeader()) {
+            String rawKey = input.getKey();
+            int pos = rawKey.indexOf(':');
+            if (pos > 0) {
+                String prefix = rawKey.substring(0, pos);
+                RestoreHelper helper = mHelpers.get(prefix);
+                if (helper != null) {
+                    stream.dataSize = input.getDataSize();
+                    stream.key = rawKey.substring(pos+1);
+                    helper.performRestore(stream);
+                }
+            }
+            input.skipEntityData(); // In case they didn't consume the data.
+        }
+    }
+}
diff --git a/core/java/android/backup/RestoreHelperDistributor.java b/core/java/android/backup/RestoreHelperDistributor.java
deleted file mode 100644
index 555ca79..0000000
--- a/core/java/android/backup/RestoreHelperDistributor.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2009 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 android.backup;
-
-import java.util.HashMap;
-
-/** @hide */
-public class RestoreHelperDistributor {
-    HashMap<String,RestoreHelper> mHelpers;
-
-    public void addHelper(String keyPrefix, RestoreHelper helper) {
-        mHelpers.put(keyPrefix, helper);
-    }
-}
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index 5da0883..123c072 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -84,7 +84,7 @@
                     bufSize = dataSize;
                     buf = new byte[bufSize];
                 }
-                changeSet.readEntityData(buf, dataSize);
+                changeSet.readEntityData(buf, 0, dataSize);
                 if (DEBUG) Log.v(TAG, "  + data size " + dataSize);
 
                 File entityFile = new File(packageDir, key);
diff --git a/core/jni/android_backup_BackupDataInput.cpp b/core/jni/android_backup_BackupDataInput.cpp
index 5b2fb73..cf8a8e8 100644
--- a/core/jni/android_backup_BackupDataInput.cpp
+++ b/core/jni/android_backup_BackupDataInput.cpp
@@ -55,18 +55,13 @@
 readNextHeader_native(JNIEnv* env, jobject clazz, int r, jobject entity)
 {
     int err;
+    bool done;
     BackupDataReader* reader = (BackupDataReader*)r;
 
-    err = reader->Status();
-    if (err != 0) {
-        return err < 0 ? err : -1;
-    }
-
     int type = 0;
 
-    err = reader->ReadNextHeader(&type);
-    if (err == EIO) {
-        // Clean EOF with no footer block; just claim we're done
+    err = reader->ReadNextHeader(&done, &type);
+    if (done) {
         return 1;
     }
 
@@ -75,24 +70,12 @@
     }
 
     switch (type) {
-    case BACKUP_HEADER_APP_V1:
-    {
-        String8 packageName;
-        int cookie;
-        err = reader->ReadAppHeader(&packageName, &cookie);
-        if (err != 0) {
-            LOGD("ReadAppHeader() returned %d; aborting", err);
-            return err < 0 ? err : -1;
-        }
-        break;
-    }
     case BACKUP_HEADER_ENTITY_V1:
     {
         String8 key;
         size_t dataSize;
         err = reader->ReadEntityHeader(&key, &dataSize);
         if (err != 0) {
-            LOGD("ReadEntityHeader(); aborting", err);
             return err < 0 ? err : -1;
         }
         // TODO: Set the fields in the entity object
@@ -101,10 +84,6 @@
         env->SetIntField(entity, s_dataSizeField, dataSize);
         return 0;
     }
-    case BACKUP_FOOTER_APP_V1:
-    {
-        break;
-    }
     default:
         LOGD("Unknown header type: 0x%08x\n", type);
         return -1;
@@ -115,12 +94,12 @@
 }
 
 static jint
-readEntityData_native(JNIEnv* env, jobject clazz, int r, jbyteArray data, int size)
+readEntityData_native(JNIEnv* env, jobject clazz, int r, jbyteArray data, int offset, int size)
 {
     int err;
     BackupDataReader* reader = (BackupDataReader*)r;
 
-    if (env->GetArrayLength(data) < size) {
+    if (env->GetArrayLength(data) < (size+offset)) {
         // size mismatch
         return -1;
     }
@@ -130,19 +109,31 @@
         return -2;
     }
 
-    err = reader->ReadEntityData(dataBytes, size);
+    err = reader->ReadEntityData(dataBytes+offset, size);
 
     env->ReleaseByteArrayElements(data, dataBytes, 0);
 
     return err;
 }
 
+static jint
+skipEntityData_native(JNIEnv* env, jobject clazz, int r)
+{
+    int err;
+    BackupDataReader* reader = (BackupDataReader*)r;
+
+    err = reader->SkipEntityData();
+
+    return err;
+}
+
 static const JNINativeMethod g_methods[] = {
     { "ctor", "(Ljava/io/FileDescriptor;)I", (void*)ctor_native },
     { "dtor", "(I)V", (void*)dtor_native },
     { "readNextHeader_native", "(ILandroid/backup/BackupDataInput$EntityHeader;)I",
             (void*)readNextHeader_native },
-    { "readEntityData_native", "(I[BI)I", (void*)readEntityData_native },
+    { "readEntityData_native", "(I[BII)I", (void*)readEntityData_native },
+    { "skipEntityData_native", "(I)I", (void*)skipEntityData_native },
 };
 
 int register_android_backup_BackupDataInput(JNIEnv* env)
diff --git a/include/utils/BackupHelpers.h b/include/utils/BackupHelpers.h
index f60f4ea..3ca8ad2 100644
--- a/include/utils/BackupHelpers.h
+++ b/include/utils/BackupHelpers.h
@@ -23,30 +23,15 @@
 namespace android {
 
 enum {
-    BACKUP_HEADER_APP_V1 = 0x31707041, // App1 (little endian)
     BACKUP_HEADER_ENTITY_V1 = 0x61746144, // Data (little endian)
-    BACKUP_FOOTER_APP_V1 = 0x746f6f46, // Foot (little endian)
 };
 
-// the sizes of all of these match.
-typedef struct {
-    int type; // == BACKUP_HEADER_APP_V1
-    int packageLen; // length of the name of the package that follows, not including the null.
-    int cookie;
-} app_header_v1;
-
 typedef struct {
     int type; // BACKUP_HEADER_ENTITY_V1
     int keyLen; // length of the key name, not including the null terminator
     int dataSize; // size of the data, not including the padding, -1 means delete
 } entity_header_v1;
 
-typedef struct {
-    int type; // BACKUP_FOOTER_APP_V1
-    int entityCount; // the number of entities that were written
-    int cookie;
-} app_footer_v1;
-
 
 /**
  * Writes the data.
@@ -61,13 +46,9 @@
     // does not close fd
     ~BackupDataWriter();
 
-    status_t WriteAppHeader(const String8& packageName, int cookie);
-
     status_t WriteEntityHeader(const String8& key, size_t dataSize);
     status_t WriteEntityData(const void* data, size_t size);
 
-    status_t WriteAppFooter(int cookie);
-
 private:
     explicit BackupDataWriter();
     status_t write_padding_for(int n);
@@ -92,28 +73,26 @@
     ~BackupDataReader();
 
     status_t Status();
-    status_t ReadNextHeader(int* type = NULL);
+    status_t ReadNextHeader(bool* done, int* type);
 
-    status_t ReadAppHeader(String8* packageName, int* cookie);
     bool HasEntities();
     status_t ReadEntityHeader(String8* key, size_t* dataSize);
     status_t SkipEntityData(); // must be called with the pointer at the begining of the data.
     status_t ReadEntityData(void* data, size_t size);
-    status_t ReadAppFooter(int* cookie);
 
 private:
     explicit BackupDataReader();
     status_t skip_padding();
     
     int m_fd;
+    bool m_done;
     status_t m_status;
     ssize_t m_pos;
+    ssize_t m_dataEndPos;
     int m_entityCount;
     union {
         int type;
-        app_header_v1 app;
         entity_header_v1 entity;
-        app_footer_v1 footer;
     } m_header;
 };
 
diff --git a/libs/utils/BackupData.cpp b/libs/utils/BackupData.cpp
index 8c9f875..16ff1e5 100644
--- a/libs/utils/BackupData.cpp
+++ b/libs/utils/BackupData.cpp
@@ -86,46 +86,6 @@
 }
 
 status_t
-BackupDataWriter::WriteAppHeader(const String8& packageName, int cookie)
-{
-    if (m_status != NO_ERROR) {
-        return m_status;
-    }
-
-    ssize_t amt;
-
-    amt = write_padding_for(m_pos);
-    if (amt != 0) {
-        return amt;
-    }
-
-    app_header_v1 header;
-    ssize_t nameLen;
-
-    nameLen = packageName.length();
-
-    header.type = tolel(BACKUP_HEADER_APP_V1);
-    header.packageLen = tolel(nameLen);
-    header.cookie = cookie;
-
-    amt = write(m_fd, &header, sizeof(app_header_v1));
-    if (amt != sizeof(app_header_v1)) {
-        m_status = errno;
-        return m_status;
-    }
-    m_pos += amt;
-
-    amt = write(m_fd, packageName.string(), nameLen+1);
-    if (amt != nameLen+1) {
-        m_status = errno;
-        return m_status;
-    }
-    m_pos += amt;
-
-    return NO_ERROR;
-}
-
-status_t
 BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize)
 {
     if (m_status != NO_ERROR) {
@@ -188,40 +148,11 @@
     return NO_ERROR;
 }
 
-status_t
-BackupDataWriter::WriteAppFooter(int cookie)
-{
-    if (m_status != NO_ERROR) {
-        return m_status;
-    }
-
-    ssize_t amt;
-
-    amt = write_padding_for(m_pos);
-    if (amt != 0) {
-        return amt;
-    }
-
-    app_footer_v1 footer;
-    ssize_t nameLen;
-
-    footer.type = tolel(BACKUP_FOOTER_APP_V1);
-    footer.entityCount = tolel(m_entityCount);
-    footer.cookie = cookie;
-
-    amt = write(m_fd, &footer, sizeof(app_footer_v1));
-    if (amt != sizeof(app_footer_v1)) {
-        m_status = errno;
-        return m_status;
-    }
-    m_pos += amt;
-
-    return NO_ERROR;
-}
 
 
 BackupDataReader::BackupDataReader(int fd)
     :m_fd(fd),
+     m_done(false),
      m_status(NO_ERROR),
      m_pos(0),
      m_entityCount(0)
@@ -260,31 +191,25 @@
     } while(0)
 
 status_t
-BackupDataReader::ReadNextHeader(int* type)
+BackupDataReader::ReadNextHeader(bool* done, int* type)
 {
+    *done = m_done;
     if (m_status != NO_ERROR) {
         return m_status;
     }
 
     int amt;
 
-    SKIP_PADDING();
+    // No error checking here, in case we're at the end of the stream.  Just let read() fail.
+    skip_padding();
     amt = read(m_fd, &m_header, sizeof(m_header));
+    *done = m_done = (amt == 0);
     CHECK_SIZE(amt, sizeof(m_header));
 
     // validate and fix up the fields.
     m_header.type = fromlel(m_header.type);
     switch (m_header.type)
     {
-        case BACKUP_HEADER_APP_V1:
-            m_header.app.packageLen = fromlel(m_header.app.packageLen);
-            if (m_header.app.packageLen < 0) {
-                LOGD("App header at %d has packageLen<0: 0x%08x\n", (int)m_pos,
-                    (int)m_header.app.packageLen);
-                m_status = EINVAL;
-            }
-            m_header.app.cookie = m_header.app.cookie;
-            break;
         case BACKUP_HEADER_ENTITY_V1:
             m_header.entity.keyLen = fromlel(m_header.entity.keyLen);
             if (m_header.entity.keyLen <= 0) {
@@ -295,15 +220,6 @@
             m_header.entity.dataSize = fromlel(m_header.entity.dataSize);
             m_entityCount++;
             break;
-        case BACKUP_FOOTER_APP_V1:
-            m_header.footer.entityCount = fromlel(m_header.footer.entityCount);
-            if (m_header.footer.entityCount < 0) {
-                LOGD("Entity header at %d has entityCount<0: 0x%08x\n", (int)m_pos,
-                        (int)m_header.footer.entityCount);
-                m_status = EINVAL;
-            }
-            m_header.footer.cookie = m_header.footer.cookie;
-            break;
         default:
             LOGD("Chunk header at %d has invalid type: 0x%08x", (int)m_pos, (int)m_header.type);
             m_status = EINVAL;
@@ -316,30 +232,6 @@
     return m_status;
 }
 
-status_t
-BackupDataReader::ReadAppHeader(String8* packageName, int* cookie)
-{
-    if (m_status != NO_ERROR) {
-        return m_status;
-    }
-    if (m_header.type != BACKUP_HEADER_APP_V1) {
-        return EINVAL;
-    }
-    size_t size = m_header.app.packageLen;
-    char* buf = packageName->lockBuffer(size);
-    if (buf == NULL) {
-        packageName->unlockBuffer();
-        m_status = ENOMEM;
-        return m_status;
-    }
-    int amt = read(m_fd, buf, size+1);
-    CHECK_SIZE(amt, (int)size+1);
-    packageName->unlockBuffer(size);
-    m_pos += size+1;
-    *cookie = m_header.app.cookie;
-    return NO_ERROR;
-}
-
 bool
 BackupDataReader::HasEntities()
 {
@@ -368,6 +260,7 @@
     m_pos += size+1;
     *dataSize = m_header.entity.dataSize;
     SKIP_PADDING();
+    m_dataEndPos = m_pos + *dataSize;
     return NO_ERROR;
 }
 
@@ -381,7 +274,7 @@
         return EINVAL;
     }
     if (m_header.entity.dataSize > 0) {
-        int pos = lseek(m_fd, m_header.entity.dataSize, SEEK_CUR);
+        int pos = lseek(m_fd, m_dataEndPos, SEEK_SET);
         return pos == -1 ? (int)errno : (int)NO_ERROR;
     } else {
         return NO_ERROR;
@@ -394,6 +287,15 @@
     if (m_status != NO_ERROR) {
         return m_status;
     }
+    int remaining = m_dataEndPos - m_pos;
+    if (size > remaining) {
+        printf("size=%d m_pos=0x%x m_dataEndPos=0x%x remaining=%d\n",
+                size, m_pos, m_dataEndPos, remaining);
+        size = remaining;
+    }
+    if (remaining <= 0) {
+        return 0;
+    }
     int amt = read(m_fd, data, size);
     CHECK_SIZE(amt, (int)size);
     m_pos += size;
@@ -401,25 +303,6 @@
 }
 
 status_t
-BackupDataReader::ReadAppFooter(int* cookie)
-{
-    if (m_status != NO_ERROR) {
-        return m_status;
-    }
-    if (m_header.type != BACKUP_FOOTER_APP_V1) {
-        return EINVAL;
-    }
-    if (m_header.footer.entityCount != m_entityCount) {
-        LOGD("entity count mismatch actual=%d expected=%d", m_entityCount,
-                m_header.footer.entityCount);
-        m_status = EINVAL;
-        return m_status;
-    }
-    *cookie = m_header.footer.cookie;
-    return NO_ERROR;
-}
-
-status_t
 BackupDataReader::skip_padding()
 {
     ssize_t amt;
diff --git a/libs/utils/BackupHelpers.cpp b/libs/utils/BackupHelpers.cpp
index 4c3e37d..c1d5404 100644
--- a/libs/utils/BackupHelpers.cpp
+++ b/libs/utils/BackupHelpers.cpp
@@ -689,41 +689,27 @@
 
 // hexdump -v -e '"    " 8/1 " 0x%02x," "\n"' data_writer.data
 const unsigned char DATA_GOLDEN_FILE[] = {
-     0x41, 0x70, 0x70, 0x31, 0x0b, 0x00, 0x00, 0x00,
-     0xdd, 0xcc, 0xbb, 0xaa, 0x6e, 0x6f, 0x5f, 0x70,
-     0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
      0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
      0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
      0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
      0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
-     0x6e, 0x67, 0x5f, 0x00, 0x41, 0x70, 0x70, 0x31,
-     0x0c, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
+     0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
+     0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
      0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
      0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
-     0x44, 0x61, 0x74, 0x61, 0x0c, 0x00, 0x00, 0x00,
-     0x0d, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
-     0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33,
-     0x00, 0xbc, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
-     0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33,
-     0x00, 0xbc, 0xbc, 0xbc, 0x41, 0x70, 0x70, 0x31,
-     0x0d, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
      0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
-     0x6f, 0x5f, 0x32, 0x5f, 0x5f, 0x00, 0xbc, 0xbc,
+     0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
      0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
      0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
      0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
      0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
      0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
-     0x5f, 0x00, 0xbc, 0xbc, 0x41, 0x70, 0x70, 0x31,
-     0x0a, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
-     0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
-     0x6f, 0x31, 0x00, 0xbc, 0x44, 0x61, 0x74, 0x61,
+     0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
      0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
      0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
      0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
-     0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00, 0xbc,
-     0x46, 0x6f, 0x6f, 0x74, 0x04, 0x00, 0x00, 0x00,
-     0x99, 0x99, 0x77, 0x77
+     0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00
+
 };
 const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
 
@@ -733,12 +719,6 @@
     int err;
     String8 text(str);
 
-    err = writer.WriteAppHeader(text, 0xaabbccdd);
-    if (err != 0) {
-        fprintf(stderr, "WriteAppHeader failed with %s\n", strerror(err));
-        return err;
-    }
-
     err = writer.WriteEntityHeader(text, text.length()+1);
     if (err != 0) {
         fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
@@ -779,8 +759,6 @@
     err |= test_write_header_and_entity(writer, "padded_to_2__");
     err |= test_write_header_and_entity(writer, "padded_to1");
 
-    writer.WriteAppFooter(0x77779999);
-
     close(fd);
 
     err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
@@ -800,70 +778,59 @@
     String8 string;
     int cookie = 0x11111111;
     size_t actualSize;
+    bool done;
+    int type;
 
     // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
 
-    err = reader.ReadNextHeader();
+    err = reader.ReadNextHeader(&done, &type);
+    if (done) {
+        fprintf(stderr, "should not be done yet\n");
+        goto finished;
+    }
     if (err != 0) {
         fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
-        goto done;
+        goto finished;
     }
-
-    err = reader.ReadAppHeader(&string, &cookie);
-    if (err != 0) {
-        fprintf(stderr, "ReadAppHeader failed with %s\n", strerror(err));
-        goto done;
-    }
-    if (string != str) {
-        fprintf(stderr, "ReadAppHeader expected packageName '%s' got '%s'\n", str, string.string());
+    if (type != BACKUP_HEADER_ENTITY_V1) {
         err = EINVAL;
-        goto done;
-    }
-    if (cookie != (int)0xaabbccdd) {
-        fprintf(stderr, "ReadAppHeader expected cookie 0x%08x got 0x%08x\n", 0xaabbccdd, cookie);
-        err = EINVAL;
-        goto done;
-    }
-
-    err = reader.ReadNextHeader();
-    if (err != 0) {
-        fprintf(stderr, "ReadNextHeader (for entity header) failed with %s\n", strerror(err));
-        goto done;
+        fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
     }
 
     err = reader.ReadEntityHeader(&string, &actualSize);
     if (err != 0) {
         fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
-        goto done;
+        goto finished;
     }
     if (string != str) {
         fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
         err = EINVAL;
-        goto done;
+        goto finished;
     }
     if ((int)actualSize != bufSize) {
         fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize,
                 actualSize);
         err = EINVAL;
-        goto done;
+        goto finished;
     }
 
     err = reader.ReadEntityData(buf, bufSize);
     if (err != NO_ERROR) {
         fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
-        goto done;
+        goto finished;
     }
 
     if (0 != memcmp(buf, str, bufSize)) {
         fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
-                "%02x %02x %02x %02x\n", str, buf[0], buf[1], buf[2], buf[3]);
+                "%02x %02x %02x %02x  '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3],
+                buf[0], buf[1], buf[2], buf[3]);
         err = EINVAL;
-        goto done;
+        goto finished;
     }
 
     // The next read will confirm whether it got the right amount of data.
 
-done:
+finished:
     if (err != NO_ERROR) {
         fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
     }
@@ -923,23 +890,6 @@
         if (err == NO_ERROR) {
             err = test_read_header_and_entity(reader, "padded_to1");
         }
-
-        if (err == NO_ERROR) {
-            err = reader.ReadNextHeader();
-            if (err != 0) {
-                fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
-            }
-
-            if (err == NO_ERROR) {
-                int cookie;
-                err |= reader.ReadAppFooter(&cookie);
-                if (cookie != 0x77779999) {
-                    fprintf(stderr, "app footer cookie expected=0x%08x actual=0x%08x\n",
-                        0x77779999, cookie);
-                    err = EINVAL;
-                }
-            }
-        }
     }
 
     close(fd);