/* * 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 "MtpDataPacket.h" #include "MtpDebug.h" #include "MtpProperty.h" #include "MtpStringBuffer.h" #include "MtpUtils.h" namespace android { 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: ALOGE("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: ALOGE("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: ALOGE("unsupported type for MtpProperty::setEnum"); break; } } } void MtpProperty::setFormDateTime() { mFormFlag = kFormDateTime; } void MtpProperty::print() { MtpString buffer; bool deviceProp = isDeviceProperty(); if (deviceProp) ALOGI(" %s (%04X)", MtpDebug::getDevicePropCodeName(mCode), mCode); else ALOGI(" %s (%04X)", MtpDebug::getObjectPropCodeName(mCode), mCode); ALOGI(" type %04X", mType); ALOGI(" writeable %s", (mWriteable ? "true" : "false")); buffer = " default value: "; print(mDefaultValue, buffer); ALOGI("%s", (const char *)buffer); if (deviceProp) { buffer = " current value: "; print(mCurrentValue, buffer); ALOGI("%s", (const char *)buffer); } switch (mFormFlag) { case kFormNone: break; case kFormRange: buffer = " Range ("; print(mMinimumValue, buffer); buffer += ", "; print(mMaximumValue, buffer); buffer += ", "; print(mStepSize, buffer); buffer += ")"; ALOGI("%s", (const char *)buffer); break; case kFormEnum: buffer = " Enum { "; for (int i = 0; i < mEnumLength; i++) { print(mEnumValues[i], buffer); buffer += " "; } buffer += "}"; ALOGI("%s", (const char *)buffer); break; case kFormDateTime: ALOGI(" DateTime\n"); break; default: ALOGI(" form %d\n", mFormFlag); break; } } void MtpProperty::print(MtpPropertyValue& value, MtpString& buffer) { switch (mType) { case MTP_TYPE_INT8: buffer.appendFormat("%d", value.u.i8); break; case MTP_TYPE_UINT8: buffer.appendFormat("%d", value.u.u8); break; case MTP_TYPE_INT16: buffer.appendFormat("%d", value.u.i16); break; case MTP_TYPE_UINT16: buffer.appendFormat("%d", value.u.u16); break; case MTP_TYPE_INT32: buffer.appendFormat("%d", value.u.i32); break; case MTP_TYPE_UINT32: buffer.appendFormat("%d", value.u.u32); break; case MTP_TYPE_INT64: buffer.appendFormat("%" PRId64, value.u.i64); break; case MTP_TYPE_UINT64: buffer.appendFormat("%" PRIu64, value.u.u64); break; case MTP_TYPE_INT128: buffer.appendFormat("%08X%08X%08X%08X", value.u.i128[0], value.u.i128[1], value.u.i128[2], value.u.i128[3]); break; case MTP_TYPE_UINT128: buffer.appendFormat("%08X%08X%08X%08X", value.u.u128[0], value.u.u128[1], value.u.u128[2], value.u.u128[3]); break; case MTP_TYPE_STR: buffer.appendFormat("%s", value.str); break; default: ALOGE("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: ALOGE("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: ALOGE("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]); } } // namespace android