Add UUID, c16lcpy (strlcpy for char16*), and their tests to util.

These are dependencies of the upcoming MinidumpStringWriter.

R=rsesek@chromium.org

Review URL: https://codereview.chromium.org/430003003
This commit is contained in:
Mark Mentovai 2014-08-01 14:39:55 -04:00
parent 5ba343ccf1
commit 4d6b867a1f
8 changed files with 429 additions and 0 deletions

62
util/misc/uuid.cc Normal file
View File

@ -0,0 +1,62 @@
// Copyright 2014 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "util/misc/uuid.h"
#include <string.h>
#include "base/basictypes.h"
#include "base/strings/stringprintf.h"
#include "util/stdlib/cxx.h"
#if CXX_LIBRARY_VERSION >= 2011
#include <type_traits>
#endif
namespace crashpad {
#if CXX_LIBRARY_VERSION >= 2011
COMPILE_ASSERT(std::is_standard_layout<UUID>::value,
UUID_must_be_standard_layout);
#endif
UUID::UUID() : data() {
}
UUID::UUID(const uint8_t* bytes) {
memcpy(data, bytes, sizeof(data));
}
std::string UUID::ToString() const {
return base::StringPrintf(
"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
data[0],
data[1],
data[2],
data[3],
data[4],
data[5],
data[6],
data[7],
data[8],
data[9],
data[10],
data[11],
data[12],
data[13],
data[14],
data[15]);
}
} // namespace crashpad

53
util/misc/uuid.h Normal file
View File

@ -0,0 +1,53 @@
// Copyright 2014 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CRASHPAD_UTIL_MISC_UUID_H_
#define CRASHPAD_UTIL_MISC_UUID_H_
#include <stdint.h>
#include <string>
namespace crashpad {
//! \brief A universally unique identifier (%UUID).
//!
//! An alternate term for %UUID is “globally unique identifier” (GUID), used
//! primarily by Microsoft.
//!
//! A %UUID is a unique 128-bit number specified by RFC 4122.
//!
//! This is a standard-layout structure, and it is acceptable to use `memcpy()`
//! to set its value.
struct UUID {
//! \brief Initializes the %UUID to zero.
UUID();
//! \brief Initializes the %UUID from a sequence of bytes.
//!
//! \param[in] bytes A buffer of exactly 16 bytes that will be assigned to the
//! %UUID.
explicit UUID(const uint8_t* bytes);
//! \brief Formats the %UUID per RFC 4122 §3.
//!
//! \return A string of the form `"00112233-4455-6677-8899-aabbccddeeff"`.
std::string ToString() const;
uint8_t data[16];
};
} // namespace crashpad
#endif // CRASHPAD_UTIL_MISC_UUID_H_

78
util/misc/uuid_test.cc Normal file
View File

@ -0,0 +1,78 @@
// Copyright 2014 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "util/misc/uuid.h"
#include <stdint.h>
#include <string>
#include "base/basictypes.h"
#include "gtest/gtest.h"
namespace {
using namespace crashpad;
TEST(UUID, UUID) {
UUID uuid_zero;
for (size_t index = 0; index < 16; ++index) {
EXPECT_EQ(0u, uuid_zero.data[index]);
}
EXPECT_EQ("00000000-0000-0000-0000-000000000000", uuid_zero.ToString());
const uint8_t kBytes[16] = {0x00,
0x01,
0x02,
0x03,
0x04,
0x05,
0x06,
0x07,
0x08,
0x09,
0x0a,
0x0b,
0x0c,
0x0d,
0x0e,
0x0f};
UUID uuid(kBytes);
for (size_t index = 0; index < arraysize(kBytes); ++index) {
EXPECT_EQ(kBytes[index], uuid.data[index]);
}
EXPECT_EQ("00010203-0405-0607-0809-0a0b0c0d0e0f", uuid.ToString());
// UUID is a standard-layout structure. It is valid to memcpy to it.
const uint8_t kMoreBytes[16] = {0xff,
0xee,
0xdd,
0xcc,
0xbb,
0xaa,
0x99,
0x88,
0x77,
0x66,
0x55,
0x44,
0x33,
0x22,
0x11,
0x00};
memcpy(&uuid, kMoreBytes, sizeof(kMoreBytes));
EXPECT_EQ("ffeeddcc-bbaa-9988-7766-554433221100", uuid.ToString());
}
} // namespace

