diff options
Diffstat (limited to 'Firestore/core')
5 files changed, 265 insertions, 16 deletions
diff --git a/Firestore/core/src/firebase/firestore/util/CMakeLists.txt b/Firestore/core/src/firebase/firestore/util/CMakeLists.txt index d70397d..a2da3b4 100644 --- a/Firestore/core/src/firebase/firestore/util/CMakeLists.txt +++ b/Firestore/core/src/firebase/firestore/util/CMakeLists.txt @@ -12,50 +12,71 @@ # See the License for the specific language governing permissions and # limitations under the License. +# firebase_firestore_util is the interface of this module. The rest of the +# libraries in here are an implementation detail of making this a +# mutli-platform build. + add_library( - firebase_firestore_util - autoid.cc + firebase_firestore_util_base secure_random_arc4random.cc + string_printf.cc +) +target_link_libraries( + firebase_firestore_util_base + PRIVATE + absl_base ) -# log_stdio can be built and tested everywhere +# stdio-dependent bits can be built and tested everywhere add_library( - firebase_firestore_util_log_stdio + firebase_firestore_util_stdio log_stdio.cc ) +target_link_libraries( + firebase_firestore_util_stdio + PUBLIC + firebase_firestore_util_base +) -# log_apple can only built and tested on apple plaforms +# apple-dependent bits can only built and tested on apple plaforms if(APPLE) add_library( - firebase_firestore_util_log_apple + firebase_firestore_util_apple log_apple.mm ) target_compile_options( - firebase_firestore_util_log_apple + firebase_firestore_util_apple PRIVATE ${OBJC_FLAGS} ) target_link_libraries( - firebase_firestore_util_log_apple + firebase_firestore_util_apple PUBLIC FirebaseCore ) endif(APPLE) +add_library( + firebase_firestore_util + autoid.cc +) + # Export a dependency on the correct logging library for this platform. All # buildable libraries are built and tested but only the best fit is exported. if(APPLE) target_link_libraries( firebase_firestore_util PUBLIC - firebase_firestore_util_log_apple + firebase_firestore_util_apple + firebase_firestore_util_base ) else(NOT APPLE) target_link_libraries( firebase_firestore_util PUBLIC - firebase_firestore_util_log_stdio + firebase_firestore_util_stdio + firebase_firestore_util_base ) endif(APPLE) diff --git a/Firestore/core/src/firebase/firestore/util/string_printf.cc b/Firestore/core/src/firebase/firestore/util/string_printf.cc new file mode 100644 index 0000000..60cc564 --- /dev/null +++ b/Firestore/core/src/firebase/firestore/util/string_printf.cc @@ -0,0 +1,101 @@ +/* + * Copyright 2018 Google + * + * 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 "Firestore/core/src/firebase/firestore/util/string_printf.h" + +#include <stdio.h> + +namespace firebase { +namespace firestore { +namespace util { + +void StringAppendV(std::string* dst, const char* format, va_list ap) { + // First try with a small fixed size buffer + static const int kSpaceLength = 1024; + char space[kSpaceLength]; + + // It's possible for methods that use a va_list to invalidate + // the data in it upon use. The fix is to make a copy + // of the structure before using it and use that copy instead. + va_list backup_ap; + va_copy(backup_ap, ap); + int result = vsnprintf(space, kSpaceLength, format, backup_ap); + va_end(backup_ap); + + if (result < kSpaceLength) { + if (result >= 0) { + // Normal case -- everything fit. + dst->append(space, result); + return; + } + +#ifdef _MSC_VER + // Error or MSVC running out of space. MSVC 8.0 and higher + // can be asked about space needed with the special idiom below: + va_copy(backup_ap, ap); + result = vsnprintf(nullptr, 0, format, backup_ap); + va_end(backup_ap); +#endif + + if (result < 0) { + // Just an error. + return; + } + } + + // Increase the buffer size to the size requested by vsnprintf, + // plus one for the closing \0. + size_t initial_size = dst->size(); + size_t target_size = initial_size + result; + + dst->resize(target_size + 1); + char* buf = &(*dst)[initial_size]; + int buf_remain = result + 1; + + // Restore the va_list before we use it again + va_copy(backup_ap, ap); + result = vsnprintf(buf, buf_remain, format, backup_ap); + va_end(backup_ap); + + if (result >= 0 && result < buf_remain) { + // It fit and vsnprintf copied in directly. Resize down one to + // remove the trailing \0. + dst->resize(target_size); + } else { + // Didn't fit. Leave the original string unchanged. + dst->resize(initial_size); + } +} + +std::string StringPrintf(const char* format, ...) { + va_list ap; + va_start(ap, format); + std::string result; + StringAppendV(&result, format, ap); + va_end(ap); + return result; +} + +void StringAppendF(std::string* dst, const char* format, ...) { + va_list ap; + va_start(ap, format); + StringAppendV(dst, format, ap); + va_end(ap); +} + +} // namespace util +} // namespace firestore +} // namespace firebase diff --git a/Firestore/core/src/firebase/firestore/util/string_printf.h b/Firestore/core/src/firebase/firestore/util/string_printf.h new file mode 100644 index 0000000..9e2b9c0 --- /dev/null +++ b/Firestore/core/src/firebase/firestore/util/string_printf.h @@ -0,0 +1,48 @@ +/* + * Copyright 2018 Google + * + * 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 FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_PRINTF_H_ +#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_PRINTF_H_ + +#include <stdarg.h> + +#include <string> + +#include <absl/base/attributes.h> + +namespace firebase { +namespace firestore { +namespace util { + +/** Return a C++ string. */ +std::string StringPrintf(const char* format, ...) + ABSL_PRINTF_ATTRIBUTE(1, 2); + +/** Append result to a supplied string. */ +void StringAppendF(std::string* dst, const char* format, ...) + ABSL_PRINTF_ATTRIBUTE(2, 3); + +/** + * Lower-level routine that takes a va_list and appends to a specified + * string. All other routines are just convenience wrappers around it. + */ +void StringAppendV(std::string* dst, const char* format, va_list ap); + +} // namespace util +} // namespace firestore +} // namespace firebase + +#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_FORMAT_H_ diff --git a/Firestore/core/test/firebase/firestore/util/CMakeLists.txt b/Firestore/core/test/firebase/firestore/util/CMakeLists.txt index 42c4dcc..5e10715 100644 --- a/Firestore/core/test/firebase/firestore/util/CMakeLists.txt +++ b/Firestore/core/test/firebase/firestore/util/CMakeLists.txt @@ -16,6 +16,7 @@ cc_test( firebase_firestore_util_test autoid_test.cc secure_random_test.cc + string_printf_test.cc ) target_link_libraries( firebase_firestore_util_test @@ -24,20 +25,20 @@ target_link_libraries( if(APPLE) cc_test( - firebase_firestore_util_log_apple_test + firebase_firestore_util_apple_test log_test.cc ) target_link_libraries( - firebase_firestore_util_log_apple_test - firebase_firestore_util_log_apple + firebase_firestore_util_apple_test + firebase_firestore_util_apple ) endif(APPLE) cc_test( - firebase_firestore_util_log_stdio_test + firebase_firestore_util_stdio_test log_test.cc ) target_link_libraries( - firebase_firestore_util_log_stdio_test - firebase_firestore_util_log_stdio + firebase_firestore_util_stdio_test + firebase_firestore_util_stdio ) diff --git a/Firestore/core/test/firebase/firestore/util/string_printf_test.cc b/Firestore/core/test/firebase/firestore/util/string_printf_test.cc new file mode 100644 index 0000000..76f7cde --- /dev/null +++ b/Firestore/core/test/firebase/firestore/util/string_printf_test.cc @@ -0,0 +1,78 @@ +/* + * Copyright 2017 Google + * + * 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 "Firestore/core/src/firebase/firestore/util/string_printf.h" + +#include <gtest/gtest.h> + +namespace firebase { +namespace firestore { +namespace util { + +TEST(StringPrintf, Empty) { + EXPECT_EQ("", StringPrintf("")); + EXPECT_EQ("", StringPrintf("%s", std::string().c_str())); + EXPECT_EQ("", StringPrintf("%s", "")); +} + +TEST(StringAppendFTest, Empty) { + std::string value("Hello"); + const char* empty = ""; + StringAppendF(&value, "%s", empty); + EXPECT_EQ("Hello", value); +} + +TEST(StringAppendFTest, EmptyString) { + std::string value("Hello"); + StringAppendF(&value, "%s", ""); + EXPECT_EQ("Hello", value); +} + +TEST(StringAppendFTest, String) { + std::string value("Hello"); + StringAppendF(&value, " %s", "World"); + EXPECT_EQ("Hello World", value); +} + +TEST(StringAppendFTest, Int) { + std::string value("Hello"); + StringAppendF(&value, " %d", 123); + EXPECT_EQ("Hello 123", value); +} + +TEST(StringPrintf, DontOverwriteErrno) { + // Check that errno isn't overwritten unless we're printing + // something significantly larger than what people are normally + // printing in their badly written PLOG() statements. + errno = ECHILD; + std::string value = StringPrintf("Hello, %s!", "World"); + EXPECT_EQ(ECHILD, errno); +} + +TEST(StringPrintf, LargeBuf) { + // Check that the large buffer is handled correctly. + int n = 2048; + char* buf = new char[n + 1]; + memset(buf, ' ', n); + buf[n] = 0; + std::string value = StringPrintf("%s", buf); + EXPECT_EQ(buf, value); + delete[] buf; +} + +} // namespace util +} // namespace firestore +} // namespace firebase |