You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
574 lines
18 KiB
574 lines
18 KiB
/* |
|
* 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" |
|
|
|
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() { |
|
std::string 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", buffer.c_str()); |
|
if (deviceProp) { |
|
buffer = " current value: "; |
|
print(mCurrentValue, buffer); |
|
ALOGI("%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 += ")"; |
|
ALOGI("%s", buffer.c_str()); |
|
break; |
|
case kFormEnum: |
|
buffer = " Enum { "; |
|
for (int i = 0; i < mEnumLength; i++) { |
|
print(mEnumValues[i], buffer); |
|
buffer += " "; |
|
} |
|
buffer += "}"; |
|
ALOGI("%s", buffer.c_str()); |
|
break; |
|
case kFormDateTime: |
|
ALOGI(" DateTime\n"); |
|
break; |
|
default: |
|
ALOGI(" 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: |
|
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
|
|
|