Add misc android/base/ helper classes.

This patch adds a few new helper classes under android/base/ that
will be used by future patches.

- Add a 'clear' method to String class.

- Add StringFormat() function to generated String instances
  from formatted string input, and StringAppendFormat() to
  append some to an existing instance.

- Add ScopedFd to implement a scoped file descriptor wrapper.

- Add ScopedHandle to implement a scoped Win32 HANDLE wrapper.

Change-Id: I0ae2a1de1123586b23e4faca8f394c6b4dff622e
diff --git a/Makefile.common b/Makefile.common
index 3d6ea6f..8215a52 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -123,6 +123,7 @@
 	android/base/files/PathUtils.cpp \
 	android/base/Log.cpp \
 	android/base/String.cpp \
+	android/base/StringFormat.cpp \
 	android/base/StringView.cpp \
 	android/filesystems/ext4_utils.cpp \
 	android/utils/assert.c \
diff --git a/Makefile.tests b/Makefile.tests
index 2c4b28c..68933b6 100644
--- a/Makefile.tests
+++ b/Makefile.tests
@@ -11,14 +11,22 @@
   android/base/containers/StringVector_unittest.cpp \
   android/base/EintrWrapper_unittest.cpp \
   android/base/files/PathUtils_unittest.cpp \
+  android/base/files/ScopedFd_unittest.cpp \
   android/base/files/ScopedStdioFile_unittest.cpp \
   android/base/Log_unittest.cpp \
   android/base/memory/MallocUsableSize_unittest.cpp \
   android/base/memory/ScopedPtr_unittest.cpp \
   android/base/String_unittest.cpp \
+  android/base/StringFormat_unittest.cpp \
   android/base/StringView_unittest.cpp \
   android/filesystems/ext4_utils_unittest.cpp \
 
+ifeq (windows,$(HOST_OS))
+EMULATOR_UNITTESTS_SOURCES += \
+  android/base/files/ScopedHandle_unittest.cpp \
+
+endif
+
 $(call start-emulator-program, emulator_unittests)
 LOCAL_C_INCLUDES += $(EMULATOR_GTEST_INCLUDES)
 LOCAL_LDLIBS += $(EMULATOR_GTEST_LDLIBS)
diff --git a/android/base/String.h b/android/base/String.h
index fc7e41f..4e574cb 100644
--- a/android/base/String.h
+++ b/android/base/String.h
@@ -62,9 +62,13 @@
 
     // Return current capacity.
     size_t capacity() const {
-        return (mStr == mStorage) ? kMinCapacity : mCapacity;
+        return (mStr == mStorage) ?
+                static_cast<size_t>(kMinCapacity) : mCapacity;
     }
 
+    // Clear the content of a given instance.
+    void clear() { resize(0); }
+
     // Array indexing operators.
     char& operator[](size_t index) { return mStr[index]; }
     const char& operator[](size_t index) const { return mStr[index]; }
