OW_SafeCString.cpp

Go to the documentation of this file.
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    // PROMISE: Copies first m = min(n, strlen(src) + 1) chars of src to dst.
00031    // RETURNS: dst + m if strlen(src) < n, NULL otherwise.
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) // '\0' found
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 // srclen < dstsize
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] = ' '; // anything but '\0'
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          // No newline at end.  Either the input line was truncated, or
00206          // we read the last line of the file and it had no newline.
00207          // We test for EOF to distinguish the two cases.  Since the EOF
00208          // marker doesn't get set until we actually try to read past EOF,
00209          // we first peek one character ahead.
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    // This could perhaps be made more efficient by reading directly into a
00232    // custom resizable character array.
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 } // namespace SafeCString
00249 } // namespace OW_NAMESPACE

Generated on Thu Feb 9 08:48:10 2006 for openwbem by  doxygen 1.4.6