1 /*
2 * Copyright (c) 2018, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /**
30 * @file
31 * This file implements OpenThread String class.
32 */
33
34 #include "string.hpp"
35 #include "debug.hpp"
36
37 #include <string.h>
38
39 namespace ot {
40
StringLength(const char * aString,uint16_t aMaxLength)41 uint16_t StringLength(const char *aString, uint16_t aMaxLength)
42 {
43 uint16_t ret;
44
45 for (ret = 0; (ret < aMaxLength) && (aString[ret] != 0); ret++)
46 {
47 // Empty loop.
48 }
49
50 return ret;
51 }
52
StringFind(const char * aString,char aChar)53 const char *StringFind(const char *aString, char aChar)
54 {
55 const char *ret = nullptr;
56
57 for (; *aString != '\0'; aString++)
58 {
59 if (*aString == aChar)
60 {
61 ret = aString;
62 break;
63 }
64 }
65
66 return ret;
67 }
68
StringFind(const char * aString,const char * aSubString)69 const char *StringFind(const char *aString, const char *aSubString)
70 {
71 const char *ret = nullptr;
72 size_t len = strlen(aString);
73 size_t subLen = strlen(aSubString);
74
75 VerifyOrExit(subLen <= len);
76
77 for (size_t index = 0; index <= static_cast<size_t>(len - subLen); index++)
78 {
79 if (memcmp(&aString[index], aSubString, subLen) == 0)
80 {
81 ExitNow(ret = &aString[index]);
82 }
83 }
84
85 exit:
86 return ret;
87 }
88
StringEndsWith(const char * aString,char aChar)89 bool StringEndsWith(const char *aString, char aChar)
90 {
91 size_t len = strlen(aString);
92
93 return len > 0 && aString[len - 1] == aChar;
94 }
95
StringEndsWith(const char * aString,const char * aSubString)96 bool StringEndsWith(const char *aString, const char *aSubString)
97 {
98 size_t len = strlen(aString);
99 size_t subLen = strlen(aSubString);
100
101 return (subLen > 0) && (len >= subLen) && (memcmp(aSubString, &aString[len - subLen], subLen) == 0);
102 }
103
StringWriter(char * aBuffer,uint16_t aSize)104 StringWriter::StringWriter(char *aBuffer, uint16_t aSize)
105 : mBuffer(aBuffer)
106 , mLength(0)
107 , mSize(aSize)
108 {
109 mBuffer[0] = '\0';
110 }
111
Clear(void)112 StringWriter &StringWriter::Clear(void)
113 {
114 mBuffer[0] = '\0';
115 mLength = 0;
116 return *this;
117 }
118
Append(const char * aFormat,...)119 StringWriter &StringWriter::Append(const char *aFormat, ...)
120 {
121 va_list args;
122 va_start(args, aFormat);
123 AppendVarArgs(aFormat, args);
124 va_end(args);
125
126 return *this;
127 }
128
AppendVarArgs(const char * aFormat,va_list aArgs)129 StringWriter &StringWriter::AppendVarArgs(const char *aFormat, va_list aArgs)
130 {
131 int len;
132
133 len = vsnprintf(mBuffer + mLength, (mSize > mLength ? (mSize - mLength) : 0), aFormat, aArgs);
134 OT_ASSERT(len >= 0);
135
136 mLength += static_cast<uint16_t>(len);
137
138 if (IsTruncated())
139 {
140 mBuffer[mSize - 1] = '\0';
141 }
142
143 return *this;
144 }
145
AppendHexBytes(const uint8_t * aBytes,uint16_t aLength)146 StringWriter &StringWriter::AppendHexBytes(const uint8_t *aBytes, uint16_t aLength)
147 {
148 while (aLength--)
149 {
150 Append("%02x", *aBytes++);
151 }
152
153 return *this;
154 }
155
IsValidUtf8String(const char * aString)156 bool IsValidUtf8String(const char *aString)
157 {
158 return IsValidUtf8String(aString, strlen(aString));
159 }
160
IsValidUtf8String(const char * aString,size_t aLength)161 bool IsValidUtf8String(const char *aString, size_t aLength)
162 {
163 bool ret = true;
164 uint8_t byte;
165 uint8_t continuationBytes = 0;
166 size_t position = 0;
167
168 while (position < aLength)
169 {
170 byte = *reinterpret_cast<const uint8_t *>(aString + position);
171 ++position;
172
173 if ((byte & 0x80) == 0)
174 {
175 continue;
176 }
177
178 // This is a leading byte 1xxx-xxxx.
179
180 if ((byte & 0x40) == 0) // 10xx-xxxx
181 {
182 // We got a continuation byte pattern without seeing a leading byte earlier.
183 ExitNow(ret = false);
184 }
185 else if ((byte & 0x20) == 0) // 110x-xxxx
186 {
187 continuationBytes = 1;
188 }
189 else if ((byte & 0x10) == 0) // 1110-xxxx
190 {
191 continuationBytes = 2;
192 }
193 else if ((byte & 0x08) == 0) // 1111-0xxx
194 {
195 continuationBytes = 3;
196 }
197 else // 1111-1xxx (invalid pattern).
198 {
199 ExitNow(ret = false);
200 }
201
202 while (continuationBytes-- != 0)
203 {
204 VerifyOrExit(position < aLength, ret = false);
205
206 byte = *reinterpret_cast<const uint8_t *>(aString + position);
207 ++position;
208
209 // Verify the continuation byte pattern 10xx-xxxx
210 VerifyOrExit((byte & 0xc0) == 0x80, ret = false);
211 }
212 }
213
214 exit:
215 return ret;
216 }
217
218 } // namespace ot
219