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 "MtpStringBuffer"
18 
19 #include <codecvt>
20 #include <locale>
21 #include <string>
22 #include <vector>
23 
24 #include "MtpDataPacket.h"
25 #include "MtpStringBuffer.h"
26 
27 namespace {
28 
29 const char * utf16_cerror = "__CONVERSION_ERROR__";
30 const char16_t * utf8_cerror = u"__CONVERSION_ERROR__";
31 
32 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> gConvert(utf16_cerror, utf8_cerror);
33 
utf16ToUtf8(std::u16string input_str)34 static std::string utf16ToUtf8(std::u16string input_str) {
35     std::string conversion = gConvert.to_bytes(input_str);
36 
37     if (conversion == utf16_cerror) {
38         ALOGE("Unable to convert UTF-16 string to UTF-8");
39         return "";
40     } else {
41         return conversion;
42     }
43 }
44 
utf8ToUtf16(std::string input_str)45 static std::u16string utf8ToUtf16(std::string input_str) {
46     std::u16string conversion = gConvert.from_bytes(input_str);
47 
48     if (conversion == utf8_cerror) {
49         ALOGE("Unable to convert UTF-8 string to UTF-16");
50         return u"";
51     } else {
52         return conversion;
53     }
54 }
55 
56 } // namespace
57 
58 namespace android {
59 
MtpStringBuffer(const char * src)60 MtpStringBuffer::MtpStringBuffer(const char* src)
61 {
62     set(src);
63 }
64 
MtpStringBuffer(const uint16_t * src)65 MtpStringBuffer::MtpStringBuffer(const uint16_t* src)
66 {
67     set(src);
68 }
69 
MtpStringBuffer(const MtpStringBuffer & src)70 MtpStringBuffer::MtpStringBuffer(const MtpStringBuffer& src)
71 {
72     mString = src.mString;
73 }
74 
set(const char * src)75 void MtpStringBuffer::set(const char* src) {
76     mString = std::string(src);
77 }
78 
set(const uint16_t * src)79 void MtpStringBuffer::set(const uint16_t* src) {
80     mString = utf16ToUtf8(std::u16string((const char16_t*)src));
81 }
82 
readFromPacket(MtpDataPacket * packet)83 bool MtpStringBuffer::readFromPacket(MtpDataPacket* packet) {
84     uint8_t count;
85     if (!packet->getUInt8(count))
86         return false;
87     if (count == 0)
88         return true;
89 
90     std::vector<char16_t> buffer(count);
91     for (int i = 0; i < count; i++) {
92         uint16_t ch;
93         if (!packet->getUInt16(ch))
94             return false;
95         buffer[i] = ch;
96     }
97     if (buffer[count-1] != '\0') {
98         ALOGE("Mtp string not null terminated\n");
99         return false;
100     }
101     mString = utf16ToUtf8(std::u16string(buffer.data()));
102     return true;
103 }
104 
writeToPacket(MtpDataPacket * packet) const105 void MtpStringBuffer::writeToPacket(MtpDataPacket* packet) const {
106     std::u16string src16 = utf8ToUtf16(mString);
107     int count = src16.length();
108 
109     if (count == 0) {
110         packet->putUInt8(0);
111         return;
112     }
113     packet->putUInt8(std::min(count + 1, MTP_STRING_MAX_CHARACTER_NUMBER));
114 
115     int i = 0;
116     for (char16_t &c : src16) {
117         if (i == MTP_STRING_MAX_CHARACTER_NUMBER - 1) {
118             // Leave a slot for null termination.
119             ALOGI("Mtp truncating long string\n");
120             break;
121         }
122         packet->putUInt16(c);
123         i++;
124     }
125     // only terminate with zero if string is not empty
126     packet->putUInt16(0);
127 }
128 
129 }  // namespace android
130