diff --git a/android/base/StringFormat.cpp b/android/base/StringFormat.cpp
new file mode 100644
index 0000000..a3ba105
--- /dev/null
+++ b/android/base/StringFormat.cpp
@@ -0,0 +1,82 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#include "android/base/StringFormat.h"
+
+#include <stdio.h>
+
+namespace android {
+namespace base {
+
+String StringFormat(const char* format, ...) {
+    va_list args;
+    va_start(args, format);
+    String result = StringFormatWithArgs(format, args);
+    va_end(args);
+    return result;
+}
+
+String StringFormatWithArgs(const char* format, va_list args) {
+    String result;
+    StringAppendFormatWithArgs(&result, format, args);
+    return result;
+}
+
+void StringAppendFormat(String* string, const char* format, ...) {
+    va_list args;
+    va_start(args, format);
+    StringAppendFormatWithArgs(string, format, args);
+    va_end(args);
+}
+
+void StringAppendFormatWithArgs(String* string,
+                                const char* format,
+                                va_list args) {
+    size_t cur_size = string->size();
+    size_t extra = 0;
+    for (;;) {
+        va_list args2;
+        va_copy(args2, args);
+        int ret = vsnprintf(&(*string)[cur_size], extra, format, args2);
+        va_end(args2);
+
+        if (ret == 0) {
+            // Nothing to do here.
+            break;
+        }
+
+        if (ret > 0) {
+            size_t ret_sz = static_cast<size_t>(ret);
+            if (extra == 0) {
+                // First pass, resize the string and try again.
+                extra = ret_sz + 1;
+                string->resize(cur_size + extra);
+                continue;
+            }
+            if (ret_sz < extra) {
+                // Second pass or later, success!
+                string->resize(cur_size + ret_sz);
+                return;
+            }
+        }
+
+        // NOTE: The MSVCRT.DLL implementation of snprintf() is broken and
+        // will return -1 in case of truncation. This code path is taken
+        // when this happens, or when |ret_sz| is equal or larger than
+        // |extra|. Grow the buffer to allow for more room, then try again.
+        extra += (extra >> 1) + 32;
+        string->resize(cur_size + extra);
+    }
+}
+
+
+}  // namespace base
+}  // namespace android
diff --git a/android/base/StringFormat.h b/android/base/StringFormat.h
new file mode 100644
index 0000000..c8e155d
--- /dev/null
+++ b/android/base/StringFormat.h
@@ -0,0 +1,45 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#ifndef ANDROID_BASE_STRING_FORMAT_H
+#define ANDROID_BASE_STRING_FORMAT_H
+
+#include "android/base/String.h"
+
+#include <stdarg.h>
+
+namespace android {
+namespace base {
+
+// Create a new String instance that contains the printf-style formatted
+// output from |format| and potentially any following arguments.
+String StringFormat(const char* format, ...);
+
+// A variant of StringFormat() which uses a va_list to list formatting
+// parameters instead.
+String StringFormatWithArgs(const char* format, va_list args);
+
+// Appends a formatted string at the end of an existing string.
+// |string| is the target String instance, |format| the format string,
+// followed by any formatting parameters. This is more efficient than
+// appending the result of StringFormat(format,...) to |*string| directly.
+void StringAppendFormat(String* string, const char* format, ...);
+
+// A variant of StringAppendFormat() that takes a va_list to list
+// formatting parameters.
+void StringAppendFormatWithArgs(String* string,
+                                const char* format,
+                                va_list args);
+
+}  // namespace base
+}  // namespace android
+
+#endif  // ANDROID_BASE_STRING_FORMAT_H
diff --git a/android/base/StringFormat_unittest.cpp b/android/base/StringFormat_unittest.cpp
new file mode 100644
index 0000000..7db8529
--- /dev/null
+++ b/android/base/StringFormat_unittest.cpp
@@ -0,0 +1,87 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#include "android/base/StringFormat.h"
+
+#include <gtest/gtest.h>
+
+#include "android/base/String.h"
+
+namespace android {
+namespace base {
+
+TEST(StringFormat, EmptyString) {
+    String s = StringFormat("");
+    EXPECT_TRUE(s.empty());
+    EXPECT_STREQ("", s.c_str());
+}
+
+TEST(StringFormat, SimpleString) {
+    String s = StringFormat("foobar");
+    EXPECT_STREQ("foobar", s.c_str());
+}
+
+TEST(StringFormat, SimpleDecimal) {
+    String s = StringFormat("Pi is about %d.%d\n", 3, 1415);
+    EXPECT_STREQ("Pi is about 3.1415\n", s.c_str());
+}
+
+TEST(StringFormat, VeryLongString) {
+    static const char kPiece[] = "A hospital bed is a parked taxi with the meter running - Groucho Marx. ";
+    const size_t kPieceLen = sizeof(kPiece) - 1U;
+    String s = StringFormat("%s%s%s%s%s%s%s",
+                            kPiece,
+                            kPiece,
+                            kPiece,
+                            kPiece,
+                            kPiece,
+                            kPiece,
+                            kPiece
+                           );
+    EXPECT_EQ(7U * kPieceLen, s.size());
+    for (size_t n = 0; n < 7U; ++n) {
+        String s2 = String(s.c_str() + n * kPieceLen, kPieceLen);
+        EXPECT_STREQ(kPiece, s2.c_str()) << "Index #" << n;
+    }
+}
+
+TEST(StringAppendFormat, EmptyString) {
+    String s = "foo";
+    StringAppendFormat(&s, "");
+    EXPECT_EQ(3U, s.size());
+    EXPECT_STREQ("foo", s.c_str());
+}
+
+TEST(StringAppendFormat, SimpleString) {
+    String s = "foo";
+    StringAppendFormat(&s, "bar");
+    EXPECT_EQ(6U, s.size());
+    EXPECT_STREQ("foobar", s.c_str());
+}
+
+TEST(StringAppendFormat, VeryLongString) {
+    static const char kPiece[] = "A hospital bed is a parked taxi with the meter running - Groucho Marx. ";
+    const size_t kPieceLen = sizeof(kPiece) - 1U;
+    const size_t kCount = 12;
+    String s;
+    for (size_t n = 0; n < kCount; ++n) {
+        StringAppendFormat(&s, "%s", kPiece);
+    }
+
+    EXPECT_EQ(kCount * kPieceLen, s.size());
+    for (size_t n = 0; n < kCount; ++n) {
+        String s2 = String(s.c_str() + n * kPieceLen, kPieceLen);
+        EXPECT_STREQ(kPiece, s2.c_str()) << "Index #" << n;
+    }
+}
+
+}  // namespace base
+}  // namespace android
diff --git a/android/base/String_unittest.cpp b/android/base/String_unittest.cpp
index e582124..69719fb 100644
--- a/android/base/String_unittest.cpp
+++ b/android/base/String_unittest.cpp
@@ -91,6 +91,14 @@
     EXPECT_EQ(kCount, s.size());
 }
 