57
util/stdlib/cxx.h Normal file
View File

@ -0,0 +1,57 @@
// Copyright 2014 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CRASHPAD_UTIL_STDLIB_CXX_H_
#define CRASHPAD_UTIL_STDLIB_CXX_H_
// <ciso646> doesnt do very much, and under libc++, it will cause the
// _LIBCPP_VERSION macro to be defined properly. Under libstdc++, it doesnt
// cause __GLIBCXX__ to be defined, but if _LIBCPP_VERSION isnt defined after
// #including <ciso646>, assume libstdc++ and #include libstdc++s internal
// header that defines __GLIBCXX__.
#include <ciso646>
#if !defined(_LIBCPP_VERSION)
#if defined(__has_include)
#if __has_include(<bits/c++config.h>)
#include <bits/c++config.h>
#endif
#else
#include <bits/c++config.h>
#endif
#endif
// libstdc++ does not identify its version directly, but identifies the GCC
// package it is a part of via the __GLIBCXX__ macro, which is based on the date
// of the GCC release. libstdc++ had sufficient C++11 support as of GCC 4.6.0,
// __GLIBCXX__ 20110325, but maintenance releases in the 4.4 an 4.5 series
// followed this date, so check for those versions by their date stamps.
// http://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html#abi.versioning
//
// libc++, identified by _LIBCPP_VERSION, always supports C++11.
#if __cplusplus >= 201103l && \
((defined(__GLIBCXX__) && \
__GLIBCXX__ >= 20110325ul && /* GCC >= 4.6.0 */ \
__GLIBCXX__ != 20110416ul && /* GCC 4.4.6 */ \
__GLIBCXX__ != 20120313ul && /* GCC 4.4.7 */ \
__GLIBCXX__ != 20110428ul && /* GCC 4.5.3 */ \
__GLIBCXX__ != 20120702ul) || /* GCC 4.5.4 */ \
(defined(_LIBCPP_VERSION)))
#define CXX_LIBRARY_VERSION 2011
#else
#define CXX_LIBRARY_VERSION 2003
#endif
#endif // CRASHPAD_UTIL_STDLIB_CXX_H_

30
util/stdlib/strlcpy.cc Normal file
View File

@ -0,0 +1,30 @@
// Copyright 2014 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "util/stdlib/strlcpy.h"
namespace crashpad {
size_t c16lcpy(char16* destination, const char16* source, size_t length) {
size_t source_length = base::c16len(source);
if (source_length < length) {
base::c16memcpy(destination, source, source_length + 1);
} else if (length != 0) {
base::c16memcpy(destination, source, length - 1);
destination[length - 1] = '\0';
}
return source_length;
}
} // namespace crashpad

52
util/stdlib/strlcpy.h Normal file
View File

@ -0,0 +1,52 @@
// Copyright 2014 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CRASHPAD_UTIL_STDLIB_STRLCPY_H_
#define CRASHPAD_UTIL_STDLIB_STRLCPY_H_
#include <stdint.h>
#include "base/strings/string16.h"
namespace crashpad {
//! \brief Copy a `NUL`-terminated char16-based string to a fixed-size buffer.
//!
//! This function behaves identically to `strlcpy()`, but it operates on char16
//! data instead of `char` data. It copies the `NUL`-terminated string in the
//! buffer beginning at \a source to the buffer of size \a length at \a
//! destination, ensuring that the destination buffer is `NUL`-terminated. No
//! data will be written outside of the \a destination buffer, but if \a length
//! is smaller than the length of the string at \a source, the string will be
//! truncated.
//!
//! \param[out] destination A pointer to a buffer of at least size \a length
//! char16 units (not bytes). The string will be copied to this buffer,
//! possibly with truncation, and `NUL`-terminated. Nothing will be written
//! following the `NUL` terminator.
//! \param[in] source A pointer to a `NUL`-terminated string of char16 data. The
//! `NUL` terminator must be a `NUL` value in a char16 unit, not just a
//! single `NUL` byte.
//! \param[in] length The length of the \a destination buffer in char16 units,
//! not bytes. A maximum of \a `length - 1` char16 units from \a source will
//! be copied to \a destination.
//!
//! \return The length of the \a source string in char16 units, not including
//! its `NUL` terminator. When truncation occurs, the return value will be
//! equal to or greater than than the \a length parameter.
size_t c16lcpy(char16* destination, const char16* source, size_t length);
} // namespace crashpad
#endif // CRASHPAD_UTIL_STDLIB_STRLCPY_H_

