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)34static 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)45static 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)60MtpStringBuffer::MtpStringBuffer(const char* src) 61 { 62 set(src); 63 } 64 MtpStringBuffer(const uint16_t * src)65MtpStringBuffer::MtpStringBuffer(const uint16_t* src) 66 { 67 set(src); 68 } 69 MtpStringBuffer(const MtpStringBuffer & src)70MtpStringBuffer::MtpStringBuffer(const MtpStringBuffer& src) 71 { 72 mString = src.mString; 73 } 74 set(const char * src)75void MtpStringBuffer::set(const char* src) { 76 mString = std::string(src); 77 } 78 set(const uint16_t * src)79void MtpStringBuffer::set(const uint16_t* src) { 80 mString = utf16ToUtf8(std::u16string((const char16_t*)src)); 81 } 82 readFromPacket(MtpDataPacket * packet)83bool 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) const105void 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