// Copyright (c) 2010 Marshall A. Greenblatt. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//    * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//    * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//    * Neither the name of Google Inc. nor the name Chromium Embedded
// Framework nor the names of its contributors may be used to endorse
// or promote products derived from this software without specific prior
// written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef CEF_INCLUDE_INTERNAL_CEF_STRING_WRAPPERS_H_
#define CEF_INCLUDE_INTERNAL_CEF_STRING_WRAPPERS_H_
#pragma once

#include <cstring>
#include <ostream>
#include <string>
#include <string_view>

#include "include/internal/cef_string_types.h"

#if defined(USING_CHROMIUM_INCLUDES)
#include "base/files/file_path.h"
#endif

///
/// Traits implementation for wide character strings.
///
struct CefStringTraitsWide {
  typedef wchar_t char_type;
  typedef cef_string_wide_t struct_type;
  typedef cef_string_userfree_wide_t userfree_struct_type;

  static inline void clear(struct_type* s) { cef_string_wide_clear(s); }
  static inline int set(const char_type* src,
                        size_t src_size,
                        struct_type* output,
                        int copy) {
    return cef_string_wide_set(src, src_size, output, copy);
  }
  static inline int compare(const struct_type* s1, const struct_type* s2) {
    return cef_string_wide_cmp(s1, s2);
  }
  static inline userfree_struct_type userfree_alloc() {
    return cef_string_userfree_wide_alloc();
  }
  static inline void userfree_free(userfree_struct_type ufs) {
    return cef_string_userfree_wide_free(ufs);
  }

  // Conversion methods.
  static inline bool from_ascii(const char* str, size_t len, struct_type* s) {
    return cef_string_ascii_to_wide(str, len, s) ? true : false;
  }
  static inline std::string to_string(const struct_type* s) {
    cef_string_utf8_t cstr;
    memset(&cstr, 0, sizeof(cstr));
    cef_string_wide_to_utf8(s->str, s->length, &cstr);
    std::string str;
    if (cstr.length > 0) {
      str = std::string(cstr.str, cstr.length);
    }
    cef_string_utf8_clear(&cstr);
    return str;
  }
  static inline bool from_string(const std::string::value_type* data,
                                 size_t length,
                                 struct_type* s) {
    return cef_string_utf8_to_wide(data, length, s) ? true : false;
  }
  static inline bool from_string(const std::string& str, struct_type* s) {
    return from_string(str.data(), str.length(), s);
  }
  static inline std::wstring to_wstring(const struct_type* s) {
    return std::wstring(s->str, s->length);
  }
  static inline bool from_wstring(const std::wstring::value_type* data,
                                  size_t length,
                                  struct_type* s) {
    return cef_string_wide_set(data, length, s, true) ? true : false;
  }
  static inline bool from_wstring(const std::wstring& str, struct_type* s) {
    return from_wstring(str.data(), str.length(), s);
  }
#if defined(WCHAR_T_IS_32_BIT)
  static inline std::u16string to_string16(const struct_type* s) {
    cef_string_utf16_t cstr;
    memset(&cstr, 0, sizeof(cstr));
    cef_string_wide_to_utf16(s->str, s->length, &cstr);
    std::u16string str;
    if (cstr.length > 0) {
      str = std::u16string(
          reinterpret_cast<std::u16string::value_type*>(cstr.str), cstr.length);
    }
    cef_string_utf16_clear(&cstr);
    return str;
  }
  static inline bool from_string16(const std::u16string::value_type* data,
                                   size_t length,
                                   struct_type* s) {
    return cef_string_utf16_to_wide(reinterpret_cast<const char16_t*>(data),
                                    length, s)
               ? true
               : false;
  }
#elif defined(WCHAR_T_IS_16_BIT)
  static inline std::u16string to_string16(const struct_type* s) {
    return std::u16string(
        reinterpret_cast<const std::u16string::value_type*>(s->str), s->length);
  }
  static inline bool from_string16(const std::u16string::value_type* data,
                                   size_t length,
                                   struct_type* s) {
    return cef_string_wide_set(reinterpret_cast<const wchar_t*>(data), length,
                               s, true)
               ? true
               : false;
  }
#endif  // WCHAR_T_IS_16_BIT
  static inline bool from_string16(const std::u16string& str, struct_type* s) {
    return from_string16(str.data(), str.length(), s);
  }
};

