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