| /* ----> DO NOT REMOVE THE FOLLOWING NOTICE <---- | |
| Copyright (c) 2014-2015 Datalight, Inc. | |
| All Rights Reserved Worldwide. | |
| This program is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; use version 2 of the License. | |
| This program is distributed in the hope that it will be useful, | |
| but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty | |
| of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| GNU General Public License for more details. | |
| You should have received a copy of the GNU General Public License along | |
| with this program; if not, write to the Free Software Foundation, Inc., | |
| 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| */ | |
| /* Businesses and individuals that for commercial or other reasons cannot | |
| comply with the terms of the GPLv2 license may obtain a commercial license | |
| before incorporating Reliance Edge into proprietary software for | |
| distribution in any form. Visit http://www.datalight.com/reliance-edge for | |
| more information. | |
| */ | |
| /** @file | |
| @brief Default implementations of memory manipulation functions. | |
| These implementations are intended to be small and simple, and thus forego | |
| all optimizations. If the C library is available, or if there are better | |
| third-party implementations available in the system, those can be used | |
| instead by defining the appropriate macros in redconf.h. | |
| These functions are not intended to be completely 100% ANSI C compatible | |
| implementations, but rather are designed to meet the needs of Reliance Edge. | |
| The compatibility is close enough that ANSI C compatible implementations | |
| can be "dropped in" as replacements without difficulty. | |
| */ | |
| #include <redfs.h> | |
| #ifndef RedMemCpyUnchecked | |
| static void RedMemCpyUnchecked(void *pDest, const void *pSrc, uint32_t ulLen); | |
| #endif | |
| #ifndef RedMemMoveUnchecked | |
| static void RedMemMoveUnchecked(void *pDest, const void *pSrc, uint32_t ulLen); | |
| #endif | |
| #ifndef RedMemSetUnchecked | |
| static void RedMemSetUnchecked(void *pDest, uint8_t bVal, uint32_t ulLen); | |
| #endif | |
| #ifndef RedMemCmpUnchecked | |
| static int32_t RedMemCmpUnchecked(const void *pMem1, const void *pMem2, uint32_t ulLen); | |
| #endif | |
| /** @brief Copy memory from one address to another. | |
| The source and destination memory buffers should not overlap. If the | |
| buffers overlap, use RedMemMove() instead. | |
| @param pDest The destination buffer. | |
| @param pSrc The source buffer. | |
| @param ulLen The number of bytes to copy. | |
| */ | |
| void RedMemCpy( | |
| void *pDest, | |
| const void *pSrc, | |
| uint32_t ulLen) | |
| { | |
| if((pDest == NULL) || (pSrc == NULL)) | |
| { | |
| REDERROR(); | |
| } | |
| else | |
| { | |
| RedMemCpyUnchecked(pDest, pSrc, ulLen); | |
| } | |
| } | |
| #ifndef RedMemCpyUnchecked | |
| /** @brief Copy memory from one address to another. | |
| This function should only be called from RedMemCpy(). | |
| @param pDest The destination buffer. | |
| @param pSrc The source buffer. | |
| @param ulLen The number of bytes to copy. | |
| */ | |
| static void RedMemCpyUnchecked( | |
| void *pDest, | |
| const void *pSrc, | |
| uint32_t ulLen) | |
| { | |
| uint8_t *pbDest = CAST_VOID_PTR_TO_UINT8_PTR(pDest); | |
| const uint8_t *pbSrc = CAST_VOID_PTR_TO_CONST_UINT8_PTR(pSrc); | |
| uint32_t ulIdx; | |
| for(ulIdx = 0U; ulIdx < ulLen; ulIdx++) | |
| { | |
| pbDest[ulIdx] = pbSrc[ulIdx]; | |
| } | |
| } | |
| #endif | |
| /** @brief Move memory from one address to another. | |
| Supports overlapping memory regions. If memory regions do not overlap, it | |
| is generally better to use RedMemCpy() instead. | |
| @param pDest The destination buffer. | |
| @param pSrc The source buffer. | |
| @param ulLen The number of bytes to copy. | |
| */ | |
| void RedMemMove( | |
| void *pDest, | |
| const void *pSrc, | |
| uint32_t ulLen) | |
| { | |
| if((pDest == NULL) || (pSrc == NULL)) | |
| { | |
| REDERROR(); | |
| } | |
| else | |
| { | |
| RedMemMoveUnchecked(pDest, pSrc, ulLen); | |
| } | |
| } | |
| #ifndef RedMemMoveUnchecked | |
| /** @brief Move memory from one address to another. | |
| This function should only be called from RedMemMove(). | |
| @param pDest The destination buffer. | |
| @param pSrc The source buffer. | |
| @param ulLen The number of bytes to copy. | |
| */ | |
| static void RedMemMoveUnchecked( | |
| void *pDest, | |
| const void *pSrc, | |
| uint32_t ulLen) | |
| { | |
| uint8_t *pbDest = CAST_VOID_PTR_TO_UINT8_PTR(pDest); | |
| const uint8_t *pbSrc = CAST_VOID_PTR_TO_CONST_UINT8_PTR(pSrc); | |
| uint32_t ulIdx; | |
| if(MEMMOVE_MUST_COPY_FORWARD(pbDest, pbSrc)) | |
| { | |
| /* If the destination is lower than the source with overlapping memory | |
| regions, we must copy from start to end in order to copy the memory | |
| correctly. | |
| Don't use RedMemCpy() to do this. It is possible that RedMemCpy() | |
| has been replaced (even though this function has not been replaced) | |
| with an implementation that cannot handle any kind of buffer | |
| overlap. | |
| */ | |
| for(ulIdx = 0U; ulIdx < ulLen; ulIdx++) | |
| { | |
| pbDest[ulIdx] = pbSrc[ulIdx]; | |
| } | |
| } | |
| else | |
| { | |
| ulIdx = ulLen; | |
| while(ulIdx > 0U) | |
| { | |
| ulIdx--; | |
| pbDest[ulIdx] = pbSrc[ulIdx]; | |
| } | |
| } | |
| } | |
| #endif /* RedMemMoveUnchecked */ | |
| /** @brief Initialize a buffer with the specified byte value. | |
| @param pDest The buffer to initialize. | |
| @param bVal The byte value with which to initialize @p pDest. | |
| @param ulLen The number of bytes to initialize. | |
| */ | |
| void RedMemSet( | |
| void *pDest, | |
| uint8_t bVal, | |
| uint32_t ulLen) | |
| { | |
| if(pDest == NULL) | |
| { | |
| REDERROR(); | |
| } | |
| else | |
| { | |
| RedMemSetUnchecked(pDest, bVal, ulLen); | |
| } | |
| } | |
| #ifndef RedMemSetUnchecked | |
| /** @brief Initialize a buffer with the specified byte value. | |
| This function should only be called from RedMemSet(). | |
| @param pDest The buffer to initialize. | |
| @param bVal The byte value with which to initialize @p pDest. | |
| @param ulLen The number of bytes to initialize. | |
| */ | |
| static void RedMemSetUnchecked( | |
| void *pDest, | |
| uint8_t bVal, | |
| uint32_t ulLen) | |
| { | |
| uint8_t *pbDest = CAST_VOID_PTR_TO_UINT8_PTR(pDest); | |
| uint32_t ulIdx; | |
| for(ulIdx = 0U; ulIdx < ulLen; ulIdx++) | |
| { | |
| pbDest[ulIdx] = bVal; | |
| } | |
| } | |
| #endif | |
| /** @brief Compare the contents of two buffers. | |
| @param pMem1 The first buffer to compare. | |
| @param pMem2 The second buffer to compare. | |
| @param ulLen The length to compare. | |
| @return Zero if the two buffers are the same, otherwise nonzero. | |
| @retval 0 @p pMem1 and @p pMem2 are the same. | |
| @retval 1 @p pMem1 is greater than @p pMem2, as determined by the | |
| values of the first differing bytes. | |
| @retval -1 @p pMem2 is greater than @p pMem1, as determined by the | |
| values of the first differing bytes. | |
| */ | |
| int32_t RedMemCmp( | |
| const void *pMem1, | |
| const void *pMem2, | |
| uint32_t ulLen) | |
| { | |
| int32_t lResult; | |
| if((pMem1 == NULL) || (pMem2 == NULL)) | |
| { | |
| REDERROR(); | |
| lResult = 0; | |
| } | |
| else | |
| { | |
| lResult = RedMemCmpUnchecked(pMem1, pMem2, ulLen); | |
| } | |
| return lResult; | |
| } | |
| #ifndef RedMemCmpUnchecked | |
| /** @brief Compare the contents of two buffers. | |
| @param pMem1 The first buffer to compare. | |
| @param pMem2 The second buffer to compare. | |
| @param ulLen The length to compare. | |
| @return Zero if the two buffers are the same, otherwise nonzero. | |
| */ | |
| static int32_t RedMemCmpUnchecked( | |
| const void *pMem1, | |
| const void *pMem2, | |
| uint32_t ulLen) | |
| { | |
| const uint8_t *pbMem1 = CAST_VOID_PTR_TO_CONST_UINT8_PTR(pMem1); | |
| const uint8_t *pbMem2 = CAST_VOID_PTR_TO_CONST_UINT8_PTR(pMem2); | |
| uint32_t ulIdx = 0U; | |
| int32_t lResult; | |
| while((ulIdx < ulLen) && (pbMem1[ulIdx] == pbMem2[ulIdx])) | |
| { | |
| ulIdx++; | |
| } | |
| if(ulIdx == ulLen) | |
| { | |
| lResult = 0; | |
| } | |
| else if(pbMem1[ulIdx] > pbMem2[ulIdx]) | |
| { | |
| lResult = 1; | |
| } | |
| else | |
| { | |
| lResult = -1; | |
| } | |
| return lResult; | |
| } | |
| #endif | |