///
/// Traits implementation for utf8 character strings.
///
struct CefStringTraitsUTF8 {
  typedef char char_type;
  typedef cef_string_utf8_t struct_type;
  typedef cef_string_userfree_utf8_t userfree_struct_type;

  static inline void clear(struct_type* s) { cef_string_utf8_clear(s); }
  static inline int set(const char_type* src,
                        size_t src_size,
                        struct_type* output,
                        int copy) {
    return cef_string_utf8_set(src, src_size, output, copy);
  }
  static inline int compare(const struct_type* s1, const struct_type* s2) {
    return cef_string_utf8_cmp(s1, s2);
  }
  static inline userfree_struct_type userfree_alloc() {
    return cef_string_userfree_utf8_alloc();
  }
  static inline void userfree_free(userfree_struct_type ufs) {
    return cef_string_userfree_utf8_free(ufs);
  }

  // Conversion methods.
  static inline bool from_ascii(const char* str, size_t len, struct_type* s) {
    return cef_string_utf8_copy(str, len, s) ? true : false;
  }
  static inline std::string to_string(const struct_type* s) {
    return std::string(s->str, s->length);
  }
  static inline bool from_string(const std::string::value_type* data,
                                 size_t length,
                                 struct_type* s) {
    return cef_string_utf8_copy(data, length, s) ? true : false;
  }
  static inline bool from_string(const std::string& str, struct_type* s) {
    return from_string(str.c_str(), str.length(), s);
  }
  static inline std::wstring to_wstring(const struct_type* s) {
    cef_string_wide_t cstr;
    memset(&cstr, 0, sizeof(cstr));
    cef_string_utf8_to_wide(s->str, s->length, &cstr);
    std::wstring str;
    if (cstr.length > 0) {
      str = std::wstring(cstr.str, cstr.length);
    }
    cef_string_wide_clear(&cstr);
    return str;
  }
  static inline bool from_wstring(const std::wstring::value_type* data,
                                  size_t length,
                                  struct_type* s) {
    return cef_string_wide_to_utf8(data, length, s) ? true : false;
  }
  static inline bool from_wstring(const std::wstring& str, struct_type* s) {
    return from_wstring(str.data(), str.length(), s);
  }
  static inline std::u16string to_string16(const struct_type* s) {
    cef_string_utf16_t cstr;
    memset(&cstr, 0, sizeof(cstr));
    cef_string_utf8_to_utf16(s->str, s->length, &cstr);
    std::u16string str;
    if (cstr.length > 0) {
      str = std::u16string(
          reinterpret_cast<std::u16string::value_type*>(cstr.str), cstr.length);
    }
    cef_string_utf16_clear(&cstr);
    return str;
  }
  static inline bool from_string16(const std::u16string::value_type* data,
                                   size_t length,
                                   struct_type* s) {
    return cef_string_utf16_to_utf8(reinterpret_cast<const char16_t*>(data),
                                    length, s)
               ? true
               : false;
  }
  static inline bool from_string16(const std::u16string& str, struct_type* s) {
    return from_string16(str.data(), str.length(), s);
  }
};

///
/// Traits implementation for utf16 character strings.
///
struct CefStringTraitsUTF16 {
  typedef char16_t char_type;
  typedef cef_string_utf16_t struct_type;
  typedef cef_string_userfree_utf16_t userfree_struct_type;

  static inline void clear(struct_type* s) { cef_string_utf16_clear(s); }
  static inline int set(const char_type* src,
                        size_t src_size,
                        struct_type* output,
                        int copy) {
    return cef_string_utf16_set(src, src_size, output, copy);
  }
  static inline int compare(const struct_type* s1, const struct_type* s2) {
    return cef_string_utf16_cmp(s1, s2);
  }
  static inline userfree_struct_type userfree_alloc() {
    return cef_string_userfree_utf16_alloc();
  }
  static inline void userfree_free(userfree_struct_type ufs) {
    return cef_string_userfree_utf16_free(ufs);
  }

