MTP: Implement GetObjectPropDesc

Change-Id: I283651257254fc9cd9d93eab4605c5e33d3db93e
Signed-off-by: Mike Lockwood <lockwood@android.com>
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
index 5612387..3ceb9b4 100644
--- a/media/mtp/MtpDevice.cpp
+++ b/media/mtp/MtpDevice.cpp
@@ -245,7 +245,7 @@
     MtpResponseCode ret = readResponse();
     if (ret == MTP_RESPONSE_OK) {
         MtpProperty* property = new MtpProperty;
-        property->read(mData);
+        property->read(mData, true);
         return property;
     }
     return NULL;
diff --git a/media/mtp/MtpProperty.cpp b/media/mtp/MtpProperty.cpp
index a114e83..8d639a5 100644
--- a/media/mtp/MtpProperty.cpp
+++ b/media/mtp/MtpProperty.cpp
@@ -41,6 +41,58 @@
     mMaximumValue.str = NULL;
 }
 
+MtpProperty::MtpProperty(MtpPropertyCode propCode,
+                         MtpDataType type,
+                         bool writeable,
+                         int defaultValue)
+    :   mCode(propCode),
+        mType(type),
+        mWriteable(writeable),
+        mDefaultArrayLength(0),
+        mDefaultArrayValues(NULL),
+        mCurrentArrayLength(0),
+        mCurrentArrayValues(NULL),
+        mFormFlag(kFormNone),
+        mEnumLength(0),
+        mEnumValues(NULL)
+{
+    memset(&mDefaultValue, 0, sizeof(mDefaultValue));
+    memset(&mCurrentValue, 0, sizeof(mCurrentValue));
+    memset(&mMinimumValue, 0, sizeof(mMinimumValue));
+    memset(&mMaximumValue, 0, sizeof(mMaximumValue));
+
+    if (defaultValue) {
+        switch (type) {
+            case MTP_TYPE_INT8:
+                mDefaultValue.i8 = defaultValue;
+                break;
+            case MTP_TYPE_UINT8:
+                mDefaultValue.u8 = defaultValue;
+                break;
+            case MTP_TYPE_INT16:
+                mDefaultValue.i16 = defaultValue;
+                break;
+            case MTP_TYPE_UINT16:
+                mDefaultValue.u16 = defaultValue;
+                break;
+            case MTP_TYPE_INT32:
+                mDefaultValue.i32 = defaultValue;
+                break;
+            case MTP_TYPE_UINT32:
+                mDefaultValue.u32 = defaultValue;
+                break;
+            case MTP_TYPE_INT64:
+                mDefaultValue.i64 = defaultValue;
+                break;
+            case MTP_TYPE_UINT64:
+                mDefaultValue.u64 = defaultValue;
+                break;
+            default:
+                LOGE("unknown type %d in MtpProperty::MtpProperty", type);
+        }
+    }
+}
+
 MtpProperty::~MtpProperty() {
     if (mType == MTP_TYPE_STR) {
         // free all strings
@@ -66,7 +118,7 @@
     delete[] mEnumValues;
 }
 
-void MtpProperty::read(MtpDataPacket& packet) {
+void MtpProperty::read(MtpDataPacket& packet, bool deviceProp) {
     MtpStringBuffer string;
 
     mCode = packet.getUInt16();
@@ -88,7 +140,8 @@
             break;
         default:
             readValue(packet, mDefaultValue);
-            readValue(packet, mCurrentValue);
+            if (deviceProp)
+                readValue(packet, mCurrentValue);
     }
     mFormFlag = packet.getUInt8();
 
@@ -104,6 +157,40 @@
     }
 }
 
