blocxx
|
00001 /******************************************************************************* 00002 * Copyright (C) 2005, Vintela, Inc. All rights reserved. 00003 * Copyright (C) 2006, Novell, Inc. All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * * Redistributions of source code must retain the above copyright notice, 00009 * this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * * Neither the name of 00014 * Vintela, Inc., 00015 * nor Novell, Inc., 00016 * nor the names of its contributors or employees may be used to 00017 * endorse or promote products derived from this software without 00018 * specific prior written permission. 00019 * 00020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00021 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00022 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00023 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00024 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00025 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00026 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00027 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00028 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00029 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00030 * POSSIBILITY OF SUCH DAMAGE. 00031 *******************************************************************************/ 00032 00033 00038 #include "blocxx/BLOCXX_config.h" 00039 #include "blocxx/SafeCString.hpp" 00040 #include <cstring> 00041 #include <new> 00042 00043 using namespace blocxx; 00044 using namespace blocxx::SafeCString; 00045 00046 namespace 00047 { 00048 inline char const * strend(char const * s, std::size_t n) 00049 { 00050 return static_cast<char const *>(std::memchr(s, '\0', n)); 00051 } 00052 00053 inline char * strend(char * s, std::size_t n) 00054 { 00055 return const_cast<char *>(strend(static_cast<char const *>(s), n)); 00056 } 00057 00058 char * strend_checked(char * s, std::size_t n) 00059 { 00060 char * retval = strend(s, n); 00061 if (retval) 00062 { 00063 return retval; 00064 } 00065 else 00066 { 00067 BLOCXX_THROW_ERR( 00068 OverflowException, 00069 "cstring catenation first operand unterminated", 00070 DEST_UNTERMINATED 00071 ); 00072 } 00073 } 00074 00075 // PROMISE: Copies first min(n, strlen(src) + 1) chars of src to dst. 00076 // RETURNS: dst + strlen(src) if strlen(src) < n, NULL otherwise. 00077 // 00078 inline char * safe_strcpy(char * dst, char const * src, std::size_t n) 00079 { 00080 #ifdef BLOCXX_HAS_MEMCCPY 00081 char * rv = static_cast<char *>(std::memccpy(dst, src, '\0', n)); 00082 return rv ? rv - 1 : 0; 00083 #else 00084 char const * end = strend(src, n); 00085 if (end) // '\0' found 00086 { 00087 size_t len = end - src; 00088 std::memcpy(dst, src, len + 1); // include terminating '\0' 00089 return dst + len; 00090 } 00091 else 00092 { 00093 std::memcpy(dst, src, n); 00094 return 0; 00095 } 00096 #endif 00097 } 00098 } 00099 00100 namespace BLOCXX_NAMESPACE 00101 { 00102 namespace SafeCString 00103 { 00104 00105 BLOCXX_DEFINE_EXCEPTION(Overflow); 00106 00107 char * str_dup(char const * s) 00108 { 00109 char * retval = new char[std::strlen(s) + 1]; 00110 return std::strcpy(retval, s); 00111 } 00112 00113 char * str_dup_nothrow(char const * s) 00114 { 00115 char * retval = new (std::nothrow) char[std::strlen(s)]; 00116 if (retval) 00117 { 00118 std::strcpy(retval, s); 00119 } 00120 return retval; 00121 } 00122 00123 char * strcpy_trunc(char * dst, std::size_t dstsize, char const * src) 00124 { 00125 std::size_t n = dstsize - 1; 00126 char * retval = safe_strcpy(dst, src, n); 00127 if (retval) 00128 { 00129 return retval; 00130 } 00131 else 00132 { 00133 dst[n] = '\0'; 00134 return dst + n; 00135 } 00136 } 00137 00138 char * strcpy_trunc( 00139 char * dst, std::size_t dstsize, char const * src, std::size_t srclen 00140 ) 00141 { 00142 std::size_t n = (srclen < dstsize ? srclen : dstsize - 1); 00143 char * retval = safe_strcpy(dst, src, n); 00144 if (retval) 00145 { 00146 return retval; 00147 } 00148 else 00149 { 00150 dst[n] = '\0'; 00151 return dst + n; 00152 } 00153 } 00154 00155 char * strcpy_check(char * dst, std::size_t dstsize, char const * src) 00156 { 00157 char * retval = safe_strcpy(dst, src, dstsize); 00158 if (retval) 00159 { 00160 return retval; 00161 } 00162 else 00163 { 00164 dst[dstsize - 1] = '\0'; 00165 BLOCXX_THROW_ERR( 00166 OverflowException, "cstring copy overflow", RESULT_TRUNCATED); 00167 } 00168 } 00169 00170 char * strcpy_check( 00171 char * dst, std::size_t dstsize, char const * src, std::size_t srclen 00172 ) 00173 { 00174 if (srclen >= dstsize) 00175 { 00176 return strcpy_check(dst, dstsize, src); 00177 } 00178 else // srclen < dstsize 00179 { 00180 return strcpy_trunc(dst, srclen + 1, src); 00181 } 00182 } 00183 00184 char * strcat_trunc(char * dst, std::size_t dstsize, char const * src) 00185 { 00186 char * dstend = strend_checked(dst, dstsize); 00187 return strcpy_trunc(dstend, (dst + dstsize) - dstend, src); 00188 } 00189 00190 char * strcat_trunc( 00191 char * dst, std::size_t dstsize, char const * src, std::size_t srclen 00192 ) 00193 { 00194 char * dstend = strend_checked(dst, dstsize); 00195 return strcpy_trunc(dstend, (dst + dstsize) - dstend, src, srclen); 00196 } 00197 00198 char * strcat_check(char * dst, std::size_t dstsize, char const * src) 00199 { 00200 char * dstend = strend_checked(dst, dstsize); 00201 return strcpy_check(dstend, (dst + dstsize) - dstend, src); 00202 } 00203 00204 char * strcat_check( 00205 char * dst, std::size_t dstsize, char const * src, std::size_t srclen 00206 ) 00207 { 00208 char * dstend = strend_checked(dst, dstsize); 00209 return strcpy_check(dstend, (dst + dstsize) - dstend, src, srclen); 00210 } 00211 00212 namespace Impl 00213 { 00214 std::size_t nchars_check(int retval, std::size_t dstsize) 00215 { 00216 if (retval < 0 || retval >= static_cast<int>(dstsize)) 00217 { 00218 BLOCXX_THROW_ERR( 00219 OverflowException, "sprintf overflow", RESULT_TRUNCATED); 00220 } 00221 return static_cast<std::size_t>(retval); 00222 } 00223 } 00224 00225 } // namespace SafeCString 00226 } // namespace BLOCXX_NAMESPACE