Use common implementation for getObject and importFile.

Previously the two functions have separate but similar implementation. ag/750097
fixed a bug in importFile, but we have a same bug in getObject. Instead fixing
the bug separately, the CL adds a common function that can be used from both
getObject and importFile.

BUG=23264575

Change-Id: I0bdc876ee9b11301ba4c445cc16556e9c951a8b4
diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp
index 4e20b1a..d0ec2a6 100644
--- a/media/mtp/MtpDataPacket.cpp
+++ b/media/mtp/MtpDataPacket.cpp
@@ -25,8 +25,6 @@
 #include "MtpDataPacket.h"
 #include "MtpStringBuffer.h"
 
-#define MTP_BUFFER_SIZE 16384
-
 namespace android {
 
 MtpDataPacket::MtpDataPacket()
@@ -540,17 +538,17 @@
 
 #endif // MTP_HOST
 
-void* MtpDataPacket::getData(int& outLength) const {
+void* MtpDataPacket::getData(int* outLength) const {
     int length = mPacketSize - MTP_CONTAINER_HEADER_SIZE;
     if (length > 0) {
         void* result = malloc(length);
         if (result) {
             memcpy(result, mBuffer + MTP_CONTAINER_HEADER_SIZE, length);
-            outLength = length;
+            *outLength = length;
             return result;
         }
     }
-    outLength = 0;
+    *outLength = 0;
     return NULL;
 }
 
diff --git a/media/mtp/MtpDataPacket.h b/media/mtp/MtpDataPacket.h
index 13d3bd9..6240f28 100644
--- a/media/mtp/MtpDataPacket.h
+++ b/media/mtp/MtpDataPacket.h
@@ -117,7 +117,7 @@
 
     inline bool         hasData() const { return mPacketSize > MTP_CONTAINER_HEADER_SIZE; }
     inline uint32_t     getContainerLength() const { return MtpPacket::getUInt32(MTP_CONTAINER_LENGTH_OFFSET); }
-    void*               getData(int& outLength) const;
+    void*               getData(int* outLength) const;
 };
 
 }; // namespace android
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
index b84a245..c70d3a1 100644
--- a/media/mtp/MtpDevice.cpp
+++ b/media/mtp/MtpDevice.cpp
@@ -19,6 +19,7 @@
 #include "MtpDebug.h"
 #include "MtpDevice.h"
 #include "MtpDeviceInfo.h"
+#include "MtpEventPacket.h"
 #include "MtpObjectInfo.h"
 #include "MtpProperty.h"
 #include "MtpStorageInfo.h"
@@ -50,6 +51,15 @@
 }
 #endif
 
+namespace {
+
+bool writeToFd(void* data, int /* unused_offset */, int length, void* clientData) {
+    const int fd = *static_cast<int*>(clientData);
+    return write(fd, data, length) == length;
+}
+
+}
+
 MtpDevice* MtpDevice::open(const char* deviceName, int fd) {
     struct usb_device *device = usb_device_new(deviceName, fd);
     if (!device) {
@@ -414,7 +424,7 @@
     if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) {
         MtpResponseCode ret = readResponse();
         if (ret == MTP_RESPONSE_OK) {
-            return mData.getData(outLength);
+            return mData.getData(&outLength);
         }
     }
     outLength = 0;
@@ -593,94 +603,10 @@
 }
 
 bool MtpDevice::readObject(MtpObjectHandle handle,
-        bool (* callback)(void* data, int offset, int length, void* clientData),
-        size_t objectSize, void* clientData) {
-    Mutex::Autolock autoLock(mMutex);
-    bool result = false;
-
-    mRequest.reset();
-    mRequest.setParameter(1, handle);
-    if (sendRequest(MTP_OPERATION_GET_OBJECT)
-            && mData.readDataHeader(mRequestIn1)) {
-        uint32_t length = mData.getContainerLength();
-        if (length - MTP_CONTAINER_HEADER_SIZE != objectSize) {
-            ALOGE("readObject error objectSize: %d, length: %d",
-                    objectSize, length);
-            goto fail;
-        }
-        length -= MTP_CONTAINER_HEADER_SIZE;
-        uint32_t remaining = length;
-        int offset = 0;
-
-        int initialDataLength = 0;
-        void* initialData = mData.getData(initialDataLength);
-        if (initialData) {
-            if (initialDataLength > 0) {
-                if (!callback(initialData, 0, initialDataLength, clientData))
-                    goto fail;
-                remaining -= initialDataLength;
-                offset += initialDataLength;
-            }
-            free(initialData);
-        }
-
-        // USB reads greater than 16K don't work
-        char buffer1[16384], buffer2[16384];
-        mRequestIn1->buffer = buffer1;
-        mRequestIn2->buffer = buffer2;
-        struct usb_request* req = mRequestIn1;
-        void* writeBuffer = NULL;
-        int writeLength = 0;
-
-        while (remaining > 0 || writeBuffer) {
-            if (remaining > 0) {
-                // queue up a read request
-                req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
-                if (mData.readDataAsync(req)) {
-                    ALOGE("readDataAsync failed");
-                    goto fail;
-                }
-            } else {
-                req = NULL;
-            }
-
-            if (writeBuffer) {
-                // write previous buffer
-                if (!callback(writeBuffer, offset, writeLength, clientData)) {
-                    ALOGE("write failed");
-                    // wait for pending read before failing
-                    if (req)
-                        mData.readDataWait(mDevice);
-                    goto fail;
-                }
-                offset += writeLength;
-                writeBuffer = NULL;
-            }
-
-            // wait for read to complete
-            if (req) {
-                int read = mData.readDataWait(mDevice);
-                if (read < 0)
-                    goto fail;
-
-                if (read > 0) {
-                    writeBuffer = req->buffer;
-                    writeLength = read;
-                    remaining -= read;
-                    req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
-                } else {
-                    writeBuffer = NULL;
-                }
-            }
-        }
-
-        MtpResponseCode response = readResponse();
-        if (response == MTP_RESPONSE_OK)
-            result = true;
-    }
-
-fail:
-    return result;
+                           ReadObjectCallback callback,
+                           size_t expectedLength,
+                           void* clientData) {
+    return readObjectInternal(handle, callback, &expectedLength, clientData);
 }
 
 // reads the object's data and writes it to the specified file path
