1 // Copyright 2016 PDFium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com 6 7 #ifndef CORE_FXCRT_STRING_DATA_TEMPLATE_H_ 8 #define CORE_FXCRT_STRING_DATA_TEMPLATE_H_ 9 10 #include "core/fxcrt/fx_memory.h" 11 #include "core/fxcrt/fx_system.h" 12 #include "third_party/base/numerics/safe_math.h" 13 14 namespace fxcrt { 15 16 template <typename CharType> 17 class StringDataTemplate { 18 public: Create(size_t nLen)19 static StringDataTemplate* Create(size_t nLen) { 20 ASSERT(nLen > 0); 21 22 // Calculate space needed for the fixed portion of the struct plus the 23 // NUL char that is not included in |m_nAllocLength|. 24 int overhead = offsetof(StringDataTemplate, m_String) + sizeof(CharType); 25 pdfium::base::CheckedNumeric<size_t> nSize = nLen; 26 nSize *= sizeof(CharType); 27 nSize += overhead; 28 29 // Now round to an 8-byte boundary. We'd expect that this is the minimum 30 // granularity of any of the underlying allocators, so there may be cases 31 // where we can save a re-alloc when adding a few characters to a string 32 // by using this otherwise wasted space. 33 nSize += 7; 34 nSize &= ~7; 35 size_t totalSize = nSize.ValueOrDie(); 36 size_t usableLen = (totalSize - overhead) / sizeof(CharType); 37 ASSERT(usableLen >= nLen); 38 39 void* pData = pdfium::base::PartitionAllocGeneric( 40 gStringPartitionAllocator.root(), totalSize, "StringDataTemplate"); 41 return new (pData) StringDataTemplate(nLen, usableLen); 42 } 43 Create(const StringDataTemplate & other)44 static StringDataTemplate* Create(const StringDataTemplate& other) { 45 StringDataTemplate* result = Create(other.m_nDataLength); 46 result->CopyContents(other); 47 return result; 48 } 49 Create(const CharType * pStr,size_t nLen)50 static StringDataTemplate* Create(const CharType* pStr, size_t nLen) { 51 StringDataTemplate* result = Create(nLen); 52 result->CopyContents(pStr, nLen); 53 return result; 54 } 55 Retain()56 void Retain() { ++m_nRefs; } Release()57 void Release() { 58 if (--m_nRefs <= 0) 59 pdfium::base::PartitionFreeGeneric(gStringPartitionAllocator.root(), 60 this); 61 } 62 CanOperateInPlace(size_t nTotalLen)63 bool CanOperateInPlace(size_t nTotalLen) const { 64 return m_nRefs <= 1 && nTotalLen <= m_nAllocLength; 65 } 66 CopyContents(const StringDataTemplate & other)67 void CopyContents(const StringDataTemplate& other) { 68 ASSERT(other.m_nDataLength <= m_nAllocLength); 69 memcpy(m_String, other.m_String, 70 (other.m_nDataLength + 1) * sizeof(CharType)); 71 } 72 CopyContents(const CharType * pStr,size_t nLen)73 void CopyContents(const CharType* pStr, size_t nLen) { 74 ASSERT(nLen >= 0 && nLen <= m_nAllocLength); 75 memcpy(m_String, pStr, nLen * sizeof(CharType)); 76 m_String[nLen] = 0; 77 } 78 CopyContentsAt(size_t offset,const CharType * pStr,size_t nLen)79 void CopyContentsAt(size_t offset, const CharType* pStr, size_t nLen) { 80 ASSERT(offset >= 0 && nLen >= 0 && offset + nLen <= m_nAllocLength); 81 memcpy(m_String + offset, pStr, nLen * sizeof(CharType)); 82 m_String[offset + nLen] = 0; 83 } 84 85 // To ensure ref counts do not overflow, consider the worst possible case: 86 // the entire address space contains nothing but pointers to this object. 87 // Since the count increments with each new pointer, the largest value is 88 // the number of pointers that can fit into the address space. The size of 89 // the address space itself is a good upper bound on it. 90 intptr_t m_nRefs; 91 92 // These lengths are in terms of number of characters, not bytes, and do not 93 // include the terminating NUL character, but the underlying buffer is sized 94 // to be capable of holding it. 95 size_t m_nDataLength; 96 size_t m_nAllocLength; 97 98 // Not really 1, variable size. 99 CharType m_String[1]; 100 101 private: StringDataTemplate(size_t dataLen,size_t allocLen)102 StringDataTemplate(size_t dataLen, size_t allocLen) 103 : m_nRefs(0), m_nDataLength(dataLen), m_nAllocLength(allocLen) { 104 ASSERT(dataLen >= 0); 105 ASSERT(dataLen <= allocLen); 106 m_String[dataLen] = 0; 107 } 108 109 ~StringDataTemplate() = delete; 110 }; 111 112 extern template class StringDataTemplate<char>; 113 extern template class StringDataTemplate<wchar_t>; 114 115 } // namespace fxcrt 116 117 using fxcrt::StringDataTemplate; 118 119 #endif // CORE_FXCRT_STRING_DATA_TEMPLATE_H_ 120