  // Conversion methods.
  static inline bool from_ascii(const char* str, size_t len, struct_type* s) {
    return cef_string_ascii_to_utf16(str, len, s) ? true : false;
  }
  static inline std::string to_string(const struct_type* s) {
    cef_string_utf8_t cstr;
    memset(&cstr, 0, sizeof(cstr));
    cef_string_utf16_to_utf8(s->str, s->length, &cstr);
    std::string str;
    if (cstr.length > 0) {
      str = std::string(cstr.str, cstr.length);
    }
    cef_string_utf8_clear(&cstr);
    return str;
  }
  static inline bool from_string(const std::string::value_type* data,
                                 size_t length,
                                 struct_type* s) {
    return cef_string_utf8_to_utf16(data, length, s) ? true : false;
  }
  static inline bool from_string(const std::string& str, struct_type* s) {
    return from_string(str.data(), str.length(), s);
  }
#if defined(WCHAR_T_IS_32_BIT)
  static inline std::wstring to_wstring(const struct_type* s) {
    cef_string_wide_t cstr;
    memset(&cstr, 0, sizeof(cstr));
    cef_string_utf16_to_wide(s->str, s->length, &cstr);
    std::wstring str;
    if (cstr.length > 0) {
      str = std::wstring(cstr.str, cstr.length);
    }
    cef_string_wide_clear(&cstr);
    return str;
  }
  static inline bool from_wstring(const std::wstring::value_type* data,
                                  size_t length,
                                  struct_type* s) {
    return cef_string_wide_to_utf16(data, length, s) ? true : false;
  }
#elif defined(WCHAR_T_IS_16_BIT)
  static inline std::wstring to_wstring(const struct_type* s) {
    return std::wstring(reinterpret_cast<wchar_t*>(s->str), s->length);
  }
  static inline bool from_wstring(const std::wstring::value_type* data,
                                  size_t length,
                                  struct_type* s) {
    return cef_string_utf16_set(reinterpret_cast<const char16_t*>(data), length,
                                s, true)
               ? true
               : false;
  }
#endif  // WCHAR_T_IS_16_BIT
  static inline bool from_wstring(const std::wstring& str, struct_type* s) {
    return from_wstring(str.data(), str.length(), s);
  }
  static inline std::u16string to_string16(const struct_type* s) {
    return std::u16string(
        reinterpret_cast<const std::u16string::value_type*>(s->str), s->length);
  }
  static inline bool from_string16(const std::u16string::value_type* data,
                                   size_t length,
                                   struct_type* s) {
    return cef_string_utf16_set(reinterpret_cast<const char16_t*>(data), length,
                                s, true)
               ? true
               : false;
  }
  static inline bool from_string16(const std::u16string& str, struct_type* s) {
    return from_string16(str.data(), str.length(), s);
  }
};

///
/// CEF string classes can convert between all supported string types. For
/// example, the CefStringWide class uses wchar_t as the underlying character
/// type and provides two approaches for converting data to/from a UTF8 string
/// (std::string).
///
/// 1. Implicit conversion using the assignment operator overload.
/// <pre>
///   CefStringWide aCefString;
///   std::string aUTF8String;
///   aCefString = aUTF8String; // Assign std::string to CefStringWide
///   aUTF8String = aCefString; // Assign CefStringWide to std::string
/// </pre>
///
/// 2. Explicit conversion using the FromString/ToString methods.
/// <pre>
///   CefStringWide aCefString;
///   std::string aUTF8String;
///   aCefString.FromString(aUTF8String); // Assign std::string to CefStringWide
///   aUTF8String = aCefString.ToString(); // Assign CefStringWide to
///   std::string
/// </pre>
///
/// Conversion will only occur if the assigned value is a different string type.
/// Assigning a std::string to a CefStringUTF8, for example, will copy the data
/// without performing a conversion.
///
/// CEF string classes are safe for reading from multiple threads but not for
/// modification. It is the user's responsibility to provide synchronization if
/// modifying CEF strings from multiple threads.
///
template <class traits>
class CefStringBase final {
 public:
  typedef typename traits::char_type char_type;
  typedef typename traits::struct_type struct_type;
  typedef typename traits::userfree_struct_type userfree_struct_type;

  ///
  /// Default constructor.
  ///
  CefStringBase() : string_(NULL), owner_(false) {}

  ///
  /// Create a new string from an existing string. Data will always be copied.
  ///
  CefStringBase(const CefStringBase& str) : string_(NULL), owner_(false) {
    FromString(str.c_str(), str.length(), true);
  }

  ///
  /// Create a new string from an existing std::string. Data will be always
  /// copied. Translation will occur if necessary based on the underlying string
  /// type.
  ///
  CefStringBase(const std::string& src) : string_(NULL), owner_(false) {
    FromString(src);
  }
  CefStringBase(const char* src, size_t length = 0)
      : string_(NULL), owner_(false) {
    if (src) {
      FromString(src, length);
    }
  }

