00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
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
00076
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)
00086 {
00087 size_t len = end - src;
00088 std::memcpy(dst, src, len + 1);
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
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 }
00226 }