View File

@ -0,0 +1,90 @@
// Copyright 2014 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "util/stdlib/strlcpy.h"
#include <string.h>
#include <algorithm>
#include "base/strings/string16.h"
#include "base/strings/stringprintf.h"
#include "gtest/gtest.h"
namespace {
using namespace crashpad;
TEST(strlcpy, c16lcpy) {
// Use a destination buffer thats larger than the length passed to c16lcpy.
// The unused portion is a guard area that must not be written to.
struct TestBuffer {
char16 lead_guard[64];
char16 data[128];
char16 trail_guard[64];
};
TestBuffer expected_untouched;
memset(&expected_untouched, 0xa5, sizeof(expected_untouched));
// Test with M, é, Ā, ő, and Ḙ. This is a mix of characters that have zero and
// nonzero low and high bytes.
const char16 test_characters[] = {0x4d, 0xe9, 0x100, 0x151, 0x1e18};
for (size_t index = 0; index < arraysize(test_characters); ++index) {
char16 test_character = test_characters[index];
SCOPED_TRACE(base::StringPrintf(
"character index %zu, character 0x%x", index, test_character));
for (size_t length = 0; length < 256; ++length) {
SCOPED_TRACE(base::StringPrintf("index %zu", length));
string16 test_string(length, test_character);
TestBuffer destination;
memset(&destination, 0xa5, sizeof(destination));
EXPECT_EQ(length,
c16lcpy(destination.data,
test_string.c_str(),
arraysize(destination.data)));
// Make sure that the destination buffer is NUL-terminated, and that as
// much of the test string was copied as could fit.
size_t expected_destination_length =
std::min(length, arraysize(destination.data) - 1);
EXPECT_EQ('\0', destination.data[expected_destination_length]);
EXPECT_EQ(expected_destination_length, base::c16len(destination.data));
EXPECT_TRUE(base::c16memcmp(test_string.c_str(),
destination.data,
expected_destination_length) == 0);
// Make sure that the portion of the destination buffer that was not used
// was not touched. This includes the guard areas and the unused portion
// of the buffer passed to c16lcpy.
EXPECT_TRUE(base::c16memcmp(expected_untouched.lead_guard,
destination.lead_guard,
arraysize(destination.lead_guard)) == 0);
size_t expected_untouched_length =
arraysize(destination.data) - expected_destination_length - 1;
EXPECT_TRUE(
base::c16memcmp(expected_untouched.data,
&destination.data[expected_destination_length + 1],
expected_untouched_length) == 0);
EXPECT_TRUE(base::c16memcmp(expected_untouched.trail_guard,
destination.trail_guard,
arraysize(destination.trail_guard)) == 0);
}
}
}
} // namespace

View File

@ -32,6 +32,11 @@
'file/file_writer.h',
'file/string_file_writer.cc',
'file/string_file_writer.h',
'misc/uuid.cc',
'misc/uuid.h',
'stdlib/cxx.h',
'stdlib/strlcpy.cc',
'stdlib/strlcpy.h',
],
},
{
@ -49,6 +54,8 @@
'sources': [
'../third_party/gtest/gtest/src/gtest_main.cc',
'file/string_file_writer_test.cc',
'misc/uuid_test.cc',
'stdlib/strlcpy_test.cc',
],
},
],