@@ -705,86 +631,98 @@
 
 bool MtpDevice::readObject(MtpObjectHandle handle, int fd) {
     ALOGD("readObject: %d", fd);
+    return readObjectInternal(handle, writeToFd, NULL /* expected size */, &fd);
+}
 
+bool MtpDevice::readObjectInternal(MtpObjectHandle handle,
+                                   ReadObjectCallback callback,
+                                   const size_t* expectedLength,
+                                   void* clientData) {
     Mutex::Autolock autoLock(mMutex);
 
     mRequest.reset();
     mRequest.setParameter(1, handle);
-    if (sendRequest(MTP_OPERATION_GET_OBJECT) && mData.readDataHeader(mRequestIn1)) {
-        uint32_t length = mData.getContainerLength();
-        if (length < MTP_CONTAINER_HEADER_SIZE) {
-            ALOGE("Invalid container length.");
-            return false;
-        }
-        length -= MTP_CONTAINER_HEADER_SIZE;
-        uint32_t remaining = length;
+    if (!sendRequest(MTP_OPERATION_GET_OBJECT)) {
+        ALOGE("Failed to send a read request.");
+        return false;
+    }
 
-        bool writingError = false;
+    if (!mData.readDataHeader(mRequestIn1)) {
+        ALOGE("Failed to read header.");
+        return false;
+    }
+
+    const uint32_t fullLength = mData.getContainerLength();
+    if ((!expectedLength && fullLength < MTP_CONTAINER_HEADER_SIZE) ||
+        (expectedLength && *expectedLength + MTP_CONTAINER_HEADER_SIZE != fullLength)) {
+        ALOGE("readObject error length: %d", fullLength);
+        return false;
+    }
+
+    const uint32_t length = fullLength - MTP_CONTAINER_HEADER_SIZE;
+    uint32_t offset = 0;
+    bool writingError = false;
+
+    {
         int initialDataLength = 0;
-        void* initialData = mData.getData(initialDataLength);
+        void* const initialData = mData.getData(&initialDataLength);
         if (initialData) {
             if (initialDataLength > 0) {
-                if (write(fd, initialData, initialDataLength) != initialDataLength) {
+                if (!callback(initialData, offset, initialDataLength, clientData)) {
                     ALOGE("Failed to write initial data.");
                     writingError = true;
                 }
-                remaining -= initialDataLength;
+                offset += initialDataLength;
             }
             free(initialData);
         }
+    }
 
-        // USB reads greater than 16K don't work
-        char buffer1[16384], buffer2[16384];
-        mRequestIn1->buffer = buffer1;
-        mRequestIn2->buffer = buffer2;
-        struct usb_request* req = mRequestIn1;
+    // USB reads greater than 16K don't work.
+    char buffer1[MTP_BUFFER_SIZE], buffer2[MTP_BUFFER_SIZE];
+    mRequestIn1->buffer = buffer1;
+    mRequestIn2->buffer = buffer2;
+    struct usb_request* req = NULL;
+
+    while (offset < length) {
+        // Wait for previous read to complete.
         void* writeBuffer = NULL;
         int writeLength = 0;
-
-        while (remaining > 0 || writeBuffer) {
-            if (remaining > 0) {
-                // queue up a read request
-                req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
-                if (mData.readDataAsync(req)) {
-                    ALOGE("readDataAsync failed");
-                    return false;
-                }
-            } else {
-                req = NULL;
+        if (req) {
+            const int read = mData.readDataWait(mDevice);
+            if (read < 0) {
+                ALOGE("readDataWait failed.");
+                return false;
             }
+            writeBuffer = req->buffer;
+            writeLength = read;
+        }
 
-            if (writeBuffer && !writingError) {
-                // write previous buffer
-                if (write(fd, writeBuffer, writeLength) != writeLength) {
-                    writingError = true;
-                }
-            }
-            writeBuffer = NULL;
-
-            // wait for read to complete
-            if (req) {
-                int read = mData.readDataWait(mDevice);
-                if (read < 0) {
-                    ALOGE("readDataWait failed.");
-                    return false;
-                }
-
-                if (read > 0) {
-                    writeBuffer = req->buffer;
-                    writeLength = read;
-                    remaining -= read;
-                    req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
-                } else {
-                    writeBuffer = NULL;
-                }
+        // Request to read next chunk.
+        const uint32_t nextOffset = offset + writeLength;
+        if (nextOffset < length) {
+            // Queue up a read request.
+            const size_t remaining = length - nextOffset;
+            req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
+            req->buffer_length =
+                    remaining > MTP_BUFFER_SIZE ? static_cast<size_t>(MTP_BUFFER_SIZE) : remaining;
+            if (mData.readDataAsync(req) != 0) {
+                ALOGE("readDataAsync failed");
+                return false;
             }
         }
 
-        MtpResponseCode response = readResponse();
-        return response == MTP_RESPONSE_OK && !writingError;
+        // Write previous buffer.
+        if (writeBuffer && !writingError) {
+            if (!callback(writeBuffer, offset, writeLength, clientData)) {
+                ALOGE("write failed");
+                writingError = true;
+            }
+        }
+        offset = nextOffset;
     }
 
-    return false;
+    return readResponse() == MTP_RESPONSE_OK && !writingError;
 }
 
 bool MtpDevice::sendRequest(MtpOperationCode operation) {
diff --git a/media/mtp/MtpDevice.h b/media/mtp/MtpDevice.h
index ef29f1b..f93a51b 100644
--- a/media/mtp/MtpDevice.h
+++ b/media/mtp/MtpDevice.h
@@ -60,6 +60,7 @@
     Mutex                   mMutex;
 
 public:
+    typedef bool (*ReadObjectCallback)(void* data, int offset, int length, void* clientData);
                             MtpDevice(struct usb_device* device, int interface,
                                     const struct usb_endpoint_descriptor *ep_in,
                                     const struct usb_endpoint_descriptor *ep_out,
@@ -95,15 +96,16 @@
     MtpProperty*            getDevicePropDesc(MtpDeviceProperty code);
     MtpProperty*            getObjectPropDesc(MtpObjectProperty code, MtpObjectFormat format);
 
-    bool                    readObject(MtpObjectHandle handle,
-                                    bool (* callback)(void* data, int offset,
-                                            int length, void* clientData),
+    bool                    readObject(MtpObjectHandle handle, ReadObjectCallback callback,
                                     size_t objectSize, void* clientData);
     bool                    readObject(MtpObjectHandle handle, const char* destPath, int group,
                                     int perm);
     bool                    readObject(MtpObjectHandle handle, int fd);
 
 private:
+    // If |objectSize| is not NULL, it checks object size before reading data bytes.
+    bool                    readObjectInternal(MtpObjectHandle handle, ReadObjectCallback callback,
+                                     const size_t* objectSize, void* clientData);
     bool                    sendRequest(MtpOperationCode operation);
     bool                    sendData();
     bool                    readData();
diff --git a/media/mtp/mtp.h b/media/mtp/mtp.h
index d270df5..7b80d2e 100644
--- a/media/mtp/mtp.h
+++ b/media/mtp/mtp.h
@@ -37,6 +37,9 @@
 #define MTP_CONTAINER_PARAMETER_OFFSET          12
 #define MTP_CONTAINER_HEADER_SIZE               12
 
+// Maximum buffer size for a MTP packet.
+#define MTP_BUFFER_SIZE 16384
+
 // MTP Data Types
 #define MTP_TYPE_UNDEFINED      0x0000          // Undefined
 #define MTP_TYPE_INT8           0x0001          // Signed 8-bit integer