summaryrefslogtreecommitdiffstats
path: root/mtp/ffs/MtpProperty.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mtp/ffs/MtpProperty.cpp')
-rw-r--r--mtp/ffs/MtpProperty.cpp570
1 files changed, 570 insertions, 0 deletions
diff --git a/mtp/ffs/MtpProperty.cpp b/mtp/ffs/MtpProperty.cpp
new file mode 100644
index 000000000..126cb7905
--- /dev/null
+++ b/mtp/ffs/MtpProperty.cpp
@@ -0,0 +1,570 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#define LOG_TAG "MtpProperty"
+
+#include <inttypes.h>
+#include <cutils/compiler.h>
+#include <iomanip>
+#include <sstream>
+#include <string>
+
+#include "MtpDataPacket.h"
+#include "MtpDebug.h"
+#include "MtpProperty.h"
+#include "MtpStringBuffer.h"
+#include "MtpUtils.h"
+
+MtpProperty::MtpProperty()
+ : mCode(0),
+ mType(0),
+ mWriteable(false),
+ mDefaultArrayLength(0),
+ mDefaultArrayValues(NULL),
+ mCurrentArrayLength(0),
+ mCurrentArrayValues(NULL),
+ mGroupCode(0),
+ 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));
+}
+
+MtpProperty::MtpProperty(MtpPropertyCode propCode,
+ MtpDataType type,
+ bool writeable,
+ int defaultValue)
+ : mCode(propCode),
+ mType(type),
+ mWriteable(writeable),
+ mDefaultArrayLength(0),
+ mDefaultArrayValues(NULL),
+ mCurrentArrayLength(0),
+ mCurrentArrayValues(NULL),
+ mGroupCode(0),
+ 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.u.i8 = defaultValue;
+ break;
+ case MTP_TYPE_UINT8:
+ mDefaultValue.u.u8 = defaultValue;
+ break;
+ case MTP_TYPE_INT16:
+ mDefaultValue.u.i16 = defaultValue;
+ break;
+ case MTP_TYPE_UINT16:
+ mDefaultValue.u.u16 = defaultValue;
+ break;
+ case MTP_TYPE_INT32:
+ mDefaultValue.u.i32 = defaultValue;
+ break;
+ case MTP_TYPE_UINT32:
+ mDefaultValue.u.u32 = defaultValue;
+ break;
+ case MTP_TYPE_INT64:
+ mDefaultValue.u.i64 = defaultValue;
+ break;
+ case MTP_TYPE_UINT64:
+ mDefaultValue.u.u64 = defaultValue;
+ break;
+ default:
+ MTPE("unknown type %04X in MtpProperty::MtpProperty", type);
+ }
+ }
+}
+
+MtpProperty::~MtpProperty() {
+ if (mType == MTP_TYPE_STR) {
+ // free all strings
+ free(mDefaultValue.str);
+ free(mCurrentValue.str);
+ free(mMinimumValue.str);
+ free(mMaximumValue.str);
+ if (mDefaultArrayValues) {
+ for (uint32_t i = 0; i < mDefaultArrayLength; i++)
+ free(mDefaultArrayValues[i].str);
+ }
+ if (mCurrentArrayValues) {
+ for (uint32_t i = 0; i < mCurrentArrayLength; i++)
+ free(mCurrentArrayValues[i].str);
+ }
+ if (mEnumValues) {
+ for (uint16_t i = 0; i < mEnumLength; i++)
+ free(mEnumValues[i].str);
+ }
+ }
+ delete[] mDefaultArrayValues;
+ delete[] mCurrentArrayValues;
+ delete[] mEnumValues;
+}
+
+bool MtpProperty::read(MtpDataPacket& packet) {
+ uint8_t temp8;
+
+ if (!packet.getUInt16(mCode)) return false;
+ bool deviceProp = isDeviceProperty();
+ if (!packet.getUInt16(mType)) return false;
+ if (!packet.getUInt8(temp8)) return false;
+ mWriteable = (temp8 == 1);
+ 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:
+ mDefaultArrayValues = readArrayValues(packet, mDefaultArrayLength);
+ if (!mDefaultArrayValues) return false;
+ if (deviceProp) {
+ mCurrentArrayValues = readArrayValues(packet, mCurrentArrayLength);
+ if (!mCurrentArrayValues) return false;
+ }
+ break;
+ default:
+ if (!readValue(packet, mDefaultValue)) return false;
+ if (deviceProp) {
+ if (!readValue(packet, mCurrentValue)) return false;
+ }
+ }
+ if (!deviceProp) {
+ if (!packet.getUInt32(mGroupCode)) return false;
+ }
+ if (!packet.getUInt8(mFormFlag)) return false;
+
+ if (mFormFlag == kFormRange) {
+ if (!readValue(packet, mMinimumValue)) return false;
+ if (!readValue(packet, mMaximumValue)) return false;
+ if (!readValue(packet, mStepSize)) return false;
+ } else if (mFormFlag == kFormEnum) {
+ if (!packet.getUInt16(mEnumLength)) return false;
+ mEnumValues = new MtpPropertyValue[mEnumLength];
+ for (int i = 0; i < mEnumLength; i++) {
+ if (!readValue(packet, mEnumValues[i])) return false;
+ }
+ }
+
+ return true;
+}
+
+void MtpProperty::write(MtpDataPacket& packet) {
+ bool deviceProp = isDeviceProperty();
+
+ 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);
+ if (deviceProp)
+ writeArrayValues(packet, mCurrentArrayValues, mCurrentArrayLength);
+ break;
+ default:
+ writeValue(packet, mDefaultValue);
+ if (deviceProp)
+ writeValue(packet, mCurrentValue);
+ }
+ if (!deviceProp)
+ packet.putUInt32(mGroupCode);
+ 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::setDefaultValue(const uint16_t* string) {
+ free(mDefaultValue.str);
+ if (string) {
+ MtpStringBuffer buffer(string);
+ mDefaultValue.str = strdup(buffer);
+ }
+ else
+ mDefaultValue.str = NULL;
+}
+
+void MtpProperty::setCurrentValue(const uint16_t* string) {
+ free(mCurrentValue.str);
+ if (string) {
+ MtpStringBuffer buffer(string);
+ mCurrentValue.str = strdup(buffer);
+ }
+ else
+ mCurrentValue.str = NULL;
+}
+
+void MtpProperty::setCurrentValue(MtpDataPacket& packet) {
+ free(mCurrentValue.str);
+ mCurrentValue.str = NULL;
+ readValue(packet, mCurrentValue);
+}
+
+void MtpProperty::setFormRange(int min, int max, int step) {
+ mFormFlag = kFormRange;
+ switch (mType) {
+ case MTP_TYPE_INT8:
+ mMinimumValue.u.i8 = min;
+ mMaximumValue.u.i8 = max;
+ mStepSize.u.i8 = step;
+ break;
+ case MTP_TYPE_UINT8:
+ mMinimumValue.u.u8 = min;
+ mMaximumValue.u.u8 = max;
+ mStepSize.u.u8 = step;
+ break;
+ case MTP_TYPE_INT16:
+ mMinimumValue.u.i16 = min;
+ mMaximumValue.u.i16 = max;
+ mStepSize.u.i16 = step;
+ break;
+ case MTP_TYPE_UINT16:
+ mMinimumValue.u.u16 = min;
+ mMaximumValue.u.u16 = max;
+ mStepSize.u.u16 = step;
+ break;
+ case MTP_TYPE_INT32:
+ mMinimumValue.u.i32 = min;
+ mMaximumValue.u.i32 = max;
+ mStepSize.u.i32 = step;
+ break;
+ case MTP_TYPE_UINT32:
+ mMinimumValue.u.u32 = min;
+ mMaximumValue.u.u32 = max;
+ mStepSize.u.u32 = step;
+ break;
+ case MTP_TYPE_INT64:
+ mMinimumValue.u.i64 = min;
+ mMaximumValue.u.i64 = max;
+ mStepSize.u.i64 = step;
+ break;
+ case MTP_TYPE_UINT64:
+ mMinimumValue.u.u64 = min;
+ mMaximumValue.u.u64 = max;
+ mStepSize.u.u64 = step;
+ break;
+ default:
+ MTPE("unsupported type for MtpProperty::setRange");
+ break;
+ }
+}
+
+void MtpProperty::setFormEnum(const int* values, int count) {
+ mFormFlag = kFormEnum;
+ delete[] mEnumValues;
+ mEnumValues = new MtpPropertyValue[count];
+ mEnumLength = count;
+
+ for (int i = 0; i < count; i++) {
+ int value = *values++;
+ switch (mType) {
+ case MTP_TYPE_INT8:
+ mEnumValues[i].u.i8 = value;
+ break;
+ case MTP_TYPE_UINT8:
+ mEnumValues[i].u.u8 = value;
+ break;
+ case MTP_TYPE_INT16:
+ mEnumValues[i].u.i16 = value;
+ break;
+ case MTP_TYPE_UINT16:
+ mEnumValues[i].u.u16 = value;
+ break;
+ case MTP_TYPE_INT32:
+ mEnumValues[i].u.i32 = value;
+ break;
+ case MTP_TYPE_UINT32:
+ mEnumValues[i].u.u32 = value;
+ break;
+ case MTP_TYPE_INT64:
+ mEnumValues[i].u.i64 = value;
+ break;
+ case MTP_TYPE_UINT64:
+ mEnumValues[i].u.u64 = value;
+ break;
+ default:
+ MTPE("unsupported type for MtpProperty::setEnum");
+ break;
+ }
+ }
+}
+
+void MtpProperty::setFormDateTime() {
+ mFormFlag = kFormDateTime;
+}
+
+void MtpProperty::print() {
+ std::string buffer;
+ bool deviceProp = isDeviceProperty();
+ if (deviceProp)
+ MTPD(" %s (%04X)", MtpDebug::getDevicePropCodeName(mCode), mCode);
+ else
+ MTPD(" %s (%04X)", MtpDebug::getObjectPropCodeName(mCode), mCode);
+ MTPD(" type %04X", mType);
+ MTPD(" writeable %s", (mWriteable ? "true" : "false"));
+ buffer = " default value: ";
+ print(mDefaultValue, buffer);
+ MTPD("%s", buffer.c_str());
+ if (deviceProp) {
+ buffer = " current value: ";
+ print(mCurrentValue, buffer);
+ MTPD("%s", buffer.c_str());
+ }
+ switch (mFormFlag) {
+ case kFormNone:
+ break;
+ case kFormRange:
+ buffer = " Range (";
+ print(mMinimumValue, buffer);
+ buffer += ", ";
+ print(mMaximumValue, buffer);
+ buffer += ", ";
+ print(mStepSize, buffer);
+ buffer += ")";
+ MTPD("%s", buffer.c_str());
+ break;
+ case kFormEnum:
+ buffer = " Enum { ";
+ for (int i = 0; i < mEnumLength; i++) {
+ print(mEnumValues[i], buffer);
+ buffer += " ";
+ }
+ buffer += "}";
+ MTPD("%s", buffer.c_str());
+ break;
+ case kFormDateTime:
+ MTPD(" DateTime\n");
+ break;
+ default:
+ MTPD(" form %d\n", mFormFlag);
+ break;
+ }
+}
+
+void MtpProperty::print(MtpPropertyValue& value, std::string& buffer) {
+ std::ostringstream s;
+ switch (mType) {
+ case MTP_TYPE_INT8:
+ buffer += std::to_string(value.u.i8);
+ break;
+ case MTP_TYPE_UINT8:
+ buffer += std::to_string(value.u.u8);
+ break;
+ case MTP_TYPE_INT16:
+ buffer += std::to_string(value.u.i16);
+ break;
+ case MTP_TYPE_UINT16:
+ buffer += std::to_string(value.u.u16);
+ break;
+ case MTP_TYPE_INT32:
+ buffer += std::to_string(value.u.i32);
+ break;
+ case MTP_TYPE_UINT32:
+ buffer += std::to_string(value.u.u32);
+ break;
+ case MTP_TYPE_INT64:
+ buffer += std::to_string(value.u.i64);
+ break;
+ case MTP_TYPE_UINT64:
+ buffer += std::to_string(value.u.u64);
+ break;
+ case MTP_TYPE_INT128:
+ for (auto i : value.u.i128) {
+ s << std::hex << std::setfill('0') << std::uppercase << i;
+ }
+ buffer += s.str();
+ break;
+ case MTP_TYPE_UINT128:
+ for (auto i : value.u.u128) {
+ s << std::hex << std::setfill('0') << std::uppercase << i;
+ }
+ buffer += s.str();
+ break;
+ case MTP_TYPE_STR:
+ buffer += value.str;
+ break;
+ default:
+ MTPE("unsupported type for MtpProperty::print\n");
+ break;
+ }
+}
+
+bool MtpProperty::readValue(MtpDataPacket& packet, MtpPropertyValue& value) {
+ MtpStringBuffer stringBuffer;
+
+ switch (mType) {
+ case MTP_TYPE_INT8:
+ case MTP_TYPE_AINT8:
+ if (!packet.getInt8(value.u.i8)) return false;
+ break;
+ case MTP_TYPE_UINT8:
+ case MTP_TYPE_AUINT8:
+ if (!packet.getUInt8(value.u.u8)) return false;
+ break;
+ case MTP_TYPE_INT16:
+ case MTP_TYPE_AINT16:
+ if (!packet.getInt16(value.u.i16)) return false;
+ break;
+ case MTP_TYPE_UINT16:
+ case MTP_TYPE_AUINT16:
+ if (!packet.getUInt16(value.u.u16)) return false;
+ break;
+ case MTP_TYPE_INT32:
+ case MTP_TYPE_AINT32:
+ if (!packet.getInt32(value.u.i32)) return false;
+ break;
+ case MTP_TYPE_UINT32:
+ case MTP_TYPE_AUINT32:
+ if (!packet.getUInt32(value.u.u32)) return false;
+ break;
+ case MTP_TYPE_INT64:
+ case MTP_TYPE_AINT64:
+ if (!packet.getInt64(value.u.i64)) return false;
+ break;
+ case MTP_TYPE_UINT64:
+ case MTP_TYPE_AUINT64:
+ if (!packet.getUInt64(value.u.u64)) return false;
+ break;
+ case MTP_TYPE_INT128:
+ case MTP_TYPE_AINT128:
+ if (!packet.getInt128(value.u.i128)) return false;
+ break;
+ case MTP_TYPE_UINT128:
+ case MTP_TYPE_AUINT128:
+ if (!packet.getUInt128(value.u.u128)) return false;
+ break;
+ case MTP_TYPE_STR:
+ if (!packet.getString(stringBuffer)) return false;
+ value.str = strdup(stringBuffer);
+ break;
+ default:
+ MTPE("unknown type %04X in MtpProperty::readValue", mType);
+ return false;
+ }
+ return true;
+}
+
+void MtpProperty::writeValue(MtpDataPacket& packet, MtpPropertyValue& value) {
+ MtpStringBuffer stringBuffer;
+
+ switch (mType) {
+ case MTP_TYPE_INT8:
+ case MTP_TYPE_AINT8:
+ packet.putInt8(value.u.i8);
+ break;
+ case MTP_TYPE_UINT8:
+ case MTP_TYPE_AUINT8:
+ packet.putUInt8(value.u.u8);
+ break;
+ case MTP_TYPE_INT16:
+ case MTP_TYPE_AINT16:
+ packet.putInt16(value.u.i16);
+ break;
+ case MTP_TYPE_UINT16:
+ case MTP_TYPE_AUINT16:
+ packet.putUInt16(value.u.u16);
+ break;
+ case MTP_TYPE_INT32:
+ case MTP_TYPE_AINT32:
+ packet.putInt32(value.u.i32);
+ break;
+ case MTP_TYPE_UINT32:
+ case MTP_TYPE_AUINT32:
+ packet.putUInt32(value.u.u32);
+ break;
+ case MTP_TYPE_INT64:
+ case MTP_TYPE_AINT64:
+ packet.putInt64(value.u.i64);
+ break;
+ case MTP_TYPE_UINT64:
+ case MTP_TYPE_AUINT64:
+ packet.putUInt64(value.u.u64);
+ break;
+ case MTP_TYPE_INT128:
+ case MTP_TYPE_AINT128:
+ packet.putInt128(value.u.i128);
+ break;
+ case MTP_TYPE_UINT128:
+ case MTP_TYPE_AUINT128:
+ packet.putUInt128(value.u.u128);
+ break;
+ case MTP_TYPE_STR:
+ if (value.str)
+ packet.putString(value.str);
+ else
+ packet.putEmptyString();
+ break;
+ default:
+ MTPE("unknown type %04X in MtpProperty::writeValue", mType);
+ }
+}
+
+MtpPropertyValue* MtpProperty::readArrayValues(MtpDataPacket& packet, uint32_t& length) {
+ if (!packet.getUInt32(length)) return NULL;
+
+ // Fail if resulting array is over 2GB. This is because the maximum array
+ // size may be less than SIZE_MAX on some platforms.
+ if ( CC_UNLIKELY(
+ length == 0 ||
+ length >= INT32_MAX / sizeof(MtpPropertyValue)) ) {
+ length = 0;
+ return NULL;
+ }
+ MtpPropertyValue* result = new MtpPropertyValue[length];
+ for (uint32_t i = 0; i < length; i++)
+ if (!readValue(packet, result[i])) {
+ delete [] result;
+ return NULL;
+ }
+ return result;
+}
+
+void MtpProperty::writeArrayValues(MtpDataPacket& packet, MtpPropertyValue* values, uint32_t length) {
+ packet.putUInt32(length);
+ for (uint32_t i = 0; i < length; i++)
+ writeValue(packet, values[i]);
+}