+TEST(String, clear) {
+    String s("foo bar");
+    EXPECT_FALSE(s.empty());
+    s.clear();
+    EXPECT_TRUE(s.empty());
+    EXPECT_EQ(0U, s.size());
+}
+
 TEST(String, IndexedAccess) {
     String s("foobar");
     EXPECT_EQ('f', s[0]);
diff --git a/android/base/files/ScopedFd.h b/android/base/files/ScopedFd.h
new file mode 100644
index 0000000..6aa5157
--- /dev/null
+++ b/android/base/files/ScopedFd.h
@@ -0,0 +1,76 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#ifndef ANDROID_BASE_SCOPED_FD_H
+#define ANDROID_BASE_SCOPED_FD_H
+
+#include "android/base/Compiler.h"
+
+#include <errno.h>
+#include <unistd.h>
+
+namespace android {
+namespace base {
+
+// Helper class to hold an integer file descriptor, and have the 'close'
+// function called automatically on scope exit, unless the 'release'
+// method was called previously.
+class ScopedFd {
+public:
+    // Default constructor will hold an invalid descriptor.
+    ScopedFd() : fd_(-1) {}
+
+    // Constructor takes ownership of |fd|.
+    explicit ScopedFd(int fd) : fd_(fd) {}
+
+    // Destructor calls close().
+    ~ScopedFd() { close(); }
+
+    // Return the file descriptor value, does _not_ transfer ownership.
+    int get() const { return fd_; }
+
+    // Return the file descriptor value, transfers ownership to the caller.
+    int release() {
+        int fd = fd_;
+        fd_ = -1;
+        return fd;
+    }
+
+    // Return true iff the file descriptor is valid.
+    bool valid() const { return fd_ >= 0; }
+
+    // Close the file descriptor (and make the wrapped value invalid).
+    void close() {
+        if (fd_ != -1) {
+            int save_errno = errno;
+            ::close(fd_);
+            fd_ = -1;
+            errno = save_errno;
+        }
+    }
+
+    // Swap two ScopedFd instances.
+    void swap(ScopedFd* other) {
+        int fd = fd_;
+        fd_ = other->fd_;
+        other->fd_ = fd;
+    }
+
+private:
+    DISALLOW_COPY_AND_ASSIGN(ScopedFd);
+
+    int fd_;
+};
+
+}  // namespace base
+}  // namespace android
+
+#endif  // ANDROID_BASE_SCOPED_FD_H
diff --git a/android/base/files/ScopedFd_unittest.cpp b/android/base/files/ScopedFd_unittest.cpp
new file mode 100644
index 0000000..7ac1d69
--- /dev/null
+++ b/android/base/files/ScopedFd_unittest.cpp
@@ -0,0 +1,76 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#include "android/base/files/ScopedFd.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace base {
+
+namespace {
+
+// The path of a file that can always be opened for reading on any platform.
+#ifdef _WIN32
+static const char kNullFile[] = "NUL";
+#else
+static const char kNullFile[] = "/dev/null";
+#endif
+
+int OpenNull() {
+    return ::open(kNullFile, O_RDONLY);
+}
+
+}  // namespace
+
+TEST(ScopedFd, DefaultConstructor) {
+    ScopedFd f;
+    EXPECT_FALSE(f.valid());
+    EXPECT_EQ(-1, f.get());
+}
+
+TEST(ScopedFd, Constructor) {
+    ScopedFd f(OpenNull());
+    EXPECT_TRUE(f.valid());
+}
+
+TEST(ScopedFd, Release) {
+    ScopedFd f(OpenNull());
+    EXPECT_TRUE(f.valid());
+    int fd = f.release();
+    EXPECT_FALSE(f.valid());
+    EXPECT_NE(-1, fd);
+    ::close(fd);
+}
+
+TEST(ScopedFd, Close) {
+    ScopedFd f(OpenNull());
+    EXPECT_TRUE(f.valid());
+    f.close();
+    EXPECT_FALSE(f.valid());
+}
+
+TEST(ScopedFd, Swap) {
+    ScopedFd f1;
+    ScopedFd f2(OpenNull());
+    EXPECT_FALSE(f1.valid());
+    EXPECT_TRUE(f2.valid());
+    f1.swap(&f2);
+    EXPECT_FALSE(f2.valid());
+    EXPECT_TRUE(f1.valid());
+}
+
+
+}  // namespace base
+}  // namespace android
diff --git a/android/base/files/ScopedHandle.h b/android/base/files/ScopedHandle.h
new file mode 100644
index 0000000..45a97eb
--- /dev/null
+++ b/android/base/files/ScopedHandle.h
@@ -0,0 +1,78 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#ifndef ANDROID_BASE_FILES_SCOPED_HANDLE_H
+#define ANDROID_BASE_FILES_SCOPED_HANDLE_H
+
+#if !defined(_WIN32) && !defined(_WIN64)
+#error "Only compile this file when targetting Windows!"
+#endif
+
+#include "android/base/Compiler.h"
+
+#define WIN32_LEAN_AND_MEAN 1
+#include <windows.h>
+
+namespace android {
+namespace base {
+
+// Helper class used to wrap a Win32 HANDLE that will be closed when
+// the instance is destroyed, unless the release() method was called
+// before that.
+class ScopedHandle {
+public:
+    // Default destructor is used to wrap an invalid handle value.
+    ScopedHandle() : handle_(INVALID_HANDLE_VALUE) {}
+
+    // Constructor takes ownership of |handle|.
+    explicit ScopedHandle(HANDLE handle) : handle_(handle) {}
+
+    // Destructor calls close() method.
+    ~ScopedHandle() { close(); }
+
+    // Returns true iff the wrapped HANDLE value is valid.
+    bool valid() const { return handle_ != INVALID_HANDLE_VALUE; }
+
+    // Return current HANDLE value. Does _not_ transfer ownership.
+    HANDLE get() const { return handle_; }
+
+    // Return current HANDLE value, transferring ownership to the caller.
+    HANDLE release() {
+        HANDLE h = handle_;
+        handle_ = INVALID_HANDLE_VALUE;
+        return h;
+    }
+
+    // Close handle if it is not invalid.
+    void close() {
+        if (handle_ != INVALID_HANDLE_VALUE) {
+            ::CloseHandle(handle_);
+            handle_ = INVALID_HANDLE_VALUE;
+        }
+    }
+
+    // Swap the content of two ScopedHandle instances.
+    void swap(ScopedHandle* other) {
+        HANDLE handle = handle_;
+        handle_ = other->handle_;
+        other->handle_ = handle;
+    }
+
+private:
+    DISALLOW_COPY_AND_ASSIGN(ScopedHandle);
+
+    HANDLE handle_;
+};
+
+}  // namespace base
+}  // namespace android
+
+#endif  // ANDROID_BASE_FILES_SCOPED_HANDLE_H
diff --git a/android/base/files/ScopedHandle_unittest.cpp b/android/base/files/ScopedHandle_unittest.cpp
new file mode 100644
index 0000000..93baf9d
--- /dev/null
+++ b/android/base/files/ScopedHandle_unittest.cpp
@@ -0,0 +1,74 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#include "android/base/files/ScopedHandle.h"
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace base {
+
+namespace {
+
+// The path of a file that can always be opened for reading on any platform.
+static const char kNullFile[] = "NUL";
+
+HANDLE OpenNull() {
+    return ::CreateFile(kNullFile,
+                        GENERIC_READ,
+                        FILE_SHARE_READ|FILE_SHARE_WRITE,
+                        NULL,
+                        OPEN_EXISTING,
+                        FILE_ATTRIBUTE_NORMAL,
+                        NULL);
+}
+
+}  // namespace
+
+TEST(ScopedHandle, DefaultConstructor) {
+    ScopedHandle h;
+    EXPECT_FALSE(h.valid());
+    EXPECT_EQ(INVALID_HANDLE_VALUE, h.get());
+}
+
+TEST(ScopedHandle, Constructor) {
+    ScopedHandle h(OpenNull());
+    EXPECT_TRUE(h.valid());
+}
+
+TEST(ScopedHandle, Release) {
+    ScopedHandle h(OpenNull());
+    EXPECT_TRUE(h.valid());
+    HANDLE handle = h.release();
+    EXPECT_FALSE(h.valid());
+    EXPECT_NE(INVALID_HANDLE_VALUE, handle);
+    ::CloseHandle(handle);
+}
+
+TEST(ScopedHandle, Close) {
+    ScopedHandle h(OpenNull());
+    EXPECT_TRUE(h.valid());
+    h.close();
+    EXPECT_FALSE(h.valid());
+}
+
+TEST(ScopedHandle, Swap) {
+    ScopedHandle h1;
+    ScopedHandle h2(OpenNull());
+    EXPECT_FALSE(h1.valid());
+    EXPECT_TRUE(h2.valid());
+    h1.swap(&h2);
+    EXPECT_FALSE(h2.valid());
+    EXPECT_TRUE(h1.valid());
+}
+
+}  // namespace base
+}  // namespace android