//virtual MtpResponseCode MozMtpDatabase::getObjectPropertyValue(MtpObjectHandle aHandle, MtpObjectProperty aProperty, MtpDataPacket& aPacket) { RefPtr<DbEntry> entry = GetEntry(aHandle); if (!entry) { MTP_ERR("Invalid Handle: 0x%08x", aHandle); return MTP_RESPONSE_INVALID_OBJECT_HANDLE; } MTP_LOG("Handle: 0x%08x '%s' Property: %s 0x%08x", aHandle, entry->mDisplayName.get(), ObjectPropertyAsStr(aProperty), aProperty); switch (aProperty) { case MTP_PROPERTY_STORAGE_ID: aPacket.putUInt32(entry->mStorageID); break; case MTP_PROPERTY_PARENT_OBJECT: aPacket.putUInt32(entry->mParent); break; case MTP_PROPERTY_OBJECT_FORMAT: aPacket.putUInt16(entry->mObjectFormat); break; case MTP_PROPERTY_OBJECT_SIZE: aPacket.putUInt64(entry->mObjectSize); break; case MTP_PROPERTY_DISPLAY_NAME: aPacket.putString(entry->mDisplayName.get()); break; case MTP_PROPERTY_PERSISTENT_UID: // the same as aPacket.putUInt128 aPacket.putUInt64(entry->mHandle); aPacket.putUInt64(entry->mStorageID); break; case MTP_PROPERTY_NAME: aPacket.putString(entry->mDisplayName.get()); break; default: MTP_LOG("Invalid Property: 0x%08x", aProperty); return MTP_RESPONSE_INVALID_OBJECT_PROP_CODE; } return MTP_RESPONSE_OK; }
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: LOG(ERROR) << "unknown type " << std::hex << mType << std::dec << " in MtpProperty::writeValue"; } }
//virtual MtpResponseCode MozMtpDatabase::getObjectPropertyList(MtpObjectHandle aHandle, uint32_t aFormat, uint32_t aProperty, int aGroupCode, int aDepth, MtpDataPacket& aPacket) { MTP_LOG("Handle: 0x%08x Format: 0x%08x aProperty: 0x%08x aGroupCode: %d aDepth %d", aHandle, aFormat, aProperty, aGroupCode, aDepth); if (aDepth > 1) { return MTP_RESPONSE_SPECIFICATION_BY_DEPTH_UNSUPPORTED; } if (aGroupCode != 0) { return MTP_RESPONSE_SPECIFICATION_BY_GROUP_UNSUPPORTED; } MatchType matchType = MatchAll; uint32_t matchField1 = 0; uint32_t matchField2 = 0; // aHandle == 0 implies all objects at the root level // further specificed by aFormat and/or aDepth if (aFormat == 0) { if (aHandle == 0xffffffff) { // select all objects matchType = MatchAll; } else { if (aDepth == 1) { // select objects whose Parent matches aHandle matchType = MatchParent; matchField1 = aHandle; } else { // select object whose handle matches aHandle matchType = MatchHandle; matchField1 = aHandle; } } } else { if (aHandle == 0xffffffff) { // select all objects whose format matches aFormat matchType = MatchFormat; matchField1 = aFormat; } else { if (aDepth == 1) { // select objects whose Parent is aHandle and format matches aFormat matchType = MatchParentFormat; matchField1 = aHandle; matchField2 = aFormat; } else { // select objects whose handle is aHandle and format matches aFormat matchType = MatchHandleFormat; matchField1 = aHandle; matchField2 = aFormat; } } } UnprotectedDbArray result; QueryEntries(matchType, matchField1, matchField2, result); const MtpObjectProperty *objectPropertyList; size_t numObjectProperties = 0; MtpObjectProperty objectProperty; if (aProperty == 0xffffffff) { // return all supported properties numObjectProperties = MOZ_ARRAY_LENGTH(sSupportedObjectProperties); objectPropertyList = sSupportedObjectProperties; } else { // return property indicated by aProperty numObjectProperties = 1; objectProperty = aProperty; objectPropertyList = &objectProperty; } UnprotectedDbArray::size_type numEntries = result.Length(); UnprotectedDbArray::index_type entryIdx; char dateStr[20]; aPacket.putUInt32(numObjectProperties * numEntries); for (entryIdx = 0; entryIdx < numEntries; entryIdx++) { RefPtr<DbEntry> entry = result[entryIdx]; for (size_t propertyIdx = 0; propertyIdx < numObjectProperties; propertyIdx++) { aPacket.putUInt32(entry->mHandle); MtpObjectProperty prop = objectPropertyList[propertyIdx]; aPacket.putUInt16(prop); switch (prop) { case MTP_PROPERTY_STORAGE_ID: aPacket.putUInt16(MTP_TYPE_UINT32); aPacket.putUInt32(entry->mStorageID); break; case MTP_PROPERTY_PARENT_OBJECT: aPacket.putUInt16(MTP_TYPE_UINT32); aPacket.putUInt32(entry->mParent); break; case MTP_PROPERTY_PERSISTENT_UID: aPacket.putUInt16(MTP_TYPE_UINT128); // the same as aPacket.putUInt128 aPacket.putUInt64(entry->mHandle); aPacket.putUInt64(entry->mStorageID); break; case MTP_PROPERTY_OBJECT_FORMAT: aPacket.putUInt16(MTP_TYPE_UINT16); aPacket.putUInt16(entry->mObjectFormat); break; case MTP_PROPERTY_OBJECT_SIZE: aPacket.putUInt16(MTP_TYPE_UINT64); aPacket.putUInt64(entry->mObjectSize); break; case MTP_PROPERTY_OBJECT_FILE_NAME: case MTP_PROPERTY_NAME: aPacket.putUInt16(MTP_TYPE_STR); aPacket.putString(entry->mObjectName.get()); break; case MTP_PROPERTY_PROTECTION_STATUS: aPacket.putUInt16(MTP_TYPE_UINT16); aPacket.putUInt16(0); // 0 = No Protection break; case MTP_PROPERTY_DATE_CREATED: { aPacket.putUInt16(MTP_TYPE_STR); aPacket.putString(FormatDate(entry->mDateCreated, dateStr, sizeof(dateStr))); MTP_LOG("mDateCreated: (%ld) %s", entry->mDateCreated, dateStr); break; } case MTP_PROPERTY_DATE_MODIFIED: { aPacket.putUInt16(MTP_TYPE_STR); aPacket.putString(FormatDate(entry->mDateModified, dateStr, sizeof(dateStr))); MTP_LOG("mDateModified: (%ld) %s", entry->mDateModified, dateStr); break; } case MTP_PROPERTY_DATE_ADDED: { aPacket.putUInt16(MTP_TYPE_STR); aPacket.putString(FormatDate(entry->mDateAdded, dateStr, sizeof(dateStr))); MTP_LOG("mDateAdded: (%ld) %s", entry->mDateAdded, dateStr); break; } default: MTP_ERR("Unrecognized property code: %u", prop); return MTP_RESPONSE_GENERAL_ERROR; } } } return MTP_RESPONSE_OK; }
int MtpStorage::getObjectPropertyList(MtpObjectHandle handle, uint32_t format, uint32_t property, int groupCode, int depth, MtpDataPacket& packet) { MTPD("MtpStorage::getObjectPropertyList handle: %u, format: %x, property: %x\n", handle, format, property); if (groupCode != 0) { MTPE("getObjectPropertyList: groupCode unsupported\n"); return -1; // TODO: RESPONSE_SPECIFICATION_BY_GROUP_UNSUPPORTED } // TODO: support all the special stuff, like: // handle == 0 -> all objects at the root level // handle == 0xffffffff -> all objects (on all storages? how could we support that?) // format == 0 -> all formats, otherwise filter by ObjectFormatCode // property == 0xffffffff -> all properties except those with group code 0xffffffff // if property == 0 then use groupCode // groupCode == 0 -> return Specification_By_Group_Unsupported // depth == 0xffffffff -> all objects incl. and below handle std::vector<PropEntry> results; if (handle == 0xffffffff) { // TODO: all object on all storages (needs a different design, result packet needs to be built by server instead of storage) } else if (handle == 0) { // all objects at the root level Tree* root = mtpmap[0]; MtpObjectHandleList list; root->getmtpids(&list); for (MtpObjectHandleList::iterator it = list.begin(); it != list.end(); ++it) { Node* node = root->findNode(*it); if (!node) { MTPE("BUG: node not found for root entry with handle %u\n", *it); break; } queryNodeProperties(results, node, property, groupCode, mStorageID); } } else { // single object Node* node = findNode(handle); if (!node) { // Item is not on this storage device return -1; } queryNodeProperties(results, node, property, groupCode, mStorageID); } MTPD("count: %u\n", results.size()); packet.putUInt32(results.size()); for (size_t i = 0; i < results.size(); ++i) { PropEntry& p = results[i]; MTPD("handle: %u, propertyCode: %x = %s, datatype: %x, value: %llu\n", p.handle, p.property, MtpDebug::getObjectPropCodeName(p.property), p.datatype, p.intvalue); packet.putUInt32(p.handle); packet.putUInt16(p.property); packet.putUInt16(p.datatype); switch (p.datatype) { case MTP_TYPE_INT8: MTPD("MTP_TYPE_INT8\n"); packet.putInt8(p.intvalue); break; case MTP_TYPE_UINT8: MTPD("MTP_TYPE_UINT8\n"); packet.putUInt8(p.intvalue); break; case MTP_TYPE_INT16: MTPD("MTP_TYPE_INT16\n"); packet.putInt16(p.intvalue); break; case MTP_TYPE_UINT16: MTPD("MTP_TYPE_UINT16\n"); packet.putUInt16(p.intvalue); break; case MTP_TYPE_INT32: MTPD("MTP_TYPE_INT32\n"); packet.putInt32(p.intvalue); break; case MTP_TYPE_UINT32: MTPD("MTP_TYPE_UINT32\n"); packet.putUInt32(p.intvalue); break; case MTP_TYPE_INT64: MTPD("MTP_TYPE_INT64\n"); packet.putInt64(p.intvalue); break; case MTP_TYPE_UINT64: MTPD("MTP_TYPE_UINT64\n"); packet.putUInt64(p.intvalue); break; case MTP_TYPE_INT128: MTPD("MTP_TYPE_INT128\n"); packet.putInt128(p.intvalue); break; case MTP_TYPE_UINT128: MTPD("MTP_TYPE_UINT128\n"); packet.putUInt128(p.intvalue); break; case MTP_TYPE_STR: MTPD("MTP_TYPE_STR: %s\n", p.strvalue.c_str()); packet.putString(p.strvalue.c_str()); break; default: MTPE("bad or unsupported data type: %x in MyMtpDatabase::getObjectPropertyList", p.datatype); break; } } return 0; }
MtpResponseCode MyMtpDatabase::getObjectPropertyList(MtpObjectHandle handle, uint32_t format, uint32_t property, int groupCode, int depth, MtpDataPacket& packet) { JNIEnv* env = AndroidRuntime::getJNIEnv(); jobject list = env->CallObjectMethod(mDatabase, method_getObjectPropertyList, (jlong)handle, (jint)format, (jlong)property, (jint)groupCode, (jint)depth); checkAndClearExceptionFromCallback(env, __FUNCTION__); if (!list) return MTP_RESPONSE_GENERAL_ERROR; int count = env->GetIntField(list, field_mCount); MtpResponseCode result = env->GetIntField(list, field_mResult); packet.putUInt32(count); if (count > 0) { jintArray objectHandlesArray = (jintArray)env->GetObjectField(list, field_mObjectHandles); jintArray propertyCodesArray = (jintArray)env->GetObjectField(list, field_mPropertyCodes); jintArray dataTypesArray = (jintArray)env->GetObjectField(list, field_mDataTypes); jlongArray longValuesArray = (jlongArray)env->GetObjectField(list, field_mLongValues); jobjectArray stringValuesArray = (jobjectArray)env->GetObjectField(list, field_mStringValues); jint* objectHandles = env->GetIntArrayElements(objectHandlesArray, 0); jint* propertyCodes = env->GetIntArrayElements(propertyCodesArray, 0); jint* dataTypes = env->GetIntArrayElements(dataTypesArray, 0); jlong* longValues = (longValuesArray ? env->GetLongArrayElements(longValuesArray, 0) : NULL); for (int i = 0; i < count; i++) { packet.putUInt32(objectHandles[i]); packet.putUInt16(propertyCodes[i]); int type = dataTypes[i]; packet.putUInt16(type); switch (type) { case MTP_TYPE_INT8: packet.putInt8(longValues[i]); break; case MTP_TYPE_UINT8: packet.putUInt8(longValues[i]); break; case MTP_TYPE_INT16: packet.putInt16(longValues[i]); break; case MTP_TYPE_UINT16: packet.putUInt16(longValues[i]); break; case MTP_TYPE_INT32: packet.putInt32(longValues[i]); break; case MTP_TYPE_UINT32: packet.putUInt32(longValues[i]); break; case MTP_TYPE_INT64: packet.putInt64(longValues[i]); break; case MTP_TYPE_UINT64: packet.putUInt64(longValues[i]); break; case MTP_TYPE_INT128: packet.putInt128(longValues[i]); break; case MTP_TYPE_UINT128: packet.putUInt128(longValues[i]); break; case MTP_TYPE_STR: { jstring value = (jstring)env->GetObjectArrayElement(stringValuesArray, i); const char *valueStr = (value ? env->GetStringUTFChars(value, NULL) : NULL); if (valueStr) { packet.putString(valueStr); env->ReleaseStringUTFChars(value, valueStr); } else { packet.putEmptyString(); } env->DeleteLocalRef(value); break; } default: ALOGE("bad or unsupported data type in MyMtpDatabase::getObjectPropertyList"); break; } } env->ReleaseIntArrayElements(objectHandlesArray, objectHandles, 0); env->ReleaseIntArrayElements(propertyCodesArray, propertyCodes, 0); env->ReleaseIntArrayElements(dataTypesArray, dataTypes, 0); if (longValues) env->ReleaseLongArrayElements(longValuesArray, longValues, 0); env->DeleteLocalRef(objectHandlesArray); env->DeleteLocalRef(propertyCodesArray); env->DeleteLocalRef(dataTypesArray); if (longValuesArray) env->DeleteLocalRef(longValuesArray); if (stringValuesArray) env->DeleteLocalRef(stringValuesArray); } env->DeleteLocalRef(list); checkAndClearExceptionFromCallback(env, __FUNCTION__); return result; }
MtpResponseCode MyMtpDatabase::getDevicePropertyValue(MtpDeviceProperty property, MtpDataPacket& packet) { int type; if (!getDevicePropertyInfo(property, type)) return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED; JNIEnv* env = AndroidRuntime::getJNIEnv(); jint result = env->CallIntMethod(mDatabase, method_getDeviceProperty, (jint)property, mLongBuffer, mStringBuffer); if (result != MTP_RESPONSE_OK) { checkAndClearExceptionFromCallback(env, __FUNCTION__); return result; } jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0); jlong longValue = longValues[0]; env->ReleaseLongArrayElements(mLongBuffer, longValues, 0); switch (type) { case MTP_TYPE_INT8: packet.putInt8(longValue); break; case MTP_TYPE_UINT8: packet.putUInt8(longValue); break; case MTP_TYPE_INT16: packet.putInt16(longValue); break; case MTP_TYPE_UINT16: packet.putUInt16(longValue); break; case MTP_TYPE_INT32: packet.putInt32(longValue); break; case MTP_TYPE_UINT32: packet.putUInt32(longValue); break; case MTP_TYPE_INT64: packet.putInt64(longValue); break; case MTP_TYPE_UINT64: packet.putUInt64(longValue); break; case MTP_TYPE_INT128: packet.putInt128(longValue); break; case MTP_TYPE_UINT128: packet.putInt128(longValue); break; case MTP_TYPE_STR: { jchar* str = env->GetCharArrayElements(mStringBuffer, 0); packet.putString(str); env->ReleaseCharArrayElements(mStringBuffer, str, 0); break; } default: ALOGE("unsupported type in getDevicePropertyValue\n"); return MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT; } checkAndClearExceptionFromCallback(env, __FUNCTION__); return MTP_RESPONSE_OK; }
MtpResponseCode MyMtpDatabase::getObjectPropertyValue(MtpObjectHandle handle, MtpObjectProperty property, MtpDataPacket& packet) { JNIEnv* env = AndroidRuntime::getJNIEnv(); jobject list = env->CallObjectMethod(mDatabase, method_getObjectPropertyList, (jlong)handle, 0, (jlong)property, 0, 0); MtpResponseCode result = env->GetIntField(list, field_mResult); int count = env->GetIntField(list, field_mCount); if (result == MTP_RESPONSE_OK && count != 1) result = MTP_RESPONSE_GENERAL_ERROR; if (result == MTP_RESPONSE_OK) { jintArray objectHandlesArray = (jintArray)env->GetObjectField(list, field_mObjectHandles); jintArray propertyCodesArray = (jintArray)env->GetObjectField(list, field_mPropertyCodes); jintArray dataTypesArray = (jintArray)env->GetObjectField(list, field_mDataTypes); jlongArray longValuesArray = (jlongArray)env->GetObjectField(list, field_mLongValues); jobjectArray stringValuesArray = (jobjectArray)env->GetObjectField(list, field_mStringValues); jint* objectHandles = env->GetIntArrayElements(objectHandlesArray, 0); jint* propertyCodes = env->GetIntArrayElements(propertyCodesArray, 0); jint* dataTypes = env->GetIntArrayElements(dataTypesArray, 0); jlong* longValues = (longValuesArray ? env->GetLongArrayElements(longValuesArray, 0) : NULL); int type = dataTypes[0]; jlong longValue = (longValues ? longValues[0] : 0); // special case date properties, which are strings to MTP // but stored internally as a uint64 if (property == MTP_PROPERTY_DATE_MODIFIED || property == MTP_PROPERTY_DATE_ADDED) { char date[20]; formatDateTime(longValue, date, sizeof(date)); packet.putString(date); goto out; } // release date is stored internally as just the year if (property == MTP_PROPERTY_ORIGINAL_RELEASE_DATE) { char date[20]; snprintf(date, sizeof(date), "%04" PRId64 "0101T000000", longValue); packet.putString(date); goto out; } switch (type) { case MTP_TYPE_INT8: packet.putInt8(longValue); break; case MTP_TYPE_UINT8: packet.putUInt8(longValue); break; case MTP_TYPE_INT16: packet.putInt16(longValue); break; case MTP_TYPE_UINT16: packet.putUInt16(longValue); break; case MTP_TYPE_INT32: packet.putInt32(longValue); break; case MTP_TYPE_UINT32: packet.putUInt32(longValue); break; case MTP_TYPE_INT64: packet.putInt64(longValue); break; case MTP_TYPE_UINT64: packet.putUInt64(longValue); break; case MTP_TYPE_INT128: packet.putInt128(longValue); break; case MTP_TYPE_UINT128: packet.putInt128(longValue); break; case MTP_TYPE_STR: { jstring stringValue = (jstring)env->GetObjectArrayElement(stringValuesArray, 0); const char* str = (stringValue ? env->GetStringUTFChars(stringValue, NULL) : NULL); if (stringValue) { packet.putString(str); env->ReleaseStringUTFChars(stringValue, str); } else { packet.putEmptyString(); } env->DeleteLocalRef(stringValue); break; } default: ALOGE("unsupported type in getObjectPropertyValue\n"); result = MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT; } out: env->ReleaseIntArrayElements(objectHandlesArray, objectHandles, 0); env->ReleaseIntArrayElements(propertyCodesArray, propertyCodes, 0); env->ReleaseIntArrayElements(dataTypesArray, dataTypes, 0); if (longValues) env->ReleaseLongArrayElements(longValuesArray, longValues, 0); env->DeleteLocalRef(objectHandlesArray); env->DeleteLocalRef(propertyCodesArray); env->DeleteLocalRef(dataTypesArray); if (longValuesArray) env->DeleteLocalRef(longValuesArray); if (stringValuesArray) env->DeleteLocalRef(stringValuesArray); } env->DeleteLocalRef(list); checkAndClearExceptionFromCallback(env, __FUNCTION__); return result; }