blocxx

SafeCString.cpp

Go to the documentation of this file.
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