00001 #include "OW_SafeCString.hpp"
00002
00003 #include <cstring>
00004 #include <new>
00005
00006 namespace
00007 {
00008 inline char * strend(char * s, std::size_t n)
00009 {
00010 return static_cast<char *>(std::memchr(s, '\0', n));
00011 }
00012
00013 char * strend_checked(char * s, std::size_t n)
00014 {
00015 char * retval = strend(s, n);
00016 if (retval)
00017 {
00018 return retval;
00019 }
00020 else
00021 {
00022 OW_THROW_ERR(
00023 OverflowException,
00024 "cstring catenation first operand unterminated",
00025 DEST_UNTERMINATED
00026 );
00027 }
00028 }
00029
00030
00031
00032
00033 inline char * safe_strcpy(char * dst, char const * src, std::size_t n)
00034 {
00035 #ifdef OW_HAS_MEMCCPY
00036 return static_cast<char *>(std::memccpy(dst, src, '\0', n));
00037 #else
00038 char const * end = strend(src, n);
00039 if (end)
00040 {
00041 n = (end - src) + 1;
00042 std::memcpy(dst, src, n);
00043 return dst + n;
00044 }
00045 else
00046 {
00047 std::memcpy(dst, src, n);
00048 return 0;
00049 }
00050 #endif
00051 }
00052 }
00053
00054 namespace OW_NAMESPACE
00055 {
00056 namespace SafeCString
00057 {
00058
00059 OW_DEFINE_EXCEPTION(Overflow);
00060
00061 char * str_dup(char const * s);
00062 {
00063 char * retval = new char[std::strlen(s) + 1];
00064 return std::strcpy(retval, s);
00065 }
00066
00067 char * str_dup_nothrow(char const * s);
00068 {
00069 char * retval = new (std::nothrow) char[std::strlen(s)];
00070 if (retval)
00071 {
00072 std::strcpy(retval, s);
00073 }
00074 return retval;
00075 }
00076
00077 char * strcpy_trunc(char * dst, std::size_t dstsize, char const * src)
00078 {
00079 std::size_t n = dstsize - 1;
00080 char * retval = safe_strcpy(dst, src, n);
00081 if (retval)
00082 {
00083 return retval;
00084 }
00085 else
00086 {
00087 dst[n] = '\0';
00088 return dst + n;
00089 }
00090 }
00091
00092 char * strcpy_trunc(
00093 char * dst, std::size_t dstsize, char const * src, std::size_t srclen
00094 )
00095 {
00096 std::size_t n = (srclen < dstsize ? srclen : dstsize - 1);
00097 char * retval = safe_strcpy(dst, src, n);
00098 if (retval)
00099 {
00100 return retval;
00101 }
00102 else
00103 {
00104 dst[n] = '\0';
00105 return dst + n;
00106 }
00107 }
00108
00109 char * strcpy_check(char * dst, std::size_t dstsize, char const * src)
00110 {
00111 char * retval = safe_strcpy(dst, src, dstsize);
00112 if (retval)
00113 {
00114 return retval;
00115 }
00116 else
00117 {
00118 dst[dstsize - 1] = '\0';
00119 OW_THROW_ERR(
00120 OverflowException, "cstring copy overflow", RESULT_TRUNCATED);
00121 }
00122 }
00123
00124 char * strcpy_check(
00125 char * dst, std::size_t dstsize, char const * src, std::size_t srclen
00126 )
00127 {
00128 if (srclen >= dstsize)
00129 {
00130 return strcpy_check(dst, dstsize, src);
00131 }
00132 else
00133 {
00134 return strcpy_trunc(dst, srclen + 1, src);
00135 }
00136 }
00137
00138 char * strcat_trunc(char * dst, std::size_t dstsize, char const * src)
00139 {
00140 char * dstend = strend_checked(dst, dstsize);
00141 return strcpy_trunc(dstend, (dst + dstsize) - dstend, src);
00142 }
00143
00144 char * strcat_trunc(
00145 char * dst, std::size_t dstsize, char const * src, std::size_t srclen
00146 )
00147 {
00148 char * dstend = strend_checked(dst, dstsize);
00149 return strcpy_trunc(dstend, (dst + dstsize) - dstend, src, srclen);
00150 }
00151
00152 char * strcat_check(char * dst, std::size_t dstsize, char const * src)
00153 {
00154 char * dstend = strend_checked(dst, dstsize);
00155 return strcpy_check(dstend, (dst + dstsize) - dstend, src);
00156 }
00157
00158 char * strcat_check(
00159 char * dst, std::size_t dstsize, char const * src, std::size_t srclen
00160 )
00161 {
00162 char * dstend = strend_checked(dst, dstsize);
00163 return strcpy_check(dstend, (dst + dstsize) - dstend, src, srclen);
00164 }
00165
00166 namespace Impl
00167 {
00168 std::size_t nchars_check(int retval, std::size_t dstsize)
00169 {
00170 if (retval < 0 || retval >= static_cast<int>(dstsize))
00171 {
00172 OW_THROW_ERR(
00173 OverflowException, "sprintf overflow", RESULT_TRUNCATED);
00174 }
00175 return static_cast<std::size_t>(retval);
00176 }
00177 }
00178
00179 char * fgets_trunc(char * dst, std::size_t dstsize, FILE * fp)
00180 {
00181 char * res = std::fgets(dst, dstsize, fp);
00182 if (!res)
00183 {
00184 if (std::feof(fp))
00185 {
00186 return 0;
00187 }
00188 OW_THROW(OpenWBEM::IOException, "read error");
00189 }
00190 return res;
00191 }
00192
00193 char * fgets_check(char * dst, std::size_t dstsize, FILE * fp)
00194 {
00195 std::size_t const end = dstsize - 1;
00196 char savechar = dst[end];
00197 dst[end] = ' ';
00198 char * res = std::fgets(dst, dstsize, fp);
00199 char endchar = dst[end];
00200 dst[end] = savechar;
00201 if (res)
00202 {
00203 if (endchar == '\0' && (end == 0 || dst[end - 1] != '\n'))
00204 {
00205
00206
00207
00208
00209
00210 std::ungetc(std::fgetc(fp), fp);
00211 if (!std::feof(fp))
00212 {
00213 OW_THROW_ERR(
00214 OverflowException, "fgets overflow", RESULT_TRUNCATED);
00215 }
00216 }
00217 return res;
00218 }
00219 else
00220 {
00221 if (std::feof(fp))
00222 {
00223 return 0;
00224 }
00225 OW_THROW(OpenWBEM::IOException, "read error");
00226 }
00227 }
00228
00229 String fget_string(FILE * fp, std::size_t const max_chars)
00230 {
00231
00232
00233 std::size_t const BUFSIZE = 8 * 1024;
00234 StringBuffer sb;
00235 char buf[BUFSIZE];
00236 while (!sb.endsWith('\n') && sb.length() <= max_chars &&
00237 fgets_trunc(buf, fp))
00238 {
00239 sb.append(buf);
00240 }
00241 if (sb.length() > max_chars)
00242 {
00243 OW_THROW(StringConversionException, "input line too long");
00244 }
00245 return sb.releaseString();
00246 }
00247
00248 }
00249 }