  ///
  /// Create a new string from an existing std::wstring. Data will be always
  /// copied. Translation will occur if necessary based on the underlying string
  /// type.
  ///
  CefStringBase(const std::wstring& src) : string_(NULL), owner_(false) {
    FromWString(src);
  }
  CefStringBase(const wchar_t* src, size_t length = 0)
      : string_(NULL), owner_(false) {
    if (src) {
      FromWString(src, length);
    }
  }

  ///
  /// Create a new string from an existing string16. Data will be always
  /// copied. Translation will occur if necessary based on the underlying string
  /// type.
  ///
  CefStringBase(const std::u16string& src) : string_(NULL), owner_(false) {
    FromString16(src);
  }
  CefStringBase(const std::u16string::value_type* src, size_t length = 0)
      : string_(NULL), owner_(false) {
    if (src) {
      FromString16(src, length);
    }
  }

  ///
  /// Create a new string from an existing character array. If |copy| is true
  /// this class will copy the data. Otherwise, this class will reference the
  /// existing data. Referenced data must exist for the lifetime of this class
  /// and will not be freed by this class.
  ///
  CefStringBase(const char_type* src, size_t src_len, bool copy)
      : string_(NULL), owner_(false) {
    if (src && src_len > 0) {
      FromString(src, src_len, copy);
    }
  }

  ///
  /// Create a new string referencing an existing string structure without
  /// taking ownership. Referenced structures must exist for the lifetime of
  /// this class and will not be freed by this class.
  ///
  CefStringBase(const struct_type* src) : string_(NULL), owner_(false) {
    if (!src) {
      return;
    }
    // Reference the existing structure without taking ownership.
    Attach(const_cast<struct_type*>(src), false);
  }

  ~CefStringBase() { ClearAndFree(); }

  /// The following methods are named for compatibility with the standard
  /// library string template types.

  ///
  /// Return a read-only pointer to the string data.
  ///
  const char_type* c_str() const { return (string_ ? string_->str : NULL); }

  ///
  /// Return the length of the string data.
  ///
  size_t length() const { return (string_ ? string_->length : 0); }

  ///
  /// Return the length of the string data.
  ///
  inline size_t size() const { return length(); }

  ///
  /// Returns true if the string is empty.
  ///
  bool empty() const { return (string_ == NULL || string_->length == 0); }

  ///
  /// Compare this string to the specified string.
  ///
  int compare(const CefStringBase& str) const {
    if (empty() && str.empty()) {
      return 0;
    }
    if (empty()) {
      return -1;
    }
    if (str.empty()) {
      return 1;
    }
    return traits::compare(string_, str.GetStruct());
  }

  ///
  /// Clear the string data.
  ///
  void clear() {
    if (string_) {
      traits::clear(string_);
    }
  }

  ///
  /// Swap this string's contents with the specified string.
  ///
  void swap(CefStringBase& str) {
    struct_type* tmp_string = string_;
    bool tmp_owner = owner_;
    string_ = str.string_;
    owner_ = str.owner_;
    str.string_ = tmp_string;
    str.owner_ = tmp_owner;
  }

  // The following methods are unique to CEF string template types.

  ///
  /// Returns true if this class owns the underlying string structure.
  ///
  bool IsOwner() const { return owner_; }

  ///
  /// Returns a read-only pointer to the underlying string structure. May return
  /// NULL if no structure is currently allocated.
  ///
  const struct_type* GetStruct() const { return string_; }

  ///
  /// Returns a writable pointer to the underlying string structure. Will never
  /// return NULL.
  ///
  struct_type* GetWritableStruct() {
    AllocIfNeeded();
    return string_;
  }

  ///
  /// Clear the state of this class. The underlying string structure and data
  /// will be freed if this class owns the structure.
  ///
  void ClearAndFree() {
    if (!string_) {
      return;
    }
    if (owner_) {
      clear();
      delete string_;
    }
    string_ = NULL;
    owner_ = false;
  }

  ///
  /// Attach to the specified string structure. If |owner| is true this class
  /// will take ownership of the structure.
  ///
  void Attach(struct_type* str, bool owner) {
    // Free the previous structure and data, if any.
    ClearAndFree();

    string_ = str;
    owner_ = owner;
  }

