1 /* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
2 *
3 * Copyright (c) 2014-2015 Datalight, Inc.
4 * All Rights Reserved Worldwide.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; use version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
12 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 /* Businesses and individuals that for commercial or other reasons cannot
21 * comply with the terms of the GPLv2 license may obtain a commercial license
22 * before incorporating Reliance Edge into proprietary software for
23 * distribution in any form. Visit http://www.datalight.com/reliance-edge for
24 * more information.
25 */
26
27 /** @file
28 * @brief Default implementations of memory manipulation functions.
29 *
30 * These implementations are intended to be small and simple, and thus forego
31 * all optimizations. If the C library is available, or if there are better
32 * third-party implementations available in the system, those can be used
33 * instead by defining the appropriate macros in redconf.h.
34 *
35 * These functions are not intended to be completely 100% ANSI C compatible
36 * implementations, but rather are designed to meet the needs of Reliance Edge.
37 * The compatibility is close enough that ANSI C compatible implementations
38 * can be "dropped in" as replacements without difficulty.
39 */
40 #include <redfs.h>
41
42
43 #ifndef RedMemCpyUnchecked
44 static void RedMemCpyUnchecked( void * pDest,
45 const void * pSrc,
46 uint32_t ulLen );
47 #endif
48 #ifndef RedMemMoveUnchecked
49 static void RedMemMoveUnchecked( void * pDest,
50 const void * pSrc,
51 uint32_t ulLen );
52 #endif
53 #ifndef RedMemSetUnchecked
54 static void RedMemSetUnchecked( void * pDest,
55 uint8_t bVal,
56 uint32_t ulLen );
57 #endif
58 #ifndef RedMemCmpUnchecked
59 static int32_t RedMemCmpUnchecked( const void * pMem1,
60 const void * pMem2,
61 uint32_t ulLen );
62 #endif
63
64
65 /** @brief Copy memory from one address to another.
66 *
67 * The source and destination memory buffers should not overlap. If the
68 * buffers overlap, use RedMemMove() instead.
69 *
70 * @param pDest The destination buffer.
71 * @param pSrc The source buffer.
72 * @param ulLen The number of bytes to copy.
73 */
RedMemCpy(void * pDest,const void * pSrc,uint32_t ulLen)74 void RedMemCpy( void * pDest,
75 const void * pSrc,
76 uint32_t ulLen )
77 {
78 if( ( pDest == NULL ) || ( pSrc == NULL ) )
79 {
80 REDERROR();
81 }
82 else
83 {
84 RedMemCpyUnchecked( pDest, pSrc, ulLen );
85 }
86 }
87
88
89 #ifndef RedMemCpyUnchecked
90
91 /** @brief Copy memory from one address to another.
92 *
93 * This function should only be called from RedMemCpy().
94 *
95 * @param pDest The destination buffer.
96 * @param pSrc The source buffer.
97 * @param ulLen The number of bytes to copy.
98 */
RedMemCpyUnchecked(void * pDest,const void * pSrc,uint32_t ulLen)99 static void RedMemCpyUnchecked( void * pDest,
100 const void * pSrc,
101 uint32_t ulLen )
102 {
103 uint8_t * pbDest = CAST_VOID_PTR_TO_UINT8_PTR( pDest );
104 const uint8_t * pbSrc = CAST_VOID_PTR_TO_CONST_UINT8_PTR( pSrc );
105 uint32_t ulIdx;
106
107 for( ulIdx = 0U; ulIdx < ulLen; ulIdx++ )
108 {
109 pbDest[ ulIdx ] = pbSrc[ ulIdx ];
110 }
111 }
112 #endif /* ifndef RedMemCpyUnchecked */
113
114
115 /** @brief Move memory from one address to another.
116 *
117 * Supports overlapping memory regions. If memory regions do not overlap, it
118 * is generally better to use RedMemCpy() instead.
119 *
120 * @param pDest The destination buffer.
121 * @param pSrc The source buffer.
122 * @param ulLen The number of bytes to copy.
123 */
RedMemMove(void * pDest,const void * pSrc,uint32_t ulLen)124 void RedMemMove( void * pDest,
125 const void * pSrc,
126 uint32_t ulLen )
127 {
128 if( ( pDest == NULL ) || ( pSrc == NULL ) )
129 {
130 REDERROR();
131 }
132 else
133 {
134 RedMemMoveUnchecked( pDest, pSrc, ulLen );
135 }
136 }
137
138
139 #ifndef RedMemMoveUnchecked
140
141 /** @brief Move memory from one address to another.
142 *
143 * This function should only be called from RedMemMove().
144 *
145 * @param pDest The destination buffer.
146 * @param pSrc The source buffer.
147 * @param ulLen The number of bytes to copy.
148 */
RedMemMoveUnchecked(void * pDest,const void * pSrc,uint32_t ulLen)149 static void RedMemMoveUnchecked( void * pDest,
150 const void * pSrc,
151 uint32_t ulLen )
152 {
153 uint8_t * pbDest = CAST_VOID_PTR_TO_UINT8_PTR( pDest );
154 const uint8_t * pbSrc = CAST_VOID_PTR_TO_CONST_UINT8_PTR( pSrc );
155 uint32_t ulIdx;
156
157 if( MEMMOVE_MUST_COPY_FORWARD( pbDest, pbSrc ) )
158 {
159 /* If the destination is lower than the source with overlapping memory
160 * regions, we must copy from start to end in order to copy the memory
161 * correctly.
162 *
163 * Don't use RedMemCpy() to do this. It is possible that RedMemCpy()
164 * has been replaced (even though this function has not been replaced)
165 * with an implementation that cannot handle any kind of buffer
166 * overlap.
167 */
168 for( ulIdx = 0U; ulIdx < ulLen; ulIdx++ )
169 {
170 pbDest[ ulIdx ] = pbSrc[ ulIdx ];
171 }
172 }
173 else
174 {
175 ulIdx = ulLen;
176
177 while( ulIdx > 0U )
178 {
179 ulIdx--;
180 pbDest[ ulIdx ] = pbSrc[ ulIdx ];
181 }
182 }
183 }
184 #endif /* RedMemMoveUnchecked */
185
186
187 /** @brief Initialize a buffer with the specified byte value.
188 *
189 * @param pDest The buffer to initialize.
190 * @param bVal The byte value with which to initialize @p pDest.
191 * @param ulLen The number of bytes to initialize.
192 */
RedMemSet(void * pDest,uint8_t bVal,uint32_t ulLen)193 void RedMemSet( void * pDest,
194 uint8_t bVal,
195 uint32_t ulLen )
196 {
197 if( pDest == NULL )
198 {
199 REDERROR();
200 }
201 else
202 {
203 RedMemSetUnchecked( pDest, bVal, ulLen );
204 }
205 }
206
207
208 #ifndef RedMemSetUnchecked
209
210 /** @brief Initialize a buffer with the specified byte value.
211 *
212 * This function should only be called from RedMemSet().
213 *
214 * @param pDest The buffer to initialize.
215 * @param bVal The byte value with which to initialize @p pDest.
216 * @param ulLen The number of bytes to initialize.
217 */
RedMemSetUnchecked(void * pDest,uint8_t bVal,uint32_t ulLen)218 static void RedMemSetUnchecked( void * pDest,
219 uint8_t bVal,
220 uint32_t ulLen )
221 {
222 uint8_t * pbDest = CAST_VOID_PTR_TO_UINT8_PTR( pDest );
223 uint32_t ulIdx;
224
225 for( ulIdx = 0U; ulIdx < ulLen; ulIdx++ )
226 {
227 pbDest[ ulIdx ] = bVal;
228 }
229 }
230 #endif /* ifndef RedMemSetUnchecked */
231
232
233 /** @brief Compare the contents of two buffers.
234 *
235 * @param pMem1 The first buffer to compare.
236 * @param pMem2 The second buffer to compare.
237 * @param ulLen The length to compare.
238 *
239 * @return Zero if the two buffers are the same, otherwise nonzero.
240 *
241 * @retval 0 @p pMem1 and @p pMem2 are the same.
242 * @retval 1 @p pMem1 is greater than @p pMem2, as determined by the
243 * values of the first differing bytes.
244 * @retval -1 @p pMem2 is greater than @p pMem1, as determined by the
245 * values of the first differing bytes.
246 */
RedMemCmp(const void * pMem1,const void * pMem2,uint32_t ulLen)247 int32_t RedMemCmp( const void * pMem1,
248 const void * pMem2,
249 uint32_t ulLen )
250 {
251 int32_t lResult;
252
253 if( ( pMem1 == NULL ) || ( pMem2 == NULL ) )
254 {
255 REDERROR();
256 lResult = 0;
257 }
258 else
259 {
260 lResult = RedMemCmpUnchecked( pMem1, pMem2, ulLen );
261 }
262
263 return lResult;
264 }
265
266
267 #ifndef RedMemCmpUnchecked
268
269 /** @brief Compare the contents of two buffers.
270 *
271 * @param pMem1 The first buffer to compare.
272 * @param pMem2 The second buffer to compare.
273 * @param ulLen The length to compare.
274 *
275 * @return Zero if the two buffers are the same, otherwise nonzero.
276 */
RedMemCmpUnchecked(const void * pMem1,const void * pMem2,uint32_t ulLen)277 static int32_t RedMemCmpUnchecked( const void * pMem1,
278 const void * pMem2,
279 uint32_t ulLen )
280 {
281 const uint8_t * pbMem1 = CAST_VOID_PTR_TO_CONST_UINT8_PTR( pMem1 );
282 const uint8_t * pbMem2 = CAST_VOID_PTR_TO_CONST_UINT8_PTR( pMem2 );
283 uint32_t ulIdx = 0U;
284 int32_t lResult;
285
286 while( ( ulIdx < ulLen ) && ( pbMem1[ ulIdx ] == pbMem2[ ulIdx ] ) )
287 {
288 ulIdx++;
289 }
290
291 if( ulIdx == ulLen )
292 {
293 lResult = 0;
294 }
295 else if( pbMem1[ ulIdx ] > pbMem2[ ulIdx ] )
296 {
297 lResult = 1;
298 }
299 else
300 {
301 lResult = -1;
302 }
303
304 return lResult;
305 }
306 #endif /* ifndef RedMemCmpUnchecked */
307