/* ----> 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 #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 /* ifndef RedMemCpyUnchecked */ /** @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 /* ifndef RedMemSetUnchecked */ /** @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 /* ifndef RedMemCmpUnchecked */