  ///
  /// Take ownership of the specified userfree structure's string data. The
  /// userfree structure itself will be freed. Only use this method with
  /// userfree structures.
  ///
  void AttachToUserFree(userfree_struct_type str) {
    // Free the previous structure and data, if any.
    ClearAndFree();

    if (!str) {
      return;
    }

    AllocIfNeeded();
    owner_ = true;
    memcpy(string_, str, sizeof(struct_type));

    /// Free the |str| structure but not the data.
    memset(str, 0, sizeof(struct_type));
    traits::userfree_free(str);
  }

  ///
  /// Detach from the underlying string structure. To avoid memory leaks only
  /// use this method if you already hold a pointer to the underlying string
  /// structure.
  ///
  void Detach() {
    string_ = NULL;
    owner_ = false;
  }

  ///
  /// Create a userfree structure and give it ownership of this class' string
  /// data. This class will be disassociated from the data. May return NULL if
  /// this string class currently contains no data.
  ///
  userfree_struct_type DetachToUserFree() {
    if (empty()) {
      return NULL;
    }

    userfree_struct_type str = traits::userfree_alloc();
    if (owner_) {
      // Transfer ownership of the data to |str|.
      memcpy(str, string_, sizeof(struct_type));
      // Free this class' structure but not the data.
      memset(string_, 0, sizeof(struct_type));
    } else {
      // Copy the data to |str|.
      traits::set(string_->str, string_->length, str, /*copy=*/true);
    }

    ClearAndFree();

    return str;
  }

  ///
  /// Set this string's data to the specified character array. If |copy| is true
  /// this class will copy the data. Otherwise, this class will reference the
  /// existing data. Referenced data must exist for the lifetime of this class
  /// and will not be freed by this class.
  ///
  bool FromString(const char_type* src, size_t src_len, bool copy) {
    if (src == NULL || src_len == 0) {
      clear();
      return true;
    }
    AllocIfNeeded();
    return traits::set(src, src_len, string_, copy) ? true : false;
  }

  ///
  /// Set this string's data from an existing ASCII string. Data will be always
  /// copied. Translation will occur if necessary based on the underlying string
  /// type.
  ///
  bool FromASCII(const char* str) {
    size_t len = str ? strlen(str) : 0;
    if (len == 0) {
      clear();
      return true;
    }
    AllocIfNeeded();
    return traits::from_ascii(str, len, string_);
  }

  ///
  /// Return this string's data as a std::string. Translation will occur if
  /// necessary based on the underlying string type.
  ///
  std::string ToString() const {
    if (empty()) {
      return std::string();
    }
    return traits::to_string(string_);
  }

  ///
  /// Set this string's data from an existing std::string. Data will be always
  /// copied. Translation will occur if necessary based on the underlying string
  /// type.
  ///
  bool FromString(const std::string& str) {
    if (str.empty()) {
      clear();
      return true;
    }
    AllocIfNeeded();
    return traits::from_string(str, string_);
  }

  ///
  /// Set this string's data from an existing std::string_view. Data will be
  /// always copied. Translation will occur if necessary based on the underlying
  /// string type.
  ///
  bool FromString(std::string_view str) {
    return FromString(str.data(), str.length());
  }

  ///
  /// Set this string's data from existing |data| and optional |length|. Data
  /// will be always copied. Translation will occur if necessary based on the
  /// underlying string type.
  ///
  bool FromString(const std::string::value_type* data, size_t length = 0) {
    if (data && length == 0) {
      length = std::char_traits<std::string::value_type>::length(data);
    }
    if (!data || length == 0) {
      clear();
      return true;
    }
    AllocIfNeeded();
    return traits::from_string(data, length, string_);
  }

  ///
  /// Return this string's data as a std::wstring. Translation will occur if
  /// necessary based on the underlying string type.
  ///
  std::wstring ToWString() const {
    if (empty()) {
      return std::wstring();
    }
    return traits::to_wstring(string_);
  }

  ///
  /// Set this string's data from an existing std::wstring. Data will be always
  /// copied. Translation will occur if necessary based on the underlying string
  /// type.
  ///
  bool FromWString(const std::wstring& str) {
    if (str.empty()) {
      clear();
      return true;
    }
    AllocIfNeeded();
    return traits::from_wstring(str, string_);
  }

