summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordeanm@google.com <deanm@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-13 14:33:40 +0000
committerdeanm@google.com <deanm@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-13 14:33:40 +0000
commit954d58c4d2bd4499ed61da01ee22684669e12f28 (patch)
treeb4e80cfdeea18ecc3fde0aef5cb46754575f3486
parent4794938ba46c128bd207c4f4509f86b1aceb1284 (diff)
downloadchromium_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.cc10
-rw-r--r--base/string_util.cc31
-rw-r--r--base/string_util.h9
-rw-r--r--base/string_util_unittest.cc53
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));
+ }
+}