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 (uint32_t i = 0; i < mDefaultArrayLength; i++)
110                free(mDefaultArrayValues[i].str);
111        }
112        if (mCurrentArrayValues) {
113            for (uint32_t i = 0; i < mCurrentArrayLength; i++)
114                free(mCurrentArrayValues[i].str);
115        }
116        if (mEnumValues) {
117            for (uint16_t i = 0; i < mEnumLength; i++)
118                free(mEnumValues[i].str);
119        }
120    }
121    delete[] mDefaultArrayValues;
122    delete[] mCurrentArrayValues;
123    delete[] mEnumValues;
124}
125
126bool MtpProperty::read(MtpDataPacket& packet) {
127    uint8_t temp8;
128
129    if (!packet.getUInt16(mCode)) return false;
130    bool deviceProp = isDeviceProperty();
131    if (!packet.getUInt16(mType)) return false;
132    if (!packet.getUInt8(temp8)) return false;
133    mWriteable = (temp8 == 1);
134    switch (mType) {
135        case MTP_TYPE_AINT8:
136        case MTP_TYPE_AUINT8:
137        case MTP_TYPE_AINT16:
138        case MTP_TYPE_AUINT16:
139        case MTP_TYPE_AINT32:
140        case MTP_TYPE_AUINT32:
141        case MTP_TYPE_AINT64:
142        case MTP_TYPE_AUINT64:
143        case MTP_TYPE_AINT128:
144        case MTP_TYPE_AUINT128:
145            mDefaultArrayValues = readArrayValues(packet, mDefaultArrayLength);
146            if (!mDefaultArrayValues) return false;
147            if (deviceProp) {
148                mCurrentArrayValues = readArrayValues(packet, mCurrentArrayLength);
149                if (!mCurrentArrayValues) return false;
150            }
151            break;
152        default:
153            if (!readValue(packet, mDefaultValue)) return false;
154            if (deviceProp) {
155                if (!readValue(packet, mCurrentValue)) return false;
156            }
157    }
158    if (!deviceProp) {
159        if (!packet.getUInt32(mGroupCode)) return false;
160    }
161    if (!packet.getUInt8(mFormFlag)) return false;
162
163    if (mFormFlag == kFormRange) {
164            if (!readValue(packet, mMinimumValue)) return false;
165            if (!readValue(packet, mMaximumValue)) return false;
166            if (!readValue(packet, mStepSize)) return false;
167    } else if (mFormFlag == kFormEnum) {
168        if (!packet.getUInt16(mEnumLength)) return false;
169        mEnumValues = new MtpPropertyValue[mEnumLength];
170        for (int i = 0; i < mEnumLength; i++) {
171            if (!readValue(packet, mEnumValues[i])) return false;
172        }
173    }
174
175    return true;
176}
177
178void MtpProperty::write(MtpDataPacket& packet) {
179    bool deviceProp = isDeviceProperty();
180
181    packet.putUInt16(mCode);
182    packet.putUInt16(mType);
183    packet.putUInt8(mWriteable ? 1 : 0);
184
185    switch (mType) {
186        case MTP_TYPE_AINT8:
187        case MTP_TYPE_AUINT8:
188        case MTP_TYPE_AINT16:
189        case MTP_TYPE_AUINT16:
190        case MTP_TYPE_AINT32:
191        case MTP_TYPE_AUINT32:
192        case MTP_TYPE_AINT64:
193        case MTP_TYPE_AUINT64:
194        case MTP_TYPE_AINT128:
195        case MTP_TYPE_AUINT128:
196            writeArrayValues(packet, mDefaultArrayValues, mDefaultArrayLength);
197            if (deviceProp)
198                writeArrayValues(packet, mCurrentArrayValues, mCurrentArrayLength);
199            break;
200        default:
201            writeValue(packet, mDefaultValue);
202            if (deviceProp)
203                writeValue(packet, mCurrentValue);
204    }
205    if (!deviceProp)
206        packet.putUInt32(mGroupCode);
207    packet.putUInt8(mFormFlag);
208    if (mFormFlag == kFormRange) {
209            writeValue(packet, mMinimumValue);
210            writeValue(packet, mMaximumValue);
211            writeValue(packet, mStepSize);
212    } else if (mFormFlag == kFormEnum) {
213        packet.putUInt16(mEnumLength);
214        for (int i = 0; i < mEnumLength; i++)
215            writeValue(packet, mEnumValues[i]);
216    }
217}
218
219void MtpProperty::setDefaultValue(const uint16_t* string) {
220    free(mDefaultValue.str);
221    if (string) {
222        MtpStringBuffer buffer(string);
223        mDefaultValue.str = strdup(buffer);
224    }
225    else
226        mDefaultValue.str = NULL;
227}
228
229void MtpProperty::setCurrentValue(const uint16_t* string) {
230    free(mCurrentValue.str);
231    if (string) {
232        MtpStringBuffer buffer(string);
233        mCurrentValue.str = strdup(buffer);
234    }
235    else
236        mCurrentValue.str = NULL;
237}
238
239void MtpProperty::setCurrentValue(MtpDataPacket& packet) {
240    free(mCurrentValue.str);
241    mCurrentValue.str = NULL;
242    readValue(packet, mCurrentValue);
243}
244
245void MtpProperty::setFormRange(int min, int max, int step) {
246    mFormFlag = kFormRange;
247    switch (mType) {
248        case MTP_TYPE_INT8:
249            mMinimumValue.u.i8 = min;
250            mMaximumValue.u.i8 = max;
251            mStepSize.u.i8 = step;
252            break;
253        case MTP_TYPE_UINT8:
254            mMinimumValue.u.u8 = min;
255            mMaximumValue.u.u8 = max;
256            mStepSize.u.u8 = step;
257            break;
258        case MTP_TYPE_INT16:
259            mMinimumValue.u.i16 = min;
260            mMaximumValue.u.i16 = max;
261            mStepSize.u.i16 = step;
262            break;
263        case MTP_TYPE_UINT16:
264            mMinimumValue.u.u16 = min;
265            mMaximumValue.u.u16 = max;
266            mStepSize.u.u16 = step;
267            break;
268        case MTP_TYPE_INT32:
269            mMinimumValue.u.i32 = min;
270            mMaximumValue.u.i32 = max;
271            mStepSize.u.i32 = step;
272            break;
273        case MTP_TYPE_UINT32:
274            mMinimumValue.u.u32 = min;
275            mMaximumValue.u.u32 = max;
276            mStepSize.u.u32 = step;
277            break;
278        case MTP_TYPE_INT64:
279            mMinimumValue.u.i64 = min;
280            mMaximumValue.u.i64 = max;
281            mStepSize.u.i64 = step;
282            break;
283        case MTP_TYPE_UINT64:
284            mMinimumValue.u.u64 = min;
285            mMaximumValue.u.u64 = max;
286            mStepSize.u.u64 = step;
287            break;
288        default:
289            ALOGE("unsupported type for MtpProperty::setRange");
290            break;
291    }
292}
293
294void MtpProperty::setFormEnum(const int* values, int count) {
295     mFormFlag = kFormEnum;
296     delete[] mEnumValues;
297     mEnumValues = new MtpPropertyValue[count];
298     mEnumLength = count;
299
300    for (int i = 0; i < count; i++) {
301        int value = *values++;
302            switch (mType) {
303                case MTP_TYPE_INT8:
304                    mEnumValues[i].u.i8 = value;
305                    break;
306                case MTP_TYPE_UINT8:
307                    mEnumValues[i].u.u8 = value;
308                    break;
309                case MTP_TYPE_INT16:
310                    mEnumValues[i].u.i16 = value;
311                    break;
312                case MTP_TYPE_UINT16:
313                    mEnumValues[i].u.u16 = value;
314                    break;
315                case MTP_TYPE_INT32:
316                    mEnumValues[i].u.i32 = value;
317                    break;
318                case MTP_TYPE_UINT32:
319                    mEnumValues[i].u.u32 = value;
320                    break;
321                case MTP_TYPE_INT64:
322                    mEnumValues[i].u.i64 = value;
323                    break;
324                case MTP_TYPE_UINT64:
325                    mEnumValues[i].u.u64 = value;
326                    break;
327                default:
328                    ALOGE("unsupported type for MtpProperty::setEnum");
329                    break;
330        }
331    }
332}
333
334void MtpProperty::setFormDateTime() {
335     mFormFlag = kFormDateTime;
336}
337
338void MtpProperty::print() {
339    MtpString buffer;
340    bool deviceProp = isDeviceProperty();
341    if (deviceProp)
342        ALOGI("    %s (%04X)", MtpDebug::getDevicePropCodeName(mCode), mCode);
343    else
344        ALOGI("    %s (%04X)", MtpDebug::getObjectPropCodeName(mCode), mCode);
345    ALOGI("    type %04X", mType);
346    ALOGI("    writeable %s", (mWriteable ? "true" : "false"));
347    buffer = "    default value: ";
348    print(mDefaultValue, buffer);
349    ALOGI("%s", (const char *)buffer);
350    if (deviceProp) {
351        buffer = "    current value: ";
352        print(mCurrentValue, buffer);
353        ALOGI("%s", (const char *)buffer);
354    }
355    switch (mFormFlag) {
356        case kFormNone:
357            break;
358        case kFormRange:
359            buffer = "    Range (";
360            print(mMinimumValue, buffer);
361            buffer += ", ";
362            print(mMaximumValue, buffer);
363            buffer += ", ";
364            print(mStepSize, buffer);
365            buffer += ")";
366            ALOGI("%s", (const char *)buffer);
367            break;
368        case kFormEnum:
369            buffer = "    Enum { ";
370            for (int i = 0; i < mEnumLength; i++) {
371                print(mEnumValues[i], buffer);
372                buffer += " ";
373            }
374            buffer += "}";
375            ALOGI("%s", (const char *)buffer);
376            break;
377        case kFormDateTime:
378            ALOGI("    DateTime\n");
379            break;
380        default:
381            ALOGI("    form %d\n", mFormFlag);
382            break;
383    }
384}
385
386void MtpProperty::print(MtpPropertyValue& value, MtpString& buffer) {
387    switch (mType) {
388        case MTP_TYPE_INT8:
389            buffer.appendFormat("%d", value.u.i8);
390            break;
391        case MTP_TYPE_UINT8:
392            buffer.appendFormat("%d", value.u.u8);
393            break;
394        case MTP_TYPE_INT16:
395            buffer.appendFormat("%d", value.u.i16);
396            break;
397        case MTP_TYPE_UINT16:
398            buffer.appendFormat("%d", value.u.u16);
399            break;
400        case MTP_TYPE_INT32:
401            buffer.appendFormat("%d", value.u.i32);
402            break;
403        case MTP_TYPE_UINT32:
404            buffer.appendFormat("%d", value.u.u32);
405            break;
406        case MTP_TYPE_INT64:
407            buffer.appendFormat("%" PRId64, value.u.i64);
408            break;
409        case MTP_TYPE_UINT64:
410            buffer.appendFormat("%" PRIu64, value.u.u64);
411            break;
412        case MTP_TYPE_INT128:
413            buffer.appendFormat("%08X%08X%08X%08X", value.u.i128[0], value.u.i128[1],
414                    value.u.i128[2], value.u.i128[3]);
415            break;
416        case MTP_TYPE_UINT128:
417            buffer.appendFormat("%08X%08X%08X%08X", value.u.u128[0], value.u.u128[1],
418                    value.u.u128[2], value.u.u128[3]);
419            break;
420        case MTP_TYPE_STR:
421            buffer.appendFormat("%s", value.str);
422            break;
423        default:
424            ALOGE("unsupported type for MtpProperty::print\n");
425            break;
426    }
427}
428
429bool MtpProperty::readValue(MtpDataPacket& packet, MtpPropertyValue& value) {
430    MtpStringBuffer stringBuffer;
431
432    switch (mType) {
433        case MTP_TYPE_INT8:
434        case MTP_TYPE_AINT8:
435            if (!packet.getInt8(value.u.i8)) return false;
436            break;
437        case MTP_TYPE_UINT8:
438        case MTP_TYPE_AUINT8:
439            if (!packet.getUInt8(value.u.u8)) return false;
440            break;
441        case MTP_TYPE_INT16:
442        case MTP_TYPE_AINT16:
443            if (!packet.getInt16(value.u.i16)) return false;
444            break;
445        case MTP_TYPE_UINT16:
446        case MTP_TYPE_AUINT16:
447            if (!packet.getUInt16(value.u.u16)) return false;
448            break;
449        case MTP_TYPE_INT32:
450        case MTP_TYPE_AINT32:
451            if (!packet.getInt32(value.u.i32)) return false;
452            break;
453        case MTP_TYPE_UINT32:
454        case MTP_TYPE_AUINT32:
455            if (!packet.getUInt32(value.u.u32)) return false;
456            break;
457        case MTP_TYPE_INT64:
458        case MTP_TYPE_AINT64:
459            if (!packet.getInt64(value.u.i64)) return false;
460            break;
461        case MTP_TYPE_UINT64:
462        case MTP_TYPE_AUINT64:
463            if (!packet.getUInt64(value.u.u64)) return false;
464            break;
465        case MTP_TYPE_INT128:
466        case MTP_TYPE_AINT128:
467            if (!packet.getInt128(value.u.i128)) return false;
468            break;
469        case MTP_TYPE_UINT128:
470        case MTP_TYPE_AUINT128:
471            if (!packet.getUInt128(value.u.u128)) return false;
472            break;
473        case MTP_TYPE_STR:
474            if (!packet.getString(stringBuffer)) return false;
475            value.str = strdup(stringBuffer);
476            break;
477        default:
478            ALOGE("unknown type %04X in MtpProperty::readValue", mType);
479            return false;
480    }
481    return true;
482}
483
484void MtpProperty::writeValue(MtpDataPacket& packet, MtpPropertyValue& value) {
485    MtpStringBuffer stringBuffer;
486
487    switch (mType) {
488        case MTP_TYPE_INT8:
489        case MTP_TYPE_AINT8:
490            packet.putInt8(value.u.i8);
491            break;
492        case MTP_TYPE_UINT8:
493        case MTP_TYPE_AUINT8:
494            packet.putUInt8(value.u.u8);
495            break;
496        case MTP_TYPE_INT16:
497        case MTP_TYPE_AINT16:
498            packet.putInt16(value.u.i16);
499            break;
500        case MTP_TYPE_UINT16:
501        case MTP_TYPE_AUINT16:
502            packet.putUInt16(value.u.u16);
503            break;
504        case MTP_TYPE_INT32:
505        case MTP_TYPE_AINT32:
506            packet.putInt32(value.u.i32);
507            break;
508        case MTP_TYPE_UINT32:
509        case MTP_TYPE_AUINT32:
510            packet.putUInt32(value.u.u32);
511            break;
512        case MTP_TYPE_INT64:
513        case MTP_TYPE_AINT64:
514            packet.putInt64(value.u.i64);
515            break;
516        case MTP_TYPE_UINT64:
517        case MTP_TYPE_AUINT64:
518            packet.putUInt64(value.u.u64);
519            break;
520        case MTP_TYPE_INT128:
521        case MTP_TYPE_AINT128:
522            packet.putInt128(value.u.i128);
523            break;
524        case MTP_TYPE_UINT128:
525        case MTP_TYPE_AUINT128:
526            packet.putUInt128(value.u.u128);
527            break;
528        case MTP_TYPE_STR:
529            if (value.str)
530                packet.putString(value.str);
531            else
532                packet.putEmptyString();
533            break;
534        default:
535            ALOGE("unknown type %04X in MtpProperty::writeValue", mType);
536    }
537}
538
539MtpPropertyValue* MtpProperty::readArrayValues(MtpDataPacket& packet, uint32_t& length) {
540    if (!packet.getUInt32(length)) return NULL;
541
542    // Fail if resulting array is over 2GB.  This is because the maximum array
543    // size may be less than SIZE_MAX on some platforms.
544    if ( CC_UNLIKELY(
545            length == 0 ||
546            length >= INT32_MAX / sizeof(MtpPropertyValue)) ) {
547        length = 0;
548        return NULL;
549    }
550    MtpPropertyValue* result = new MtpPropertyValue[length];
551    for (uint32_t i = 0; i < length; i++)
552        if (!readValue(packet, result[i])) {
553            delete [] result;
554            return NULL;
555        }
556    return result;
557}
558
559void MtpProperty::writeArrayValues(MtpDataPacket& packet, MtpPropertyValue* values, uint32_t length) {
560    packet.putUInt32(length);
561    for (uint32_t i = 0; i < length; i++)
562        writeValue(packet, values[i]);
563}
564
565}  // namespace android
566