  ///
  /// Set this string's data from existing |data| and optional |length|. Data
  /// will be always copied. Translation will occur if necessary based on the
  /// underlying string type.
  ///
  bool FromWString(const std::wstring::value_type* data, size_t length = 0) {
    if (data && length == 0) {
      length = std::char_traits<std::wstring::value_type>::length(data);
    }
    if (!data || length == 0) {
      clear();
      return true;
    }
    AllocIfNeeded();
    return traits::from_wstring(data, length, string_);
  }

  ///
  /// Return this string's data as a string16. Translation will occur if
  /// necessary based on the underlying string type.
  ///
  std::u16string ToString16() const {
    if (empty()) {
      return std::u16string();
    }
    return traits::to_string16(string_);
  }

  ///
  /// Set this string's data from an existing string16. Data will be always
  /// copied. Translation will occur if necessary based on the underlying string
  /// type.
  ///
  bool FromString16(const std::u16string& str) {
    if (str.empty()) {
      clear();
      return true;
    }
    AllocIfNeeded();
    return traits::from_string16(str, string_);
  }

  ///
  /// Set this string's data from existing |data| and optional |length|. Data
  /// will be always copied. Translation will occur if necessary based on the
  /// underlying string type.
  ///
  bool FromString16(const std::u16string::value_type* data, size_t length = 0) {
    if (data && length == 0) {
      length = std::char_traits<std::u16string::value_type>::length(data);
    }
    if (!data || length == 0) {
      clear();
      return true;
    }
    AllocIfNeeded();
    return traits::from_string16(data, length, string_);
  }

  ///
  /// Comparison operator overloads.
  ///
  bool operator<(const CefStringBase& str) const { return (compare(str) < 0); }
  bool operator<=(const CefStringBase& str) const {
    return (compare(str) <= 0);
  }
  bool operator>(const CefStringBase& str) const { return (compare(str) > 0); }
  bool operator>=(const CefStringBase& str) const {
    return (compare(str) >= 0);
  }
  bool operator==(const CefStringBase& str) const {
    return (compare(str) == 0);
  }
  bool operator!=(const CefStringBase& str) const {
    return (compare(str) != 0);
  }

  ///
  /// Assignment operator overloads.
  ///
  CefStringBase& operator=(const CefStringBase& str) {
    FromString(str.c_str(), str.length(), true);
    return *this;
  }
  operator std::string() const { return ToString(); }
  CefStringBase& operator=(const std::string& str) {
    FromString(str);
    return *this;
  }
  CefStringBase& operator=(const std::string::value_type* str) {
    FromString(str);
    return *this;
  }
  operator std::wstring() const { return ToWString(); }
  CefStringBase& operator=(const std::wstring& str) {
    FromWString(str);
    return *this;
  }
  CefStringBase& operator=(const std::wstring::value_type* str) {
    FromWString(str);
    return *this;
  }
  operator std::u16string() const { return ToString16(); }
  CefStringBase& operator=(const std::u16string& str) {
    FromString16(str);
    return *this;
  }
  CefStringBase& operator=(const std::u16string::value_type* str) {
    FromString16(str);
    return *this;
  }
#if defined(USING_CHROMIUM_INCLUDES)
  // The base::FilePath constructor is marked as explicit so provide the
  // conversion here for convenience.
  operator base::FilePath() const {
#if defined(OS_WIN)
    return base::FilePath(ToWString());
#else
    return base::FilePath(ToString());
#endif
  }
#endif  // USING_CHROMIUM_INCLUDES

 private:
  /// Allocate the string structure if it doesn't already exist.
  void AllocIfNeeded() {
    if (string_ == NULL) {
      string_ = new struct_type;
      memset(string_, 0, sizeof(struct_type));
      owner_ = true;
    }
  }

  struct_type* string_;
  bool owner_;
};

typedef CefStringBase<CefStringTraitsWide> CefStringWide;
typedef CefStringBase<CefStringTraitsUTF8> CefStringUTF8;
typedef CefStringBase<CefStringTraitsUTF16> CefStringUTF16;

// These functions are provided as a convenience for logging, which is where we
// use streams. Non-ASCII characters will be converted to UTF-8.
template <class traits>
inline std::ostream& operator<<(std::ostream& out,
                                const CefStringBase<traits>& str) {
  return operator<<(out, str.ToString());
}

#endif  // CEF_INCLUDE_INTERNAL_CEF_STRING_WRAPPERS_H_
