blob: fe8cf043815b7ed99c64415ec0b72284c1ed76c6 [file] [log] [blame]
Mike Lockwood56118b52010-05-11 17:16:59 -04001/*
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
Mike Lockwood3e6616d2010-06-29 18:11:52 -040017#define LOG_TAG "MtpStringBuffer"
18
Mike Lockwood56118b52010-05-11 17:16:59 -040019#include <string.h>
20
21#include "MtpDataPacket.h"
22#include "MtpStringBuffer.h"
23
Mike Lockwood8d3257a2010-05-14 10:10:36 -040024namespace android {
Mike Lockwood56118b52010-05-11 17:16:59 -040025
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
Mike Lockwooda2a21282010-09-25 21:21:05 -040040MtpStringBuffer::MtpStringBuffer(const uint16_t* src)
41 : mCharCount(0),
42 mByteCount(1)
43{
44 set(src);
45}
46
Mike Lockwood56118b52010-05-11 17:16:59 -040047MtpStringBuffer::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
Mike Lockwooda2a21282010-09-25 21:21:05 -040098void 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
Mike Lockwood56118b52010-05-11 17:16:59 -0400121void 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;
Mike Lockwood9e837862010-08-18 12:31:09 -0400145 packet->putUInt8(count > 0 ? count + 1 : 0);
Mike Lockwood56118b52010-05-11 17:16:59 -0400146
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 }
Mike Lockwood9e837862010-08-18 12:31:09 -0400166 // only terminate with zero if string is not empty
167 if (count > 0)
168 packet->putUInt16(0);
Mike Lockwood56118b52010-05-11 17:16:59 -0400169}
Mike Lockwood8d3257a2010-05-14 10:10:36 -0400170
171} // namespace android