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