]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/stringimpl.cpp
Return NULL from wxWindow::GetCapture() when the capture is being lost.
[wxWidgets.git] / src / common / stringimpl.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/common/stringimpl.cpp
3// Purpose: wxString class
4// Author: Vadim Zeitlin, Ryan Norton
5// Modified by:
6// Created: 29/01/98
7// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
8// (c) 2004 Ryan Norton <wxprojects@comcast.net>
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12/*
13 * About ref counting:
14 * 1) all empty strings use g_strEmpty, nRefs = -1 (set in Init())
15 * 2) AllocBuffer() sets nRefs to 1, Lock() increments it by one
16 * 3) Unlock() decrements nRefs and frees memory if it goes to 0
17 */
18
19// ===========================================================================
20// headers, declarations, constants
21// ===========================================================================
22
23// For compilers that support precompilation, includes "wx.h".
24#include "wx/wxprec.h"
25
26#ifdef __BORLANDC__
27 #pragma hdrstop
28#endif
29
30#ifndef WX_PRECOMP
31 #include "wx/stringimpl.h"
32 #include "wx/wxcrt.h"
33#endif
34
35#include <ctype.h>
36
37#ifndef __WXWINCE__
38 #include <errno.h>
39#endif
40
41#include <string.h>
42#include <stdlib.h>
43
44// allocating extra space for each string consumes more memory but speeds up
45// the concatenation operations (nLen is the current string's length)
46// NB: EXTRA_ALLOC must be >= 0!
47#define EXTRA_ALLOC (19 - nLen % 16)
48
49
50// string handling functions used by wxString:
51#if wxUSE_UNICODE_UTF8
52 #define wxStringMemcpy memcpy
53 #define wxStringMemcmp memcmp
54 #define wxStringMemchr memchr
55#else
56 #define wxStringMemcpy wxTmemcpy
57 #define wxStringMemcmp wxTmemcmp
58 #define wxStringMemchr wxTmemchr
59#endif
60
61
62// ---------------------------------------------------------------------------
63// static class variables definition
64// ---------------------------------------------------------------------------
65
66#if !wxUSE_STL_BASED_WXSTRING
67//According to STL _must_ be a -1 size_t
68const size_t wxStringImpl::npos = (size_t) -1;
69#endif
70
71// ----------------------------------------------------------------------------
72// static data
73// ----------------------------------------------------------------------------
74
75#if wxUSE_STL_BASED_WXSTRING
76
77// FIXME-UTF8: get rid of this, have only one wxEmptyString
78#if wxUSE_UNICODE_UTF8
79const wxStringCharType WXDLLIMPEXP_BASE *wxEmptyStringImpl = "";
80#endif
81const wxChar WXDLLIMPEXP_BASE *wxEmptyString = wxT("");
82
83#else
84
85// for an empty string, GetStringData() will return this address: this
86// structure has the same layout as wxStringData and it's data() method will
87// return the empty string (dummy pointer)
88static const struct
89{
90 wxStringData data;
91 wxStringCharType dummy;
92} g_strEmpty = { {-1, 0, 0}, wxT('\0') };
93
94// empty C style string: points to 'string data' byte of g_strEmpty
95#if wxUSE_UNICODE_UTF8
96// FIXME-UTF8: get rid of this, have only one wxEmptyString
97const wxStringCharType WXDLLIMPEXP_BASE *wxEmptyStringImpl = &g_strEmpty.dummy;
98const wxChar WXDLLIMPEXP_BASE *wxEmptyString = wxT("");
99#else
100const wxStringCharType WXDLLIMPEXP_BASE *wxEmptyString = &g_strEmpty.dummy;
101#endif
102
103#endif
104
105
106#if !wxUSE_STL_BASED_WXSTRING
107
108// ----------------------------------------------------------------------------
109// private classes
110// ----------------------------------------------------------------------------
111
112// this small class is used to gather statistics for performance tuning
113
114// uncomment this to enable gathering of some statistics about wxString
115// efficiency
116//#define WXSTRING_STATISTICS
117
118#ifdef WXSTRING_STATISTICS
119 class Averager
120 {
121 public:
122 Averager(const wxStringCharType *sz) { m_sz = sz; m_nTotal = m_nCount = 0; }
123 ~Averager()
124 {
125 wxPrintf("wxString %s: total = %lu, average = %f\n",
126 m_sz, m_nTotal, ((float)m_nTotal)/m_nCount);
127 }
128
129 void Add(size_t n) { m_nTotal += n; m_nCount++; }
130
131 private:
132 unsigned long m_nCount, m_nTotal;
133 const wxStringCharType *m_sz;
134 } g_averageLength("allocation size"),
135 g_averageSummandLength("summand length"),
136 g_averageConcatHit("hit probability in concat"),
137 g_averageInitialLength("initial string length");
138
139 #define STATISTICS_ADD(av, val) g_average##av.Add(val)
140#else
141 #define STATISTICS_ADD(av, val)
142#endif // WXSTRING_STATISTICS
143
144// ===========================================================================
145// wxStringData class deallocation
146// ===========================================================================
147
148#if defined(__VISUALC__) && defined(_MT) && !defined(_DLL)
149# pragma message (__FILE__ ": building with Multithreaded non DLL runtime has a performance impact on wxString!")
150void wxStringData::Free()
151{
152 free(this);
153}
154#endif
155
156// ===========================================================================
157// wxStringImpl
158// ===========================================================================
159
160// takes nLength elements of psz starting at nPos
161void wxStringImpl::InitWith(const wxStringCharType *psz,
162 size_t nPos, size_t nLength)
163{
164 Init();
165
166 // if the length is not given, assume the string to be NUL terminated
167 if ( nLength == npos ) {
168 wxASSERT_MSG( nPos <= wxStrlen(psz), wxT("index out of bounds") );
169
170 nLength = wxStrlen(psz + nPos);
171 }
172
173 STATISTICS_ADD(InitialLength, nLength);
174
175 if ( nLength > 0 ) {
176 // trailing '\0' is written in AllocBuffer()
177 if ( !AllocBuffer(nLength) ) {
178 wxFAIL_MSG( wxT("out of memory in wxStringImpl::InitWith") );
179 return;
180 }
181 wxStringMemcpy(m_pchData, psz + nPos, nLength);
182 }
183}
184
185wxStringImpl::wxStringImpl(const_iterator first, const_iterator last)
186{
187 if ( last >= first )
188 {
189 InitWith(first.GetPtr(), 0, last - first);
190 }
191 else
192 {
193 wxFAIL_MSG( wxT("first must be before last") );
194 Init();
195 }
196}
197
198wxStringImpl::wxStringImpl(size_type n, wxStringCharType ch)
199{
200 Init();
201 append(n, ch);
202}
203
204// ---------------------------------------------------------------------------
205// memory allocation
206// ---------------------------------------------------------------------------
207
208// allocates memory needed to store a C string of length nLen
209bool wxStringImpl::AllocBuffer(size_t nLen)
210{
211 // allocating 0 sized buffer doesn't make sense, all empty strings should
212 // reuse g_strEmpty
213 wxASSERT( nLen > 0 );
214
215 // make sure that we don't overflow
216 wxCHECK( nLen < (INT_MAX / sizeof(wxStringCharType)) -
217 (sizeof(wxStringData) + EXTRA_ALLOC + 1), false );
218
219 STATISTICS_ADD(Length, nLen);
220
221 // allocate memory:
222 // 1) one extra character for '\0' termination
223 // 2) sizeof(wxStringData) for housekeeping info
224 wxStringData* pData = (wxStringData*)
225 malloc(sizeof(wxStringData) + (nLen + EXTRA_ALLOC + 1)*sizeof(wxStringCharType));
226
227 if ( pData == NULL ) {
228 // allocation failures are handled by the caller
229 return false;
230 }
231
232 pData->nRefs = 1;
233 pData->nDataLength = nLen;
234 pData->nAllocLength = nLen + EXTRA_ALLOC;
235 m_pchData = pData->data(); // data starts after wxStringData
236 m_pchData[nLen] = wxT('\0');
237 return true;
238}
239
240// must be called before changing this string
241bool wxStringImpl::CopyBeforeWrite()
242{
243 wxStringData* pData = GetStringData();
244
245 if ( pData->IsShared() ) {
246 pData->Unlock(); // memory not freed because shared
247 size_t nLen = pData->nDataLength;
248 if ( !AllocBuffer(nLen) ) {
249 // allocation failures are handled by the caller
250 return false;
251 }
252 wxStringMemcpy(m_pchData, pData->data(), nLen);
253 }
254
255 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
256
257 return true;
258}
259
260// must be called before replacing contents of this string
261bool wxStringImpl::AllocBeforeWrite(size_t nLen)
262{
263 wxASSERT( nLen != 0 ); // doesn't make any sense
264
265 // must not share string and must have enough space
266 wxStringData* pData = GetStringData();
267 if ( pData->IsShared() || pData->IsEmpty() ) {
268 // can't work with old buffer, get new one
269 pData->Unlock();
270 if ( !AllocBuffer(nLen) ) {
271 // allocation failures are handled by the caller
272 return false;
273 }
274 }
275 else {
276 if ( nLen > pData->nAllocLength ) {
277 // realloc the buffer instead of calling malloc() again, this is more
278 // efficient
279 STATISTICS_ADD(Length, nLen);
280
281 nLen += EXTRA_ALLOC;
282
283 pData = (wxStringData*)
284 realloc(pData,
285 sizeof(wxStringData) + (nLen + 1)*sizeof(wxStringCharType));
286
287 if ( pData == NULL ) {
288 // allocation failures are handled by the caller
289 // keep previous data since reallocation failed
290 return false;
291 }
292
293 pData->nAllocLength = nLen;
294 m_pchData = pData->data();
295 }
296 }
297
298 wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
299
300 // it doesn't really matter what the string length is as it's going to be
301 // overwritten later but, for extra safety, set it to 0 for now as we may
302 // have some junk in m_pchData
303 GetStringData()->nDataLength = 0;
304
305 return true;
306}
307
308wxStringImpl& wxStringImpl::append(size_t n, wxStringCharType ch)
309{
310 size_type len = length();
311
312 if ( !Alloc(len + n) || !CopyBeforeWrite() ) {
313 wxFAIL_MSG( wxT("out of memory in wxStringImpl::append") );
314 return *this;
315 }
316 GetStringData()->nDataLength = len + n;
317 m_pchData[len + n] = '\0';
318 for ( size_t i = 0; i < n; ++i )
319 m_pchData[len + i] = ch;
320 return *this;
321}
322
323void wxStringImpl::resize(size_t nSize, wxStringCharType ch)
324{
325 size_t len = length();
326
327 if ( nSize < len )
328 {
329 erase(begin() + nSize, end());
330 }
331 else if ( nSize > len )
332 {
333 append(nSize - len, ch);
334 }
335 //else: we have exactly the specified length, nothing to do
336}
337
338// allocate enough memory for nLen characters
339bool wxStringImpl::Alloc(size_t nLen)
340{
341 wxStringData *pData = GetStringData();
342 if ( pData->nAllocLength <= nLen ) {
343 if ( pData->IsEmpty() ) {
344 STATISTICS_ADD(Length, nLen);
345
346 nLen += EXTRA_ALLOC;
347
348 pData = (wxStringData *)
349 malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxStringCharType));
350
351 if ( pData == NULL ) {
352 // allocation failure handled by caller
353 return false;
354 }
355
356 pData->nRefs = 1;
357 pData->nDataLength = 0;
358 pData->nAllocLength = nLen;
359 m_pchData = pData->data(); // data starts after wxStringData
360 m_pchData[0u] = wxT('\0');
361 }
362 else if ( pData->IsShared() ) {
363 pData->Unlock(); // memory not freed because shared
364 size_t nOldLen = pData->nDataLength;
365 if ( !AllocBuffer(nLen) ) {
366 // allocation failure handled by caller
367 return false;
368 }
369 // +1 to copy the terminator, too
370 memcpy(m_pchData, pData->data(), (nOldLen+1)*sizeof(wxStringCharType));
371 GetStringData()->nDataLength = nOldLen;
372 }
373 else {
374 nLen += EXTRA_ALLOC;
375
376 pData = (wxStringData *)
377 realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxStringCharType));
378
379 if ( pData == NULL ) {
380 // allocation failure handled by caller
381 // keep previous data since reallocation failed
382 return false;
383 }
384
385 // it's not important if the pointer changed or not (the check for this
386 // is not faster than assigning to m_pchData in all cases)
387 pData->nAllocLength = nLen;
388 m_pchData = pData->data();
389 }
390 }
391 //else: we've already got enough
392 return true;
393}
394
395wxStringImpl::iterator wxStringImpl::begin()
396{
397 if ( !empty() )
398 CopyBeforeWrite();
399 return m_pchData;
400}
401
402wxStringImpl::iterator wxStringImpl::end()
403{
404 if ( !empty() )
405 CopyBeforeWrite();
406 return m_pchData + length();
407}
408
409wxStringImpl::iterator wxStringImpl::erase(iterator it)
410{
411 size_type idx = it - begin();
412 erase(idx, 1);
413 return begin() + idx;
414}
415
416wxStringImpl& wxStringImpl::erase(size_t nStart, size_t nLen)
417{
418 wxASSERT(nStart <= length());
419 size_t strLen = length() - nStart;
420 // delete nLen or up to the end of the string characters
421 nLen = strLen < nLen ? strLen : nLen;
422 wxStringImpl strTmp(c_str(), nStart);
423 strTmp.append(c_str() + nStart + nLen, length() - nStart - nLen);
424
425 swap(strTmp);
426 return *this;
427}
428
429wxStringImpl& wxStringImpl::insert(size_t nPos,
430 const wxStringCharType *sz, size_t n)
431{
432 wxASSERT( nPos <= length() );
433
434 if ( n == npos ) n = wxStrlen(sz);
435 if ( n == 0 ) return *this;
436
437 if ( !Alloc(length() + n) || !CopyBeforeWrite() ) {
438 wxFAIL_MSG( wxT("out of memory in wxStringImpl::insert") );
439 return *this;
440 }
441
442 memmove(m_pchData + nPos + n, m_pchData + nPos,
443 (length() - nPos) * sizeof(wxStringCharType));
444 memcpy(m_pchData + nPos, sz, n * sizeof(wxStringCharType));
445 GetStringData()->nDataLength = length() + n;
446 m_pchData[length()] = '\0';
447
448 return *this;
449}
450
451void wxStringImpl::swap(wxStringImpl& str)
452{
453 wxStringCharType* tmp = str.m_pchData;
454 str.m_pchData = m_pchData;
455 m_pchData = tmp;
456}
457
458size_t wxStringImpl::find(const wxStringImpl& str, size_t nStart) const
459{
460 // deal with the special case of empty string first
461 const size_t nLen = length();
462 const size_t nLenOther = str.length();
463
464 if ( !nLenOther )
465 {
466 // empty string is a substring of anything
467 return 0;
468 }
469
470 if ( !nLen )
471 {
472 // the other string is non empty so can't be our substring
473 return npos;
474 }
475
476 wxASSERT( str.GetStringData()->IsValid() );
477 wxASSERT( nStart <= nLen );
478
479 const wxStringCharType * const other = str.c_str();
480
481 // anchor
482 const wxStringCharType* p =
483 (const wxStringCharType*)wxStringMemchr(c_str() + nStart,
484 *other,
485 nLen - nStart);
486
487 if ( !p )
488 return npos;
489
490 while ( p - c_str() + nLenOther <= nLen &&
491 wxStringMemcmp(p, other, nLenOther) )
492 {
493 p++;
494
495 // anchor again
496 p = (const wxStringCharType*)
497 wxStringMemchr(p, *other, nLen - (p - c_str()));
498
499 if ( !p )
500 return npos;
501 }
502
503 return p - c_str() + nLenOther <= nLen ? p - c_str() : npos;
504}
505
506size_t wxStringImpl::find(const wxStringCharType* sz,
507 size_t nStart, size_t n) const
508{
509 return find(wxStringImpl(sz, n), nStart);
510}
511
512size_t wxStringImpl::find(wxStringCharType ch, size_t nStart) const
513{
514 wxASSERT( nStart <= length() );
515
516 const wxStringCharType *p = (const wxStringCharType*)
517 wxStringMemchr(c_str() + nStart, ch, length() - nStart);
518
519 return p == NULL ? npos : p - c_str();
520}
521
522size_t wxStringImpl::rfind(const wxStringImpl& str, size_t nStart) const
523{
524 wxASSERT( str.GetStringData()->IsValid() );
525 wxASSERT( nStart == npos || nStart <= length() );
526
527 if ( length() >= str.length() )
528 {
529 // avoids a corner case later
530 if ( empty() && str.empty() )
531 return 0;
532
533 // "top" is the point where search starts from
534 size_t top = length() - str.length();
535
536 if ( nStart == npos )
537 nStart = length() - 1;
538 if ( nStart < top )
539 top = nStart;
540
541 const wxStringCharType *cursor = c_str() + top;
542 do
543 {
544 if ( wxStringMemcmp(cursor, str.c_str(), str.length()) == 0 )
545 {
546 return cursor - c_str();
547 }
548 } while ( cursor-- > c_str() );
549 }
550
551 return npos;
552}
553
554size_t wxStringImpl::rfind(const wxStringCharType* sz,
555 size_t nStart, size_t n) const
556{
557 return rfind(wxStringImpl(sz, n), nStart);
558}
559
560size_t wxStringImpl::rfind(wxStringCharType ch, size_t nStart) const
561{
562 if ( nStart == npos )
563 {
564 nStart = length();
565 }
566 else
567 {
568 wxASSERT( nStart <= length() );
569 }
570
571 const wxStringCharType *actual;
572 for ( actual = c_str() + ( nStart == npos ? length() : nStart + 1 );
573 actual > c_str(); --actual )
574 {
575 if ( *(actual - 1) == ch )
576 return (actual - 1) - c_str();
577 }
578
579 return npos;
580}
581
582wxStringImpl& wxStringImpl::replace(size_t nStart, size_t nLen,
583 const wxStringCharType *sz, size_t nCount)
584{
585 // check and adjust parameters
586 const size_t lenOld = length();
587
588 wxASSERT_MSG( nStart <= lenOld,
589 wxT("index out of bounds in wxStringImpl::replace") );
590 size_t nEnd = nStart + nLen;
591 if ( nLen > lenOld - nStart )
592 {
593 // nLen may be out of range, as it can be npos, just clump it down
594 nLen = lenOld - nStart;
595 nEnd = lenOld;
596 }
597
598 if ( nCount == npos )
599 nCount = wxStrlen(sz);
600
601 // build the new string from 3 pieces: part of this string before nStart,
602 // the new substring and the part of this string after nStart+nLen
603 wxStringImpl tmp;
604 const size_t lenNew = lenOld + nCount - nLen;
605 if ( lenNew )
606 {
607 tmp.AllocBuffer(lenOld + nCount - nLen);
608
609 wxStringCharType *dst = tmp.m_pchData;
610 memcpy(dst, m_pchData, nStart*sizeof(wxStringCharType));
611 dst += nStart;
612
613 memcpy(dst, sz, nCount*sizeof(wxStringCharType));
614 dst += nCount;
615
616 memcpy(dst, m_pchData + nEnd, (lenOld - nEnd)*sizeof(wxStringCharType));
617 }
618
619 // and replace this string contents with the new one
620 swap(tmp);
621 return *this;
622}
623
624wxStringImpl wxStringImpl::substr(size_t nStart, size_t nLen) const
625{
626 if ( nLen == npos )
627 nLen = length() - nStart;
628 return wxStringImpl(*this, nStart, nLen);
629}
630
631// assigns one string to another
632wxStringImpl& wxStringImpl::operator=(const wxStringImpl& stringSrc)
633{
634 wxASSERT( stringSrc.GetStringData()->IsValid() );
635
636 // don't copy string over itself
637 if ( m_pchData != stringSrc.m_pchData ) {
638 if ( stringSrc.GetStringData()->IsEmpty() ) {
639 Reinit();
640 }
641 else {
642 // adjust references
643 GetStringData()->Unlock();
644 m_pchData = stringSrc.m_pchData;
645 GetStringData()->Lock();
646 }
647 }
648
649 return *this;
650}
651
652// assigns a single character
653wxStringImpl& wxStringImpl::operator=(wxStringCharType ch)
654{
655 wxStringCharType c(ch);
656 if ( !AssignCopy(1, &c) ) {
657 wxFAIL_MSG( wxT("out of memory in wxStringImpl::operator=(wxStringCharType)") );
658 }
659 return *this;
660}
661
662// assigns C string
663wxStringImpl& wxStringImpl::operator=(const wxStringCharType *psz)
664{
665 if ( !AssignCopy(wxStrlen(psz), psz) ) {
666 wxFAIL_MSG( wxT("out of memory in wxStringImpl::operator=(const wxStringCharType *)") );
667 }
668 return *this;
669}
670
671// helper function: does real copy
672bool wxStringImpl::AssignCopy(size_t nSrcLen,
673 const wxStringCharType *pszSrcData)
674{
675 if ( nSrcLen == 0 ) {
676 Reinit();
677 }
678 else {
679 if ( !AllocBeforeWrite(nSrcLen) ) {
680 // allocation failure handled by caller
681 return false;
682 }
683
684 // use memmove() and not memcpy() here as we might be copying from our own
685 // buffer in case of assignment such as "s = s.c_str()" (see #11294)
686 memmove(m_pchData, pszSrcData, nSrcLen*sizeof(wxStringCharType));
687
688 GetStringData()->nDataLength = nSrcLen;
689 m_pchData[nSrcLen] = wxT('\0');
690 }
691 return true;
692}
693
694// ---------------------------------------------------------------------------
695// string concatenation
696// ---------------------------------------------------------------------------
697
698// add something to this string
699bool wxStringImpl::ConcatSelf(size_t nSrcLen,
700 const wxStringCharType *pszSrcData,
701 size_t nMaxLen)
702{
703 STATISTICS_ADD(SummandLength, nSrcLen);
704
705 nSrcLen = nSrcLen < nMaxLen ? nSrcLen : nMaxLen;
706
707 // concatenating an empty string is a NOP
708 if ( nSrcLen > 0 ) {
709 wxStringData *pData = GetStringData();
710 size_t nLen = pData->nDataLength;
711
712 // take special care when appending part of this string to itself: the code
713 // below reallocates our buffer and this invalidates pszSrcData pointer so
714 // we have to copy it in another temporary string in this case (but avoid
715 // doing this unnecessarily)
716 if ( pszSrcData >= m_pchData && pszSrcData < m_pchData + nLen )
717 {
718 wxStringImpl tmp(pszSrcData, nSrcLen);
719 return ConcatSelf(nSrcLen, tmp.m_pchData, nSrcLen);
720 }
721
722 size_t nNewLen = nLen + nSrcLen;
723
724 // alloc new buffer if current is too small
725 if ( pData->IsShared() ) {
726 STATISTICS_ADD(ConcatHit, 0);
727
728 // we have to allocate another buffer
729 wxStringData* pOldData = GetStringData();
730 if ( !AllocBuffer(nNewLen) ) {
731 // allocation failure handled by caller
732 return false;
733 }
734 memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxStringCharType));
735 pOldData->Unlock();
736 }
737 else if ( nNewLen > pData->nAllocLength ) {
738 STATISTICS_ADD(ConcatHit, 0);
739
740 reserve(nNewLen);
741 // we have to grow the buffer
742 if ( capacity() < nNewLen ) {
743 // allocation failure handled by caller
744 return false;
745 }
746 }
747 else {
748 STATISTICS_ADD(ConcatHit, 1);
749
750 // the buffer is already big enough
751 }
752
753 // should be enough space
754 wxASSERT( nNewLen <= GetStringData()->nAllocLength );
755
756 // fast concatenation - all is done in our buffer
757 memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(wxStringCharType));
758
759 m_pchData[nNewLen] = wxT('\0'); // put terminating '\0'
760 GetStringData()->nDataLength = nNewLen; // and fix the length
761 }
762 //else: the string to append was empty
763 return true;
764}
765
766// get the pointer to writable buffer of (at least) nLen bytes
767wxStringCharType *wxStringImpl::DoGetWriteBuf(size_t nLen)
768{
769 if ( !AllocBeforeWrite(nLen) ) {
770 // allocation failure handled by caller
771 return NULL;
772 }
773
774 wxASSERT( GetStringData()->nRefs == 1 );
775 GetStringData()->Validate(false);
776
777 return m_pchData;
778}
779
780// put string back in a reasonable state after GetWriteBuf
781void wxStringImpl::DoUngetWriteBuf()
782{
783 DoUngetWriteBuf(wxStrlen(m_pchData));
784}
785
786void wxStringImpl::DoUngetWriteBuf(size_t nLen)
787{
788 wxStringData * const pData = GetStringData();
789
790 wxASSERT_MSG( nLen < pData->nAllocLength, wxT("buffer overrun") );
791
792 // the strings we store are always NUL-terminated
793 pData->data()[nLen] = wxT('\0');
794 pData->nDataLength = nLen;
795 pData->Validate(true);
796}
797
798#endif // !wxUSE_STL_BASED_WXSTRING