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"; } }
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; }