Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020 Project CHIP Authors
4 : * All rights reserved.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : /**
20 : * @file
21 : * This file defines string operations that allocate heap memory.
22 : */
23 :
24 : #pragma once
25 :
26 : #include <algorithm>
27 : #include <stdlib.h>
28 : #include <string.h>
29 :
30 : #include <lib/support/ScopedBuffer.h>
31 : #include <lib/support/Span.h>
32 :
33 : namespace chip {
34 : namespace Platform {
35 :
36 : /**
37 : * Copies a C-style string.
38 : *
39 : * This differs from `strncpy()` in some important ways:
40 : * - `dest` can be nullptr, in which case no copy is attempted, and the function returns nullptr.
41 : * - A non-nullptr result is always null-terminated.
42 : *
43 : * @param[in] dest Destination string buffer or nullptr.
44 : *
45 : * @param[in] destLength Maximum length to be copied. Will need space for null terminator as
46 : * well (string will be truncated if it does not fit). If 0 this method
47 : * is a noop.
48 : *
49 : * @param[in] source String to be copied.
50 : *
51 : * @retval Same as `dest`.
52 : */
53 7594 : inline void CopyString(char * dest, size_t destLength, const char * source)
54 : {
55 7594 : if (dest && destLength)
56 : {
57 7594 : strncpy(dest, source, destLength);
58 7594 : dest[destLength - 1] = 0;
59 : }
60 7594 : }
61 :
62 : /**
63 : * Convenience method for CopyString to auto-detect destination size.
64 : */
65 : template <size_t N>
66 7887 : inline void CopyString(char (&dest)[N], const char * source)
67 : {
68 7887 : CopyString(dest, N, source);
69 7887 : }
70 :
71 : /**
72 : * Creates a null-terminated string from a ByteSpan.
73 : * If dest is nullptr, no copy happens. Non-nullptr result is always null-terminated.
74 : *
75 : * @param[in] dest Destination string buffer or nullptr.
76 : *
77 : * @param[in] destLength Maximum length to be copied. Will need space for null terminator as
78 : * well (string will be truncated if it does not fit). If 0 this method
79 : * is a noop.
80 : *
81 : * @param[in] source Data to be copied.
82 : */
83 169 : inline void CopyString(char * dest, size_t destLength, ByteSpan source)
84 : {
85 169 : if ((dest == nullptr) || (destLength == 0))
86 : {
87 0 : return; // no space to copy anything, not even a null terminator
88 : }
89 :
90 169 : if (source.empty())
91 : {
92 13 : *dest = '\0'; // just a null terminator, we are copying empty data
93 13 : return;
94 : }
95 :
96 156 : size_t maxChars = std::min(destLength - 1, source.size());
97 156 : memcpy(dest, source.data(), maxChars);
98 156 : dest[maxChars] = '\0';
99 : }
100 :
101 : /**
102 : * Convenience method for CopyString to auto-detect destination size.
103 : */
104 : template <size_t N>
105 : inline void CopyString(char (&dest)[N], ByteSpan source)
106 : {
107 : CopyString(dest, N, source);
108 : }
109 :
110 : /**
111 : * Creates a null-terminated string from a CharSpan.
112 : * If dest is nullptr, no copy happens. Non-nullptr result is always null-terminated.
113 : *
114 : * @param[in] dest Destination string buffer or nullptr.
115 : *
116 : * @param[in] destLength Maximum length to be copied. Will need space for null terminator as
117 : * well (string will be truncated if it does not fit). If 0 this method
118 : * is a noop.
119 : *
120 : * @param[in] source Data to be copied.
121 : */
122 736 : inline void CopyString(char * dest, size_t destLength, CharSpan source)
123 : {
124 736 : if ((dest == nullptr) || (destLength == 0))
125 : {
126 0 : return; // no space to copy anything, not even a null terminator
127 : }
128 :
129 736 : if (source.empty())
130 : {
131 728 : *dest = '\0'; // just a null terminator, we are copying empty data
132 728 : return;
133 : }
134 :
135 8 : size_t maxChars = std::min(destLength - 1, source.size());
136 8 : memcpy(dest, source.data(), maxChars);
137 8 : dest[maxChars] = '\0';
138 : }
139 :
140 : /**
141 : * Convenience method for CopyString to auto-detect destination size.
142 : */
143 : template <size_t N>
144 732 : inline void CopyString(char (&dest)[N], CharSpan source)
145 : {
146 732 : CopyString(dest, N, source);
147 732 : }
148 :
149 : /**
150 : * This function copies a C-style string to memory newly allocated by Platform::MemoryAlloc().
151 : *
152 : * @param[in] string String to be copied.
153 : *
154 : * @param[in] length Length to be copied. Like `strncpy()`, if the `string` is shorter
155 : * than `length`, then the remaining space will be filled with null
156 : * bytes. Like `strndup()` but unlike `strncpy()`, the result is always
157 : * null-terminated.
158 : *
159 : * @retval Pointer to a null-terminated string in case of success.
160 : * @retval `nullptr` if memory allocation fails.
161 : *
162 : */
163 0 : inline char * MemoryAllocString(const char * string, size_t length)
164 : {
165 0 : size_t lengthWithNull = length + 1;
166 0 : char * result = static_cast<char *>(MemoryAlloc(lengthWithNull));
167 0 : CopyString(result, lengthWithNull, string);
168 0 : return result;
169 : }
170 :
171 : /**
172 : * Represents a C string in a ScopedMemoryBuffer.
173 : */
174 :
175 : class ScopedMemoryString : public ScopedMemoryBuffer<char>
176 : {
177 : public:
178 : /**
179 : * Create a ScopedMemoryString.
180 : *
181 : * @param[in] string String to be copied.
182 : *
183 : * @param[in] length Length to be copied. Like `strncpy()`, if the `string` is shorter than
184 : * `length`, then the remaining space will be filled with null bytes. Like
185 : * `strndup()` but unlike `strncpy()`, the result is always null-terminated.
186 : */
187 4 : ScopedMemoryString(const char * string, size_t length)
188 4 : {
189 4 : size_t lengthWithNull = length + 1;
190 :
191 : // We must convert the source string to a CharSpan, so we call the
192 : // version of CopyString that handles unterminated strings.
193 4 : CopyString(Alloc(lengthWithNull).Get(), lengthWithNull, CharSpan(string, length));
194 4 : }
195 : };
196 :
197 : } // namespace Platform
198 : } // namespace chip
|