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 <string.h> 20 21#include "MtpDataPacket.h" 22#include "MtpStringBuffer.h" 23 24namespace android { 25 26MtpStringBuffer::MtpStringBuffer() 27 : mCharCount(0), 28 mByteCount(1) 29{ 30 mBuffer[0] = 0; 31} 32 33MtpStringBuffer::MtpStringBuffer(const char* src) 34 : mCharCount(0), 35 mByteCount(1) 36{ 37 set(src); 38} 39 40MtpStringBuffer::MtpStringBuffer(const uint16_t* src) 41 : mCharCount(0), 42 mByteCount(1) 43{ 44 set(src); 45} 46 47MtpStringBuffer::MtpStringBuffer(const MtpStringBuffer& src) 48 : mCharCount(src.mCharCount), 49 mByteCount(src.mByteCount) 50{ 51 memcpy(mBuffer, src.mBuffer, mByteCount); 52} 53 54 55MtpStringBuffer::~MtpStringBuffer() { 56} 57 58void MtpStringBuffer::set(const char* src) { 59 int length = strlen(src); 60 if (length >= sizeof(mBuffer)) 61 length = sizeof(mBuffer) - 1; 62 memcpy(mBuffer, src, length); 63 64 // count the characters 65 int count = 0; 66 char ch; 67 while ((ch = *src++) != 0) { 68 if ((ch & 0x80) == 0) { 69 // single byte character 70 } else if ((ch & 0xE0) == 0xC0) { 71 // two byte character 72 if (! *src++) { 73 // last character was truncated, so ignore last byte 74 length--; 75 break; 76 } 77 } else if ((ch & 0xF0) == 0xE0) { 78 // 3 byte char 79 if (! *src++) { 80 // last character was truncated, so ignore last byte 81 length--; 82 break; 83 } 84 if (! *src++) { 85 // last character was truncated, so ignore last two bytes 86 length -= 2; 87 break; 88 } 89 } 90 count++; 91 } 92 93 mByteCount = length + 1; 94 mBuffer[length] = 0; 95 mCharCount = count; 96} 97 98void MtpStringBuffer::set(const uint16_t* src) { 99 int count = 0; 100 uint16_t ch; 101 uint8_t* dest = mBuffer; 102 103 while ((ch = *src++) != 0 && count < 255) { 104 if (ch >= 0x0800) { 105 *dest++ = (uint8_t)(0xE0 | (ch >> 12)); 106 *dest++ = (uint8_t)(0x80 | ((ch >> 6) & 0x3F)); 107 *dest++ = (uint8_t)(0x80 | (ch & 0x3F)); 108 } else if (ch >= 0x80) { 109 *dest++ = (uint8_t)(0xC0 | (ch >> 6)); 110 *dest++ = (uint8_t)(0x80 | (ch & 0x3F)); 111 } else { 112 *dest++ = ch; 113 } 114 count++; 115 } 116 *dest++ = 0; 117 mCharCount = count; 118 mByteCount = dest - mBuffer; 119} 120 121void MtpStringBuffer::readFromPacket(MtpDataPacket* packet) { 122 int count = packet->getUInt8(); 123 uint8_t* dest = mBuffer; 124 for (int i = 0; i < count; i++) { 125 uint16_t ch = packet->getUInt16(); 126 if (ch >= 0x0800) { 127 *dest++ = (uint8_t)(0xE0 | (ch >> 12)); 128 *dest++ = (uint8_t)(0x80 | ((ch >> 6) & 0x3F)); 129 *dest++ = (uint8_t)(0x80 | (ch & 0x3F)); 130 } else if (ch >= 0x80) { 131 *dest++ = (uint8_t)(0xC0 | (ch >> 6)); 132 *dest++ = (uint8_t)(0x80 | (ch & 0x3F)); 133 } else { 134 *dest++ = ch; 135 } 136 } 137 *dest++ = 0; 138 mCharCount = count; 139 mByteCount = dest - mBuffer; 140} 141 142void MtpStringBuffer::writeToPacket(MtpDataPacket* packet) const { 143 int count = mCharCount; 144 const uint8_t* src = mBuffer; 145 packet->putUInt8(count > 0 ? count + 1 : 0); 146 147 // expand utf8 to 16 bit chars 148 for (int i = 0; i < count; i++) { 149 uint16_t ch; 150 uint16_t ch1 = *src++; 151 if ((ch1 & 0x80) == 0) { 152 // single byte character 153 ch = ch1; 154 } else if ((ch1 & 0xE0) == 0xC0) { 155 // two byte character 156 uint16_t ch2 = *src++; 157 ch = ((ch1 & 0x1F) << 6) | (ch2 & 0x3F); 158 } else { 159 // three byte character 160 uint16_t ch2 = *src++; 161 uint16_t ch3 = *src++; 162 ch = ((ch1 & 0x0F) << 12) | ((ch2 & 0x3F) << 6) | (ch3 & 0x3F); 163 } 164 packet->putUInt16(ch); 165 } 166 // only terminate with zero if string is not empty 167 if (count > 0) 168 packet->putUInt16(0); 169} 170 171} // namespace android 172