MtpProperty.cpp revision eb5d7f2f1cc049ea7f95a4f089ce2113d7683dda
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "MtpProperty"
18
19#include <inttypes.h>
20#include <cutils/compiler.h>
21#include "MtpDataPacket.h"
22#include "MtpDebug.h"
23#include "MtpProperty.h"
24#include "MtpStringBuffer.h"
25#include "MtpUtils.h"
26
27namespace android {
28
29MtpProperty::MtpProperty()
30    :   mCode(0),
31        mType(0),
32        mWriteable(false),
33        mDefaultArrayLength(0),
34        mDefaultArrayValues(NULL),
35        mCurrentArrayLength(0),
36        mCurrentArrayValues(NULL),
37        mGroupCode(0),
38        mFormFlag(kFormNone),
39        mEnumLength(0),
40        mEnumValues(NULL)
41{
42    memset(&mDefaultValue, 0, sizeof(mDefaultValue));
43    memset(&mCurrentValue, 0, sizeof(mCurrentValue));
44    memset(&mMinimumValue, 0, sizeof(mMinimumValue));
45    memset(&mMaximumValue, 0, sizeof(mMaximumValue));
46}
47
48MtpProperty::MtpProperty(MtpPropertyCode propCode,
49                         MtpDataType type,
50                         bool writeable,
51                         int defaultValue)
52    :   mCode(propCode),
53        mType(type),
54        mWriteable(writeable),
55        mDefaultArrayLength(0),
56        mDefaultArrayValues(NULL),
57        mCurrentArrayLength(0),
58        mCurrentArrayValues(NULL),
59        mGroupCode(0),
60        mFormFlag(kFormNone),
61        mEnumLength(0),
62        mEnumValues(NULL)
63{
64    memset(&mDefaultValue, 0, sizeof(mDefaultValue));
65    memset(&mCurrentValue, 0, sizeof(mCurrentValue));
66    memset(&mMinimumValue, 0, sizeof(mMinimumValue));
67    memset(&mMaximumValue, 0, sizeof(mMaximumValue));
68
69    if (defaultValue) {
70        switch (type) {
71            case MTP_TYPE_INT8:
72                mDefaultValue.u.i8 = defaultValue;
73                break;
74            case MTP_TYPE_UINT8:
75                mDefaultValue.u.u8 = defaultValue;
76                break;
77            case MTP_TYPE_INT16:
78                mDefaultValue.u.i16 = defaultValue;
79                break;
80            case MTP_TYPE_UINT16:
81                mDefaultValue.u.u16 = defaultValue;
82                break;
83            case MTP_TYPE_INT32:
84                mDefaultValue.u.i32 = defaultValue;
85                break;
86            case MTP_TYPE_UINT32:
87                mDefaultValue.u.u32 = defaultValue;
88                break;
89            case MTP_TYPE_INT64:
90                mDefaultValue.u.i64 = defaultValue;
91                break;
92            case MTP_TYPE_UINT64:
93                mDefaultValue.u.u64 = defaultValue;
94                break;
95            default:
96                ALOGE("unknown type %04X in MtpProperty::MtpProperty", type);
97        }
98    }
99}
100
101MtpProperty::~MtpProperty() {
102    if (mType == MTP_TYPE_STR) {
103        // free all strings
104        free(mDefaultValue.str);
105        free(mCurrentValue.str);
106        free(mMinimumValue.str);
107        free(mMaximumValue.str);
108        if (mDefaultArrayValues) {
109            for (int i = 0; i < mDefaultArrayLength; i++)
110                free(mDefaultArrayValues[i].str);
111        }
112        if (mCurrentArrayValues) {
113            for (int i = 0; i < mCurrentArrayLength; i++)
114                free(mCurrentArrayValues[i].str);
115        }
116        if (mEnumValues) {
117            for (int i = 0; i < mEnumLength; i++)
118                free(mEnumValues[i].str);
119        }
120    }
121    delete[] mDefaultArrayValues;
122    delete[] mCurrentArrayValues;
123    delete[] mEnumValues;
124}
125
126void MtpProperty::read(MtpDataPacket& packet) {
127    mCode = packet.getUInt16();
128    bool deviceProp = isDeviceProperty();
129    mType = packet.getUInt16();
130    mWriteable = (packet.getUInt8() == 1);
131    switch (mType) {
132        case MTP_TYPE_AINT8:
133        case MTP_TYPE_AUINT8:
134        case MTP_TYPE_AINT16:
135        case MTP_TYPE_AUINT16:
136        case MTP_TYPE_AINT32:
137        case MTP_TYPE_AUINT32:
138        case MTP_TYPE_AINT64:
139        case MTP_TYPE_AUINT64:
140        case MTP_TYPE_AINT128:
141        case MTP_TYPE_AUINT128:
142            mDefaultArrayValues = readArrayValues(packet, mDefaultArrayLength);
143            if (deviceProp)
144                mCurrentArrayValues = readArrayValues(packet, mCurrentArrayLength);
145            break;
146        default:
147            readValue(packet, mDefaultValue);
148            if (deviceProp)
149                readValue(packet, mCurrentValue);
150    }
151    if (!deviceProp)
152        mGroupCode = packet.getUInt32();
153    mFormFlag = packet.getUInt8();
154
155    if (mFormFlag == kFormRange) {
156            readValue(packet, mMinimumValue);
157            readValue(packet, mMaximumValue);
158            readValue(packet, mStepSize);
159    } else if (mFormFlag == kFormEnum) {
160        mEnumLength = packet.getUInt16();
161        mEnumValues = new MtpPropertyValue[mEnumLength];
162        for (int i = 0; i < mEnumLength; i++)
163            readValue(packet, mEnumValues[i]);
164    }
165}
166
167void MtpProperty::write(MtpDataPacket& packet) {
168    bool deviceProp = isDeviceProperty();
169
170    packet.putUInt16(mCode);
171    packet.putUInt16(mType);
172    packet.putUInt8(mWriteable ? 1 : 0);
173
174    switch (mType) {
175        case MTP_TYPE_AINT8:
176        case MTP_TYPE_AUINT8:
177        case MTP_TYPE_AINT16:
178        case MTP_TYPE_AUINT16:
179        case MTP_TYPE_AINT32:
180        case MTP_TYPE_AUINT32:
181        case MTP_TYPE_AINT64:
182        case MTP_TYPE_AUINT64:
183        case MTP_TYPE_AINT128:
184        case MTP_TYPE_AUINT128:
185            writeArrayValues(packet, mDefaultArrayValues, mDefaultArrayLength);
186            if (deviceProp)
187                writeArrayValues(packet, mCurrentArrayValues, mCurrentArrayLength);
188            break;
189        default:
190            writeValue(packet, mDefaultValue);
191            if (deviceProp)
192                writeValue(packet, mCurrentValue);
193    }
194    if (!deviceProp)
195        packet.putUInt32(mGroupCode);
196    packet.putUInt8(mFormFlag);
197    if (mFormFlag == kFormRange) {
198            writeValue(packet, mMinimumValue);
199            writeValue(packet, mMaximumValue);
200            writeValue(packet, mStepSize);
201    } else if (mFormFlag == kFormEnum) {
202        packet.putUInt16(mEnumLength);
203        for (int i = 0; i < mEnumLength; i++)
204            writeValue(packet, mEnumValues[i]);
205    }
206}
207
208void MtpProperty::setDefaultValue(const uint16_t* string) {
209    free(mDefaultValue.str);
210    if (string) {
211        MtpStringBuffer buffer(string);
212        mDefaultValue.str = strdup(buffer);
213    }
214    else
215        mDefaultValue.str = NULL;
216}
217
218void MtpProperty::setCurrentValue(const uint16_t* string) {
219    free(mCurrentValue.str);
220    if (string) {
221        MtpStringBuffer buffer(string);
222        mCurrentValue.str = strdup(buffer);
223    }
224    else
225        mCurrentValue.str = NULL;
226}
227
228void MtpProperty::setFormRange(int min, int max, int step) {
229    mFormFlag = kFormRange;
230    switch (mType) {
231        case MTP_TYPE_INT8:
232            mMinimumValue.u.i8 = min;
233            mMaximumValue.u.i8 = max;
234            mStepSize.u.i8 = step;
235            break;
236        case MTP_TYPE_UINT8:
237            mMinimumValue.u.u8 = min;
238            mMaximumValue.u.u8 = max;
239            mStepSize.u.u8 = step;
240            break;
241        case MTP_TYPE_INT16:
242            mMinimumValue.u.i16 = min;
243            mMaximumValue.u.i16 = max;
244            mStepSize.u.i16 = step;
245            break;
246        case MTP_TYPE_UINT16:
247            mMinimumValue.u.u16 = min;
248            mMaximumValue.u.u16 = max;
249            mStepSize.u.u16 = step;
250            break;
251        case MTP_TYPE_INT32:
252            mMinimumValue.u.i32 = min;
253            mMaximumValue.u.i32 = max;
254            mStepSize.u.i32 = step;
255            break;
256        case MTP_TYPE_UINT32:
257            mMinimumValue.u.u32 = min;
258            mMaximumValue.u.u32 = max;
259            mStepSize.u.u32 = step;
260            break;
261        case MTP_TYPE_INT64:
262            mMinimumValue.u.i64 = min;
263            mMaximumValue.u.i64 = max;
264            mStepSize.u.i64 = step;
265            break;
266        case MTP_TYPE_UINT64:
267            mMinimumValue.u.u64 = min;
268            mMaximumValue.u.u64 = max;
269            mStepSize.u.u64 = step;
270            break;
271        default:
272            ALOGE("unsupported type for MtpProperty::setRange");
273            break;
274    }
275}
276
277void MtpProperty::setFormEnum(const int* values, int count) {
278     mFormFlag = kFormEnum;
279     delete[] mEnumValues;
280     mEnumValues = new MtpPropertyValue[count];
281     mEnumLength = count;
282
283    for (int i = 0; i < count; i++) {
284        int value = *values++;
285            switch (mType) {
286                case MTP_TYPE_INT8:
287                    mEnumValues[i].u.i8 = value;
288                    break;
289                case MTP_TYPE_UINT8:
290                    mEnumValues[i].u.u8 = value;
291                    break;
292                case MTP_TYPE_INT16:
293                    mEnumValues[i].u.i16 = value;
294                    break;
295                case MTP_TYPE_UINT16:
296                    mEnumValues[i].u.u16 = value;
297                    break;
298                case MTP_TYPE_INT32:
299                    mEnumValues[i].u.i32 = value;
300                    break;
301                case MTP_TYPE_UINT32:
302                    mEnumValues[i].u.u32 = value;
303                    break;
304                case MTP_TYPE_INT64:
305                    mEnumValues[i].u.i64 = value;
306                    break;
307                case MTP_TYPE_UINT64:
308                    mEnumValues[i].u.u64 = value;
309                    break;
310                default:
311                    ALOGE("unsupported type for MtpProperty::setEnum");
312                    break;
313        }
314    }
315}
316
317void MtpProperty::setFormDateTime() {
318     mFormFlag = kFormDateTime;
319}
320
321void MtpProperty::print() {
322    MtpString buffer;
323    bool deviceProp = isDeviceProperty();
324    if (deviceProp)
325        ALOGI("    %s (%04X)", MtpDebug::getDevicePropCodeName(mCode), mCode);
326    else
327        ALOGI("    %s (%04X)", MtpDebug::getObjectPropCodeName(mCode), mCode);
328    ALOGI("    type %04X", mType);
329    ALOGI("    writeable %s", (mWriteable ? "true" : "false"));
330    buffer = "    default value: ";
331    print(mDefaultValue, buffer);
332    ALOGI("%s", (const char *)buffer);
333    if (deviceProp) {
334        buffer = "    current value: ";
335        print(mCurrentValue, buffer);
336        ALOGI("%s", (const char *)buffer);
337    }
338    switch (mFormFlag) {
339        case kFormNone:
340            break;
341        case kFormRange:
342            buffer = "    Range (";
343            print(mMinimumValue, buffer);
344            buffer += ", ";
345            print(mMaximumValue, buffer);
346            buffer += ", ";
347            print(mStepSize, buffer);
348            buffer += ")";
349            ALOGI("%s", (const char *)buffer);
350            break;
351        case kFormEnum:
352            buffer = "    Enum { ";
353            for (int i = 0; i < mEnumLength; i++) {
354                print(mEnumValues[i], buffer);
355                buffer += " ";
356            }
357            buffer += "}";
358            ALOGI("%s", (const char *)buffer);
359            break;
360        case kFormDateTime:
361            ALOGI("    DateTime\n");
362            break;
363        default:
364            ALOGI("    form %d\n", mFormFlag);
365            break;
366    }
367}
368
369void MtpProperty::print(MtpPropertyValue& value, MtpString& buffer) {
370    switch (mType) {
371        case MTP_TYPE_INT8:
372            buffer.appendFormat("%d", value.u.i8);
373            break;
374        case MTP_TYPE_UINT8:
375            buffer.appendFormat("%d", value.u.u8);
376            break;
377        case MTP_TYPE_INT16:
378            buffer.appendFormat("%d", value.u.i16);
379            break;
380        case MTP_TYPE_UINT16:
381            buffer.appendFormat("%d", value.u.u16);
382            break;
383        case MTP_TYPE_INT32:
384            buffer.appendFormat("%d", value.u.i32);
385            break;
386        case MTP_TYPE_UINT32:
387            buffer.appendFormat("%d", value.u.u32);
388            break;
389        case MTP_TYPE_INT64:
390            buffer.appendFormat("%" PRId64, value.u.i64);
391            break;
392        case MTP_TYPE_UINT64:
393            buffer.appendFormat("%" PRIu64, value.u.u64);
394            break;
395        case MTP_TYPE_INT128:
396            buffer.appendFormat("%08X%08X%08X%08X", value.u.i128[0], value.u.i128[1],
397                    value.u.i128[2], value.u.i128[3]);
398            break;
399        case MTP_TYPE_UINT128:
400            buffer.appendFormat("%08X%08X%08X%08X", value.u.u128[0], value.u.u128[1],
401                    value.u.u128[2], value.u.u128[3]);
402            break;
403        case MTP_TYPE_STR:
404            buffer.appendFormat("%s", value.str);
405            break;
406        default:
407            ALOGE("unsupported type for MtpProperty::print\n");
408            break;
409    }
410}
411
412void MtpProperty::readValue(MtpDataPacket& packet, MtpPropertyValue& value) {
413    MtpStringBuffer stringBuffer;
414
415    switch (mType) {
416        case MTP_TYPE_INT8:
417        case MTP_TYPE_AINT8:
418            value.u.i8 = packet.getInt8();
419            break;
420        case MTP_TYPE_UINT8:
421        case MTP_TYPE_AUINT8:
422            value.u.u8 = packet.getUInt8();
423            break;
424        case MTP_TYPE_INT16:
425        case MTP_TYPE_AINT16:
426            value.u.i16 = packet.getInt16();
427            break;
428        case MTP_TYPE_UINT16:
429        case MTP_TYPE_AUINT16:
430            value.u.u16 = packet.getUInt16();
431            break;
432        case MTP_TYPE_INT32:
433        case MTP_TYPE_AINT32:
434            value.u.i32 = packet.getInt32();
435            break;
436        case MTP_TYPE_UINT32:
437        case MTP_TYPE_AUINT32:
438            value.u.u32 = packet.getUInt32();
439            break;
440        case MTP_TYPE_INT64:
441        case MTP_TYPE_AINT64:
442            value.u.i64 = packet.getInt64();
443            break;
444        case MTP_TYPE_UINT64:
445        case MTP_TYPE_AUINT64:
446            value.u.u64 = packet.getUInt64();
447            break;
448        case MTP_TYPE_INT128:
449        case MTP_TYPE_AINT128:
450            packet.getInt128(value.u.i128);
451            break;
452        case MTP_TYPE_UINT128:
453        case MTP_TYPE_AUINT128:
454            packet.getUInt128(value.u.u128);
455            break;
456        case MTP_TYPE_STR:
457            packet.getString(stringBuffer);
458            value.str = strdup(stringBuffer);
459            break;
460        default:
461            ALOGE("unknown type %04X in MtpProperty::readValue", mType);
462    }
463}
464
465void MtpProperty::writeValue(MtpDataPacket& packet, MtpPropertyValue& value) {
466    MtpStringBuffer stringBuffer;
467
468    switch (mType) {
469        case MTP_TYPE_INT8:
470        case MTP_TYPE_AINT8:
471            packet.putInt8(value.u.i8);
472            break;
473        case MTP_TYPE_UINT8:
474        case MTP_TYPE_AUINT8:
475            packet.putUInt8(value.u.u8);
476            break;
477        case MTP_TYPE_INT16:
478        case MTP_TYPE_AINT16:
479            packet.putInt16(value.u.i16);
480            break;
481        case MTP_TYPE_UINT16:
482        case MTP_TYPE_AUINT16:
483            packet.putUInt16(value.u.u16);
484            break;
485        case MTP_TYPE_INT32:
486        case MTP_TYPE_AINT32:
487            packet.putInt32(value.u.i32);
488            break;
489        case MTP_TYPE_UINT32:
490        case MTP_TYPE_AUINT32:
491            packet.putUInt32(value.u.u32);
492            break;
493        case MTP_TYPE_INT64:
494        case MTP_TYPE_AINT64:
495            packet.putInt64(value.u.i64);
496            break;
497        case MTP_TYPE_UINT64:
498        case MTP_TYPE_AUINT64:
499            packet.putUInt64(value.u.u64);
500            break;
501        case MTP_TYPE_INT128:
502        case MTP_TYPE_AINT128:
503            packet.putInt128(value.u.i128);
504            break;
505        case MTP_TYPE_UINT128:
506        case MTP_TYPE_AUINT128:
507            packet.putUInt128(value.u.u128);
508            break;
509        case MTP_TYPE_STR:
510            if (value.str)
511                packet.putString(value.str);
512            else
513                packet.putEmptyString();
514            break;
515        default:
516            ALOGE("unknown type %04X in MtpProperty::writeValue", mType);
517    }
518}
519
520MtpPropertyValue* MtpProperty::readArrayValues(MtpDataPacket& packet, int& length) {
521    length = packet.getUInt32();
522    // Fail if resulting array is over 2GB.  This is because the maximum array
523    // size may be less than SIZE_MAX on some platforms.
524    if ( CC_UNLIKELY(
525            length == 0 ||
526            length >= INT32_MAX / sizeof(MtpPropertyValue)) ) {
527        length = 0;
528        return NULL;
529    }
530    MtpPropertyValue* result = new MtpPropertyValue[length];
531    for (int i = 0; i < length; i++)
532        readValue(packet, result[i]);
533    return result;
534}
535
536void MtpProperty::writeArrayValues(MtpDataPacket& packet, MtpPropertyValue* values, int length) {
537    packet.putUInt32(length);
538    for (int i = 0; i < length; i++)
539        writeValue(packet, values[i]);
540}
541
542}  // namespace android
543