diff options
author | deanm@google.com <deanm@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-08-13 14:33:40 +0000 |
---|---|---|
committer | deanm@google.com <deanm@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-08-13 14:33:40 +0000 |
commit | 954d58c4d2bd4499ed61da01ee22684669e12f28 (patch) | |
tree | b4e80cfdeea18ecc3fde0aef5cb46754575f3486 | |
parent | 4794938ba46c128bd207c4f4509f86b1aceb1284 (diff) | |
download | chromium_src-954d58c4d2bd4499ed61da01ee22684669e12f28.zip chromium_src-954d58c4d2bd4499ed61da01ee22684669e12f28.tar.gz chromium_src-954d58c4d2bd4499ed61da01ee22684669e12f28.tar.bz2 |
Implement an interface compatible wcslcpy and strlcpy. Possibly slightly
slower than the OpenBSD implementation, but a bit clearer and fits our style.
Move file_util_posix to use it now that we have it everywhere.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@798 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | base/file_util_posix.cc | 10 | ||||
-rw-r--r-- | base/string_util.cc | 31 | ||||
-rw-r--r-- | base/string_util.h | 9 | ||||
-rw-r--r-- | base/string_util_unittest.cc | 53 |
4 files changed, 95 insertions, 8 deletions
diff --git a/base/file_util_posix.cc b/base/file_util_posix.cc index 510747f..4f77e94 100644 --- a/base/file_util_posix.cc +++ b/base/file_util_posix.cc @@ -37,6 +37,7 @@ #include <fstream> +#include "base/basictypes.h" #include "base/logging.h" #include "base/string_util.h" @@ -44,14 +45,7 @@ namespace file_util { std::wstring GetDirectoryFromPath(const std::wstring& path) { char full_path[PATH_MAX]; -#if defined(OS_MACOSX) - strlcpy(full_path, WideToUTF8(path).c_str(), sizeof(full_path)); -#elif defined(OS_LINUX) - std::string utf8_path = WideToUTF8(path); - const char* cstr = utf8_path.c_str(); - strncpy(full_path, cstr, PATH_MAX); - cstr[PATH_MAX - 1] = '\0'; -#endif + base::strlcpy(full_path, WideToUTF8(path).c_str(), arraysize(full_path)); return UTF8ToWide(dirname(full_path)); } diff --git a/base/string_util.cc b/base/string_util.cc index 864612ae..7208cd0 100644 --- a/base/string_util.cc +++ b/base/string_util.cc @@ -1384,3 +1384,34 @@ double StringToDouble(const std::wstring& value) { StringToDouble(value, &result); return result; } + +// The following code is compatible with the OpenBSD lcpy interface. See: +// http://www.gratisoft.us/todd/papers/strlcpy.html +// ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/{wcs,str}lcpy.c + +namespace { + +template <typename CHAR> +size_t lcpyT(CHAR* dst, const CHAR* src, size_t dst_size) { + for (size_t i = 0; i < dst_size; ++i) { + if ((dst[i] = src[i]) == 0) // We hit and copied the terminating NULL. + return i; + } + + // We were left off at dst_size. We over copied 1 byte. Null terminate. + if (dst_size != 0) + dst[dst_size - 1] = 0; + + // Count the rest of the |src|, and return it's length in characters. + while (src[dst_size]) ++dst_size; + return dst_size; +} + +} // namespace + +size_t base::strlcpy(char* dst, const char* src, size_t dst_size) { + return lcpyT<char>(dst, src, dst_size); +} +size_t base::wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) { + return lcpyT<wchar_t>(dst, src, dst_size); +} diff --git a/base/string_util.h b/base/string_util.h index 17c1793..5faa9cf 100644 --- a/base/string_util.h +++ b/base/string_util.h @@ -83,6 +83,15 @@ inline int swprintf(wchar_t* buffer, size_t size, const wchar_t* format, ...) { return result; } +// BSD-style safe and consistent string copy functions. +// Copies |src| to |dst|, where |dst_size| is the total allocated size of |dst|. +// Copies at most |dst_size|-1 characters, and always NULL terminates |dst|, as +// long as |dst_size| is not 0. Returns the length of |src| in characters. +// If the return value is >= dst_size, then the output was truncated. +// NOTE: All sizes are in number of characters, NOT in bytes. +size_t strlcpy(char* dst, const char* src, size_t dst_size); +size_t wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size); + } // namespace base #if defined(OS_WIN) diff --git a/base/string_util_unittest.cc b/base/string_util_unittest.cc index fb3681b5..7cc9764 100644 --- a/base/string_util_unittest.cc +++ b/base/string_util_unittest.cc @@ -1252,4 +1252,57 @@ TEST(StringUtilTest, MatchPatternTest) { EXPECT_EQ(MatchPattern("Hello*", "Hello*"), true); // narrow string } +TEST(StringUtilTest, LcpyTest) { + // Test the normal case where we fit in our buffer. + { + char dst[10]; + wchar_t wdst[10]; + EXPECT_EQ(7, base::strlcpy(dst, "abcdefg", arraysize(dst))); + EXPECT_EQ(0, memcmp(dst, "abcdefg", 8)); + EXPECT_EQ(7, base::wcslcpy(wdst, L"abcdefg", arraysize(wdst))); + EXPECT_EQ(0, memcmp(wdst, L"abcdefg", sizeof(wchar_t) * 8)); + } + + // Test dst_size == 0, nothing should be written to |dst| and we should + // have the equivalent of strlen(src). + { + char dst[2] = {1, 2}; + wchar_t wdst[2] = {1, 2}; + EXPECT_EQ(7, base::strlcpy(dst, "abcdefg", 0)); + EXPECT_EQ(1, dst[0]); + EXPECT_EQ(2, dst[1]); + EXPECT_EQ(7, base::wcslcpy(wdst, L"abcdefg", 0)); + EXPECT_EQ(1, wdst[0]); + EXPECT_EQ(2, wdst[1]); + } + + // Test the case were we _just_ competely fit including the null. + { + char dst[8]; + wchar_t wdst[8]; + EXPECT_EQ(7, base::strlcpy(dst, "abcdefg", arraysize(dst))); + EXPECT_EQ(0, memcmp(dst, "abcdefg", 8)); + EXPECT_EQ(7, base::wcslcpy(wdst, L"abcdefg", arraysize(wdst))); + EXPECT_EQ(0, memcmp(wdst, L"abcdefg", sizeof(wchar_t) * 8)); + } + // Test the case were we we are one smaller, so we can't fit the null. + { + char dst[7]; + wchar_t wdst[7]; + EXPECT_EQ(7, base::strlcpy(dst, "abcdefg", arraysize(dst))); + EXPECT_EQ(0, memcmp(dst, "abcdef", 7)); + EXPECT_EQ(7, base::wcslcpy(wdst, L"abcdefg", arraysize(wdst))); + EXPECT_EQ(0, memcmp(wdst, L"abcdef", sizeof(wchar_t) * 7)); + } + + // Test the case were we are just too small. + { + char dst[3]; + wchar_t wdst[3]; + EXPECT_EQ(7, base::strlcpy(dst, "abcdefg", arraysize(dst))); + EXPECT_EQ(0, memcmp(dst, "ab", 3)); + EXPECT_EQ(7, base::wcslcpy(wdst, L"abcdefg", arraysize(wdst))); + EXPECT_EQ(0, memcmp(wdst, L"ab", sizeof(wchar_t) * 3)); + } +} |