+// FIXME - only works for object properties
+void MtpProperty::write(MtpDataPacket& packet) {
+    packet.putUInt16(mCode);
+    packet.putUInt16(mType);
+    packet.putUInt8(mWriteable ? 1 : 0);
+
+    switch (mType) {
+        case MTP_TYPE_AINT8:
+        case MTP_TYPE_AUINT8:
+        case MTP_TYPE_AINT16:
+        case MTP_TYPE_AUINT16:
+        case MTP_TYPE_AINT32:
+        case MTP_TYPE_AUINT32:
+        case MTP_TYPE_AINT64:
+        case MTP_TYPE_AUINT64:
+        case MTP_TYPE_AINT128:
+        case MTP_TYPE_AUINT128:
+            writeArrayValues(packet, mDefaultArrayValues, mDefaultArrayLength);
+            break;
+        default:
+            writeValue(packet, mDefaultValue);
+    }
+    packet.putUInt8(mFormFlag);
+    if (mFormFlag == kFormRange) {
+            writeValue(packet, mMinimumValue);
+            writeValue(packet, mMaximumValue);
+            writeValue(packet, mStepSize);
+    } else if (mFormFlag == kFormEnum) {
+        packet.putUInt16(mEnumLength);
+        for (int i = 0; i < mEnumLength; i++)
+            writeValue(packet, mEnumValues[i]);
+    }
+}
+
 void MtpProperty::print() {
     LOGD("MtpProperty %04X\n", mCode);
     LOGD("    type %04X\n", mType);
@@ -147,6 +234,43 @@
     }
 }
 
+void MtpProperty::writeValue(MtpDataPacket& packet, MtpPropertyValue& value) {
+    switch (mType) {
+        case MTP_TYPE_INT8:
+            packet.putInt8(value.i8);
+            break;
+        case MTP_TYPE_UINT8:
+            packet.putUInt8(value.u8);
+            break;
+        case MTP_TYPE_INT16:
+            packet.putInt16(value.i16);
+            break;
+        case MTP_TYPE_UINT16:
+            packet.putUInt16(value.u16);
+            break;
+        case MTP_TYPE_INT32:
+            packet.putInt32(value.i32);
+            break;
+        case MTP_TYPE_UINT32:
+            packet.putUInt32(value.u32);
+            break;
+        case MTP_TYPE_INT64:
+            packet.putInt64(value.i64);
+            break;
+        case MTP_TYPE_UINT64:
+            packet.putUInt64(value.u64);
+            break;
+        case MTP_TYPE_INT128:
+            packet.putInt128(value.i128);
+            break;
+        case MTP_TYPE_UINT128:
+            packet.putUInt128(value.u128);
+            break;
+        default:
+            LOGE("unknown type %d in MtpProperty::readValue", mType);
+    }
+}
+
 MtpPropertyValue* MtpProperty::readArrayValues(MtpDataPacket& packet, int& length) {
     length = packet.getUInt32();
     if (length == 0)
@@ -157,4 +281,10 @@
     return result;
 }
 
+void MtpProperty::writeArrayValues(MtpDataPacket& packet, MtpPropertyValue* values, int length) {
+    packet.putUInt32(length);
+    for (int i = 0; i < length; i++)
+        writeValue(packet, values[i]);
+}
+
 }  // namespace android
diff --git a/media/mtp/MtpProperty.h b/media/mtp/MtpProperty.h
index 6372290..4923d40 100644
--- a/media/mtp/MtpProperty.h
+++ b/media/mtp/MtpProperty.h
@@ -55,15 +55,24 @@
 
 public:
                         MtpProperty();
+                        MtpProperty(MtpPropertyCode propCode,
+                                     MtpDataType type,
+                                     bool writeable = false,
+                                     int defaultValue = 0);
     virtual             ~MtpProperty();
 
-    void                read(MtpDataPacket& packet);
+    inline MtpPropertyCode getPropertyCode() const { return mCode; }
+
+    void                read(MtpDataPacket& packet, bool deviceProp);
+    void                write(MtpDataPacket& packet);
 
     void                print();
 
 private:
     void                readValue(MtpDataPacket& packet, MtpPropertyValue& value);
+    void                writeValue(MtpDataPacket& packet, MtpPropertyValue& value);
     MtpPropertyValue*   readArrayValues(MtpDataPacket& packet, int& length);
+    void                writeArrayValues(MtpDataPacket& packet, MtpPropertyValue* values, int length);
 };
 
 }; // namespace android
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 048d1dc..0b99cb1 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "MtpServer"
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/types.h>
@@ -27,11 +25,11 @@
 #include <cutils/properties.h>
 
 #include "MtpDebug.h"
+#include "MtpDatabase.h"
+#include "MtpProperty.h"
 #include "MtpServer.h"
 #include "MtpStorage.h"
 #include "MtpStringBuffer.h"
-#include "MtpDatabase.h"
-#include "MtpDebug.h"
 
 #include "f_mtp.h"
 
