// Copyright 2016 PDFium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef CORE_FXCRT_CFX_STRING_C_TEMPLATE_H_ #define CORE_FXCRT_CFX_STRING_C_TEMPLATE_H_ #include #include #include #include "core/fxcrt/cfx_unowned_ptr.h" #include "core/fxcrt/fx_system.h" #include "third_party/base/stl_util.h" // An immutable string with caller-provided storage which must outlive the // string itself. These are not necessarily nul-terminated, so that substring // extraction (via the Mid(), Left(), and Right() methods) is copy-free. template class CFX_StringCTemplate { public: using CharType = T; using UnsignedType = typename std::make_unsigned::type; using const_iterator = const CharType*; CFX_StringCTemplate() : m_Ptr(nullptr), m_Length(0) {} // Deliberately implicit to avoid calling on every string literal. // NOLINTNEXTLINE(runtime/explicit) CFX_StringCTemplate(const CharType* ptr) : m_Ptr(reinterpret_cast(ptr)), m_Length(ptr ? FXSYS_len(ptr) : 0) {} CFX_StringCTemplate(const CharType* ptr, FX_STRSIZE len) : m_Ptr(reinterpret_cast(ptr)), m_Length(len == -1 ? FXSYS_len(ptr) : len) {} template CFX_StringCTemplate( const UnsignedType* ptr, FX_STRSIZE size, typename std::enable_if::value>::type* = 0) : m_Ptr(ptr), m_Length(size) {} // Deliberately implicit to avoid calling on every string literal. // |ch| must be an lvalue that outlives the the CFX_StringCTemplate. // NOLINTNEXTLINE(runtime/explicit) CFX_StringCTemplate(CharType& ch) { m_Ptr = reinterpret_cast(&ch); m_Length = 1; } CFX_StringCTemplate(const CFX_StringCTemplate& src) { m_Ptr = src.m_Ptr; m_Length = src.m_Length; } // Any changes to |vec| invalidate the string. explicit CFX_StringCTemplate(const std::vector& vec) { m_Ptr = vec.data(); m_Length = pdfium::CollectionSize(vec); } CFX_StringCTemplate& operator=(const CharType* src) { m_Ptr = reinterpret_cast(src); m_Length = src ? FXSYS_len(src) : 0; return *this; } CFX_StringCTemplate& operator=(const CFX_StringCTemplate& src) { m_Ptr = src.m_Ptr; m_Length = src.m_Length; return *this; } const_iterator begin() const { return reinterpret_cast(m_Ptr.Get()); } const_iterator end() const { return m_Ptr ? reinterpret_cast(m_Ptr.Get()) + m_Length : nullptr; } bool operator==(const CharType* ptr) const { return FXSYS_len(ptr) == m_Length && FXSYS_cmp(ptr, reinterpret_cast(m_Ptr.Get()), m_Length) == 0; } bool operator==(const CFX_StringCTemplate& other) const { return other.m_Length == m_Length && FXSYS_cmp(reinterpret_cast(other.m_Ptr.Get()), reinterpret_cast(m_Ptr.Get()), m_Length) == 0; } bool operator!=(const CharType* ptr) const { return !(*this == ptr); } bool operator!=(const CFX_StringCTemplate& other) const { return !(*this == other); } uint32_t GetID(FX_STRSIZE start_pos = 0) const { if (m_Length == 0 || start_pos < 0 || start_pos >= m_Length) return 0; uint32_t strid = 0; FX_STRSIZE size = std::min(4, m_Length - start_pos); for (FX_STRSIZE i = 0; i < size; i++) strid = strid * 256 + m_Ptr.Get()[start_pos + i]; return strid << ((4 - size) * 8); } const UnsignedType* raw_str() const { return m_Ptr.Get(); } const CharType* c_str() const { return reinterpret_cast(m_Ptr.Get()); } FX_STRSIZE GetLength() const { return m_Length; } bool IsEmpty() const { return m_Length == 0; } UnsignedType GetAt(FX_STRSIZE index) const { return m_Ptr.Get()[index]; } CharType CharAt(FX_STRSIZE index) const { return static_cast(m_Ptr.Get()[index]); } FX_STRSIZE Find(CharType ch) const { const UnsignedType* found = reinterpret_cast(FXSYS_chr( reinterpret_cast(m_Ptr.Get()), ch, m_Length)); return found ? found - m_Ptr.Get() : -1; } CFX_StringCTemplate Mid(FX_STRSIZE index, FX_STRSIZE count = -1) const { index = std::max(0, index); if (index > m_Length) return CFX_StringCTemplate(); if (count < 0 || count > m_Length - index) count = m_Length - index; return CFX_StringCTemplate(m_Ptr.Get() + index, count); } CFX_StringCTemplate Left(FX_STRSIZE count) const { if (count <= 0) return CFX_StringCTemplate(); return CFX_StringCTemplate(m_Ptr.Get(), std::min(count, m_Length)); } CFX_StringCTemplate Right(FX_STRSIZE count) const { if (count <= 0) return CFX_StringCTemplate(); count = std::min(count, m_Length); return CFX_StringCTemplate(m_Ptr.Get() + m_Length - count, count); } const UnsignedType& operator[](size_t index) const { return m_Ptr.Get()[index]; } bool operator<(const CFX_StringCTemplate& that) const { int result = FXSYS_cmp(reinterpret_cast(m_Ptr.Get()), reinterpret_cast(that.m_Ptr.Get()), std::min(m_Length, that.m_Length)); return result < 0 || (result == 0 && m_Length < that.m_Length); } protected: CFX_UnownedPtr m_Ptr; FX_STRSIZE m_Length; private: void* operator new(size_t) throw() { return nullptr; } }; template inline bool operator==(const T* lhs, const CFX_StringCTemplate& rhs) { return rhs == lhs; } template inline bool operator!=(const T* lhs, const CFX_StringCTemplate& rhs) { return rhs != lhs; } extern template class CFX_StringCTemplate; extern template class CFX_StringCTemplate; using CFX_ByteStringC = CFX_StringCTemplate; using CFX_WideStringC = CFX_StringCTemplate; #endif // CORE_FXCRT_CFX_STRING_C_TEMPLATE_H_