@@ -126,6 +124,8 @@
 {
     mDatabase = new MtpDatabase();
     mDatabase->open(databasePath, true);
+
+    initObjectProperties();
 }
 
 MtpServer::~MtpServer() {
@@ -157,7 +157,7 @@
 void MtpServer::run() {
     int fd = mFD;
 
-    LOGD("MtpServer::run fd: %d", fd);
+    LOGV("MtpServer::run fd: %d\n", fd);
 
     while (1) {
         int ret = mRequest.read(fd);
@@ -222,11 +222,37 @@
                 break;
             }
         } else {
-            LOGV("skipping response");
+            LOGV("skipping response\n");
         }
     }
 }
 
+MtpProperty* MtpServer::getObjectProperty(MtpPropertyCode propCode) {
+    for (int i = 0; i < mObjectProperties.size(); i++) {
+        MtpProperty* property = mObjectProperties[i];
+        if (property->getPropertyCode() == propCode)
+            return property;
+    }
+    return NULL;
+}
+
+MtpProperty* MtpServer::getDeviceProperty(MtpPropertyCode propCode) {
+    for (int i = 0; i < mDeviceProperties.size(); i++) {
+        MtpProperty* property = mDeviceProperties[i];
+        if (property->getPropertyCode() == propCode)
+            return property;
+    }
+    return NULL;
+}
+
+void MtpServer::initObjectProperties() {
+    mObjectProperties.push(new MtpProperty(MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT16));
+    mObjectProperties.push(new MtpProperty(MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16));
+    mObjectProperties.push(new MtpProperty(MTP_PROPERTY_OBJECT_SIZE, MTP_TYPE_UINT64));
+    mObjectProperties.push(new MtpProperty(MTP_PROPERTY_OBJECT_FILE_NAME, MTP_TYPE_STR));
+    mObjectProperties.push(new MtpProperty(MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32));
+}
+
 bool MtpServer::handleRequest() {
     MtpOperationCode operation = mRequest.getOperationCode();
     MtpResponseCode response;
@@ -280,6 +306,8 @@
             response = doDeleteObject();
             break;
         case MTP_OPERATION_GET_OBJECT_PROP_DESC:
+            response = doGetObjectPropDesc();
+            break;
         default:
             response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
             break;
@@ -489,9 +517,6 @@
     time_t modifiedTime;
     if (!parseDateTime(modified, modifiedTime))
         modifiedTime = 0;
-    LOGV("SendObjectInfo format: %04X size: %d name: %s, created: %s, modified: %s",
-            format, mSendObjectFileSize, (const char*)name, (const char*)created,
-            (const char*)modified);
 
     if (path[path.size() - 1] != '/')
         path += "/";
@@ -589,10 +614,14 @@
 }
 
 MtpResponseCode MtpServer::doGetObjectPropDesc() {
-    MtpObjectProperty property = mRequest.getParameter(1);
+    MtpObjectProperty propCode = mRequest.getParameter(1);
     MtpObjectFormat format = mRequest.getParameter(2);
+    MtpProperty* property = getObjectProperty(propCode);
+    if (!property)
+        return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
 
-    return -1;
+    property->write(mData);
+    return MTP_RESPONSE_OK;
 }
 
 }  // namespace android
diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
index 40f3c52..40329c5 100644
--- a/media/mtp/MtpServer.h
+++ b/media/mtp/MtpServer.h
@@ -28,6 +28,7 @@
 
 class MtpStorage;
 class MtpDatabase;
+class MtpProperty;
 
 class MtpServer {
 
@@ -51,6 +52,9 @@
 
     MtpStorageList      mStorages;
 
+    MtpPropertyList     mObjectProperties;
+    MtpPropertyList     mDeviceProperties;
+
     // handle for new object, set by SendObjectInfo and used by SendObject
     MtpObjectHandle     mSendObjectHandle;
     MtpString           mSendObjectFilePath;
@@ -66,7 +70,12 @@
     void                scanStorage();
     void                run();
 
+    MtpProperty*        getObjectProperty(MtpPropertyCode propCode);
+    MtpProperty*        getDeviceProperty(MtpPropertyCode propCode);
+
 private:
+    void                initObjectProperties();
+
     bool                handleRequest();
 
     MtpResponseCode     doGetDeviceInfo();