Пример #1
0
void
nsTSubstring_CharT::Replace( index_type cutStart, size_type cutLength, const char_type* data, size_type length )
  {
      // unfortunately, some callers pass null :-(
    if (!data)
      {
        length = 0;
      }
    else
      {
        if (length == size_type(-1))
          length = char_traits::length(data);

        if (IsDependentOn(data, data + length))
          {
            nsTAutoString_CharT temp(data, length);
            Replace(cutStart, cutLength, temp);
            return;
          }
      }

    cutStart = XPCOM_MIN(cutStart, Length());

    if (ReplacePrep(cutStart, cutLength, length) && length > 0)
      char_traits::copy(mData + cutStart, data, length);
  }
Пример #2
0
NS_IMETHODIMP
nsScriptableInputStream::Read(uint32_t aCount, char** aResult)
{
  nsresult rv = NS_OK;
  uint64_t count64 = 0;
  char* buffer = nullptr;

  if (!mInputStream) {
    return NS_ERROR_NOT_INITIALIZED;
  }

  rv = mInputStream->Available(&count64);
  if (NS_FAILED(rv)) {
    return rv;
  }

  // bug716556 - Ensure count+1 doesn't overflow
  uint32_t count =
    XPCOM_MIN((uint32_t)XPCOM_MIN<uint64_t>(count64, aCount), UINT32_MAX - 1);
  buffer = (char*)malloc(count + 1);  // make room for '\0'
  if (!buffer) {
    return NS_ERROR_OUT_OF_MEMORY;
  }

  rv = ReadHelper(buffer, count);
  if (NS_FAILED(rv)) {
    free(buffer);
    return rv;
  }

  buffer[count] = '\0';
  *aResult = buffer;
  return NS_OK;
}
Пример #3
0
static int32_t
CompareVP(VersionPartW& aVer1, VersionPartW& aVer2)
{
  int32_t r = ns_cmp(aVer1.numA, aVer2.numA);
  if (r) {
    return r;
  }

  r = wcsncmp(aVer1.strB, aVer2.strB, XPCOM_MIN(aVer1.strBlen, aVer2.strBlen));
  if (r) {
    return r;
  }

  r = ns_cmp(aVer1.numC, aVer2.numC);
  if (r) {
    return r;
  }

  if (!aVer1.extraD) {
    return aVer2.extraD != 0;
  }

  if (!aVer2.extraD) {
    return -1;
  }

  return wcscmp(aVer1.extraD, aVer2.extraD);
}
Пример #4
0
bool
nsString::EqualsIgnoreCase( const char* aString, int32_t aCount ) const
{
    uint32_t strLen = nsCharTraits<char>::length(aString);

    int32_t maxCount = int32_t(XPCOM_MIN(mLength, strLen));

    int32_t compareCount;
    if (aCount < 0 || aCount > maxCount)
        compareCount = maxCount;
    else
        compareCount = aCount;

    int32_t result =
        nsBufferRoutines<char16_t>::compare(mData, aString, compareCount, true);

    if (result == 0 &&
            (aCount < 0 || strLen < uint32_t(aCount) || mLength < uint32_t(aCount)))
    {
        // Since the caller didn't give us a length to test, or strings shorter
        // than aCount, and compareCount characters matched, we have to assume
        // that the longer string is greater.

        if (mLength != strLen)
            result = 1; // Arbitrarily using any number != 0
    }
    return result == 0;
}
Пример #5
0
int NS_FASTCALL
Compare(const nsTSubstring_CharT::base_string_type& aLhs,
        const nsTSubstring_CharT::base_string_type& aRhs,
        const nsTStringComparator_CharT& comp)
{
  typedef nsTSubstring_CharT::size_type size_type;

  if (&aLhs == &aRhs) {
    return 0;
  }

  nsTSubstring_CharT::const_iterator leftIter, rightIter;
  aLhs.BeginReading(leftIter);
  aRhs.BeginReading(rightIter);

  size_type lLength = leftIter.size_forward();
  size_type rLength = rightIter.size_forward();
  size_type lengthToCompare = XPCOM_MIN(lLength, rLength);

  int result;
  if ((result = comp(leftIter.get(), rightIter.get(),
                     lengthToCompare, lengthToCompare)) == 0) {
    if (lLength < rLength) {
      result = -1;
    } else if (rLength < lLength) {
      result = 1;
    } else {
      result = 0;
    }
  }

  return result;
}
Пример #6
0
int32_t
nsCString::Compare( const char* aString, bool aIgnoreCase, int32_t aCount ) const
{
    uint32_t strLen = char_traits::length(aString);

    int32_t maxCount = int32_t(XPCOM_MIN(mLength, strLen));

    int32_t compareCount;
    if (aCount < 0 || aCount > maxCount)
        compareCount = maxCount;
    else
        compareCount = aCount;

    int32_t result =
        nsBufferRoutines<char>::compare(mData, aString, compareCount, aIgnoreCase);

    if (result == 0 &&
            (aCount < 0 || strLen < uint32_t(aCount) || mLength < uint32_t(aCount)))
    {
        // Since the caller didn't give us a length to test, or strings shorter
        // than aCount, and compareCount characters matched, we have to assume
        // that the longer string is greater.

        if (mLength != strLen)
            result = (mLength < strLen) ? -1 : 1;
    }
    return result;
}
NS_IMETHODIMP
StringUnicharInputStream::ReadSegments(nsWriteUnicharSegmentFun aWriter,
                                       void* aClosure,
                                       uint32_t aCount, uint32_t* aReadCount)
{
  uint32_t bytesWritten;
  uint32_t totalBytesWritten = 0;

  nsresult rv;
  aCount = XPCOM_MIN(mString.Length() - mPos, aCount);

  nsAString::const_iterator iter;
  mString.BeginReading(iter);

  while (aCount) {
    rv = aWriter(this, aClosure, iter.get() + mPos,
                 totalBytesWritten, aCount, &bytesWritten);

    if (NS_FAILED(rv)) {
      // don't propagate errors to the caller
      break;
    }

    aCount -= bytesWritten;
    totalBytesWritten += bytesWritten;
    mPos += bytesWritten;
  }

  *aReadCount = totalBytesWritten;

  return NS_OK;
}
Пример #8
0
  // This version of Replace is optimized for single-character replacement.
void
nsTSubstring_CharT::Replace( index_type cutStart, size_type cutLength, char_type c )
  {
    cutStart = XPCOM_MIN(cutStart, Length());

    if (ReplacePrep(cutStart, cutLength, 1))
      mData[cutStart] = c;
  }
Пример #9
0
NS_IMETHODIMP
nsStorageStream::Write(const char *aBuffer, uint32_t aCount, uint32_t *aNumWritten)
{
    if (NS_WARN_IF(!aNumWritten) || NS_WARN_IF(!aBuffer))
        return NS_ERROR_INVALID_ARG;
    if (NS_WARN_IF(!mSegmentedBuffer))
        return NS_ERROR_NOT_INITIALIZED;
    
    const char* readCursor;
    uint32_t count, availableInSegment, remaining;
    nsresult rv = NS_OK;

    LOG(("nsStorageStream [%p] Write mWriteCursor=%x mSegmentEnd=%x aCount=%d\n",
        this, mWriteCursor, mSegmentEnd, aCount));

    remaining = aCount;
    readCursor = aBuffer;
    // If no segments have been created yet, create one even if we don't have
    // to write any data; this enables creating an input stream which reads from
    // the very end of the data for any amount of data in the stream (i.e.
    // this stream contains N bytes of data and newInputStream(N) is called),
    // even for N=0 (with the caveat that we require .write("", 0) be called to
    // initialize internal buffers).
    bool firstTime = mSegmentedBuffer->GetSegmentCount() == 0;
    while (remaining || MOZ_UNLIKELY(firstTime)) {
        firstTime = false;
        availableInSegment = mSegmentEnd - mWriteCursor;
        if (!availableInSegment) {
            mWriteCursor = mSegmentedBuffer->AppendNewSegment();
            if (!mWriteCursor) {
                mSegmentEnd = 0;
                rv = NS_ERROR_OUT_OF_MEMORY;
                goto out;
            }
            mLastSegmentNum++;
            mSegmentEnd = mWriteCursor + mSegmentSize;
            availableInSegment = mSegmentEnd - mWriteCursor;
            LOG(("nsStorageStream [%p] Write (new seg) mWriteCursor=%x mSegmentEnd=%x\n",
                this, mWriteCursor, mSegmentEnd));
        }
	
        count = XPCOM_MIN(availableInSegment, remaining);
        memcpy(mWriteCursor, readCursor, count);
        remaining -= count;
        readCursor += count;
        mWriteCursor += count;
        LOG(("nsStorageStream [%p] Writing mWriteCursor=%x mSegmentEnd=%x count=%d\n",
            this, mWriteCursor, mSegmentEnd, count));
    };

 out:
    *aNumWritten = aCount - remaining;
    mLogicalLength += *aNumWritten;

    LOG(("nsStorageStream [%p] Wrote mWriteCursor=%x mSegmentEnd=%x numWritten=%d\n",
        this, mWriteCursor, mSegmentEnd, *aNumWritten));
    return rv;
}
Пример #10
0
void
nsTDependentSubstring_CharT::Rebind( const substring_type& str, uint32_t startPos, uint32_t length )
{
  // If we currently own a buffer, release it.
  Finalize();

  size_type strLength = str.Length();

  if (startPos > strLength)
    startPos = strLength;

  mData = const_cast<char_type*>(static_cast<const char_type*>(str.Data())) + startPos;
  mLength = XPCOM_MIN(length, strLength - startPos);

  SetDataFlags(F_NONE);
}
Пример #11
0
void
nsTSubstring_CharT::Replace( index_type cutStart, size_type cutLength, const substring_tuple_type& tuple )
  {
    if (tuple.IsDependentOn(mData, mData + mLength))
      {
        nsTAutoString_CharT temp(tuple);
        Replace(cutStart, cutLength, temp);
        return;
      }

    size_type length = tuple.Length();

    cutStart = XPCOM_MIN(cutStart, Length());

    if (ReplacePrep(cutStart, cutLength, length) && length > 0)
      tuple.WriteTo(mData + cutStart, length);
  }
Пример #12
0
 uint32_t
 write( const char* aSource, uint32_t aSourceLength )
   {
     uint32_t len = XPCOM_MIN(uint32_t(mIter.size_forward()), aSourceLength);
     char* cp = mIter.get();
     const char* end = aSource + len;
     while (aSource != end) {
       char ch = *aSource;
       if ((ch >= 'A') && (ch <= 'Z'))
         *cp = ch + ('a' - 'A');
       else
         *cp = ch;
       ++aSource;
       ++cp;
     }
     mIter.advance(len);
     return len;
   }
Пример #13
0
nsresult
FileLocation::Data::Copy(char *buf, uint32_t len)
{
  if (mFd) {
    for (uint32_t totalRead = 0; totalRead < len; ) {
      int32_t read = PR_Read(mFd, buf + totalRead, XPCOM_MIN(len - totalRead, uint32_t(INT32_MAX)));
      if (read < 0)
        return NS_ErrorAccordingToNSPR();
      totalRead += read;
    }
    return NS_OK;
  } else if (mItem) {
    nsZipCursor cursor(mItem, mZip, reinterpret_cast<uint8_t *>(buf), len, true);
    uint32_t readLen;
    cursor.Copy(&readLen);
    return (readLen == len) ? NS_OK : NS_ERROR_FILE_CORRUPTED;
  }
  return NS_ERROR_NOT_INITIALIZED;
}
Пример #14
0
bool
nsTSubstring_CharT::SetCapacity( size_type capacity, const fallible_t& )
  {
    // capacity does not include room for the terminating null char

    // if our capacity is reduced to zero, then free our buffer.
    if (capacity == 0)
      {
        ::ReleaseData(mData, mFlags);
        mData = char_traits::sEmptyBuffer;
        mLength = 0;
        SetDataFlags(F_TERMINATED);
        return true;
      }

    char_type* oldData;
    uint32_t oldFlags;
    if (!MutatePrep(capacity, &oldData, &oldFlags))
      return false; // out-of-memory

    // compute new string length
    size_type newLen = XPCOM_MIN(mLength, capacity);

    if (oldData)
      {
        // preserve old data
        if (mLength > 0)
          char_traits::copy(mData, oldData, newLen);

        ::ReleaseData(oldData, oldFlags);
      }

    // adjust mLength if our buffer shrunk down in size
    if (newLen < mLength)
      mLength = newLen;

    // always null-terminate here, even if the buffer got longer.  this is
    // for backwards compat with the old string implementation.
    mData[capacity] = char_type(0);

    return true;
  }
Пример #15
0
void
LossyConvertEncoding8to16::write_sse2(const char* aSource,
                                      uint32_t aSourceLength)
{
  char16_t* dest = mDestination;

  // Align source to a 16-byte boundary.  We choose to align source rather than
  // dest because we'd rather have our loads than our stores be fast. You have
  // to wait for a load to complete, but you can keep on moving after issuing a
  // store.
  uint32_t i = 0;
  uint32_t alignLen = XPCOM_MIN(aSourceLength, uint32_t(-NS_PTR_TO_INT32(aSource) & 0xf));
  for (; i < alignLen; ++i) {
    dest[i] = static_cast<unsigned char>(aSource[i]);
  }

  // Walk 32 bytes (two XMM registers) at a time.
  for (; aSourceLength - i > 31; i += 32) {
    __m128i source1 = _mm_load_si128(reinterpret_cast<const __m128i*>(aSource + i));
    __m128i source2 = _mm_load_si128(reinterpret_cast<const __m128i*>(aSource + i + 16));

    // Interleave 0s in with the bytes of source to create lo and hi.
    __m128i lo1 = _mm_unpacklo_epi8(source1, _mm_setzero_si128());
    __m128i hi1 = _mm_unpackhi_epi8(source1, _mm_setzero_si128());
    __m128i lo2 = _mm_unpacklo_epi8(source2, _mm_setzero_si128());
    __m128i hi2 = _mm_unpackhi_epi8(source2, _mm_setzero_si128());

    // store lo and hi into dest.
    _mm_storeu_si128(reinterpret_cast<__m128i*>(dest + i),      lo1);
    _mm_storeu_si128(reinterpret_cast<__m128i*>(dest + i + 8),  hi1);
    _mm_storeu_si128(reinterpret_cast<__m128i*>(dest + i + 16), lo2);
    _mm_storeu_si128(reinterpret_cast<__m128i*>(dest + i + 24), hi2);
  }

  // Finish up whatever's left.
  for (; i < aSourceLength; ++i) {
    dest[i] = static_cast<unsigned char>(aSource[i]);
  }

  mDestination += i;
}
Пример #16
0
void
nsTSubstring_CharT::ReplaceASCII( index_type cutStart, size_type cutLength, const char* data, size_type length )
  {
    if (length == size_type(-1))
      length = strlen(data);
    
    // A Unicode string can't depend on an ASCII string buffer,
    // so this dependence check only applies to CStrings.
#ifdef CharT_is_char
    if (IsDependentOn(data, data + length))
      {
        nsTAutoString_CharT temp(data, length);
        Replace(cutStart, cutLength, temp);
        return;
      }
#endif

    cutStart = XPCOM_MIN(cutStart, Length());

    if (ReplacePrep(cutStart, cutLength, length) && length > 0)
      char_traits::copyASCII(mData + cutStart, data, length);
  }
Пример #17
0
void NS_QuickSort (
	void *a,
	unsigned int n,
    unsigned int es,
	cmp_t *cmp,
	void *data
    )
{
	char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
	int d, r, swaptype;

loop:	SWAPINIT(a, es);
	/* Use insertion sort when input is small */
	if (n < 7) {
		for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
			for (pl = pm; pl > (char *)a && cmp(pl - es, pl, data) > 0;
			     pl -= es)
				swap(pl, pl - es);
		return;
	}
	/* Choose pivot */
	pm = (char *)a + (n / 2) * es;
	if (n > 7) {
		pl = (char *)a;
		pn = (char *)a + (n - 1) * es;
		if (n > 40) {
			d = (n / 8) * es;
			pl = med3(pl, pl + d, pl + 2 * d, cmp, data);
			pm = med3(pm - d, pm, pm + d, cmp, data);
			pn = med3(pn - 2 * d, pn - d, pn, cmp, data);
		}
		pm = med3(pl, pm, pn, cmp, data);
	}
	swap(a, pm);
	pa = pb = (char *)a + es;

	pc = pd = (char *)a + (n - 1) * es;
	/* loop invariants:
	 * [a, pa) = pivot
	 * [pa, pb) < pivot
	 * [pb, pc + es) unprocessed
	 * [pc + es, pd + es) > pivot
	 * [pd + es, pn) = pivot
	 */
	for (;;) {
		while (pb <= pc && (r = cmp(pb, a, data)) <= 0) {
			if (r == 0) {
				swap(pa, pb);
				pa += es;
			}
			pb += es;
		}
		while (pb <= pc && (r = cmp(pc, a, data)) >= 0) {
			if (r == 0) {
				swap(pc, pd);
				pd -= es;
			}
			pc -= es;
		}
		if (pb > pc)
			break;
		swap(pb, pc);
		pb += es;
		pc -= es;
	}
	/* Move pivot values */
	pn = (char *)a + n * es;
	r = XPCOM_MIN(pa - (char *)a, pb - pa);
	vecswap(a, pb - r, r);
	r = XPCOM_MIN<size_t>(pd - pc, pn - pd - es);
	vecswap(pb, pn - r, r);
	/* Recursively process partitioned items */
	if ((r = pb - pa) > (int)es)
        NS_QuickSort(a, r / es, es, cmp, data);
	if ((r = pd - pc) > (int)es) {
		/* Iterate rather than recurse to save stack space */
		a = pn - r;
		n = r / es;
		goto loop;
	}
/*		NS_QuickSort(pn - r, r / es, es, cmp, data);*/
}
Пример #18
0
nsresult
FileReader::DoReadData(uint64_t aCount)
{
  MOZ_ASSERT(mAsyncStream);

  uint32_t bytesRead = 0;

  if (mDataFormat == FILE_AS_BINARY) {
    //Continuously update our binary string as data comes in
    CheckedInt<uint64_t> size = mResult.Length();
    size += aCount;

    if (!size.isValid() ||
        size.value() > UINT32_MAX ||
        size.value() > mTotal) {
      return NS_ERROR_OUT_OF_MEMORY;
    }

    uint32_t oldLen = mResult.Length();
    MOZ_ASSERT(oldLen == mDataLen, "unexpected mResult length");

    char16_t* dest = nullptr;
    mResult.GetMutableData(&dest, size.value(), fallible);
    NS_ENSURE_TRUE(dest, NS_ERROR_OUT_OF_MEMORY);

    dest += oldLen;

    if (NS_InputStreamIsBuffered(mAsyncStream)) {
      nsresult rv = mAsyncStream->ReadSegments(ReadFuncBinaryString, dest,
                                               aCount, &bytesRead);
      NS_ENSURE_SUCCESS(rv, rv);
    } else {
      while (aCount > 0) {
        char tmpBuffer[4096];
        uint32_t minCount =
          XPCOM_MIN(aCount, static_cast<uint64_t>(sizeof(tmpBuffer)));
        uint32_t read;

        nsresult rv = mAsyncStream->Read(tmpBuffer, minCount, &read);
        if (rv == NS_BASE_STREAM_CLOSED) {
          rv = NS_OK;
        }

        NS_ENSURE_SUCCESS(rv, rv);

        if (read == 0) {
          // The stream finished too early.
          return NS_ERROR_OUT_OF_MEMORY;
        }

        PopulateBufferForBinaryString(dest, tmpBuffer, read);

        dest += read;
        aCount -= read;
        bytesRead += read;
      }
    }

    MOZ_ASSERT(size.value() == oldLen + bytesRead);
    mResult.Truncate(size.value());
  }
  else {
    CheckedInt<uint64_t> size = mDataLen;
    size += aCount;

    //Update memory buffer to reflect the contents of the file
    if (!size.isValid() ||
        // PR_Realloc doesn't support over 4GB memory size even if 64-bit OS
        // XXX: it's likely that this check is unnecessary and the comment is
        // wrong because we no longer use PR_Realloc outside of NSPR and NSS.
        size.value() > UINT32_MAX ||
        size.value() > mTotal) {
      return NS_ERROR_OUT_OF_MEMORY;
    }

    MOZ_DIAGNOSTIC_ASSERT(mFileData);
    MOZ_RELEASE_ASSERT((mDataLen + aCount) <= mTotal);

    nsresult rv = mAsyncStream->Read(mFileData + mDataLen, aCount, &bytesRead);
    if (NS_WARN_IF(NS_FAILED(rv))) {
      return rv;
    }
  }

  mDataLen += bytesRead;
  return NS_OK;
}
Пример #19
0
void
LossyConvertEncoding16to8::write_vmx(const char16_t* aSource,
                                      uint32_t aSourceLength)
{
  char* dest = mDestination;

  // Align destination to a 16-byte boundary.
  // We must use unsigned datatypes because aSourceLength is unsigned.
  uint32_t i = 0;
  uint32_t alignLen = XPCOM_MIN(aSourceLength, uint32_t(-NS_PTR_TO_INT32(dest) & 0xf));
  // subtraction result can underflow if aSourceLength < alignLen!!!
  // check for underflow
  if (aSourceLength >= alignLen && aSourceLength - alignLen > 31) {
    for (; i < alignLen; i++) {
      dest[i] = static_cast<unsigned char>(aSource[i]);
    }

    // maxIndex can underflow if aSourceLength < 33!!!
    uint32_t maxIndex = aSourceLength - 33;

    // check for underflow
    if (maxIndex <= aSourceLength && i < maxIndex) {
      const char16_t *aOurSource = &aSource[i];
      char *aOurDest = &dest[i];
      register vector unsigned char packed1, packed2;
      register vector unsigned short source1, source2, source3, source4;
      if ((NS_PTR_TO_UINT32(aOurSource) & 15) == 0) {
        // Walk 64 bytes (four VMX registers) at a time.
        while (1) {
          source1 = vec_ld(0, (unsigned short *)aOurSource);
          source2 = vec_ld(16, (unsigned short *)aOurSource);
          source3 = vec_ld(32, (unsigned short *)aOurSource);
          source4 = vec_ld(48, (unsigned short *)aOurSource);
          packed1 = vec_packsu(source1, source2);
          packed2 = vec_packsu(source3, source4);
          vec_st(packed1, 0, (unsigned char *)aOurDest);
          vec_st(packed2, 16, (unsigned char *)aOurDest);
          i += 32;
          if(i > maxIndex)
           break;
          aOurDest += 32;
          aOurSource += 32;
        }
      }
      else {
        register vector unsigned char mask = vec_lvsl(0, (unsigned short *)aOurSource);
        register vector unsigned short vector1  = vec_ld(0, (unsigned short *)aOurSource);
        register vector unsigned short vector2;
        // Walk 64 bytes (four VMX registers) at a time.
        while (1) {
          LoadUnaligned(source1, 0, (unsigned short *)aOurSource, vector1, vector2, mask);
          LoadUnaligned(source2, 16, (unsigned short *)aOurSource, vector2, vector1, mask);
          LoadUnaligned(source3, 32, (unsigned short *)aOurSource, vector1, vector2, mask);
          LoadUnaligned(source4, 48, (unsigned short *)aOurSource, vector2, vector1, mask);
          packed1 = vec_packsu(source1, source2);
          packed2 = vec_packsu(source3, source4);
          vec_st(packed1, 0, (unsigned char *)aOurDest);
          vec_st(packed2, 16, (unsigned char *)aOurDest);
          i += 32;
          if(i > maxIndex)
            break;
          aOurDest += 32;
          aOurSource += 32;
        }
      }
    }
  }

  // Finish up the rest.
  for (; i < aSourceLength; i++) {
    dest[i] = static_cast<unsigned char>(aSource[i]);
  }

  mDestination += i;
}
Пример #20
0
  /**
   * this function is called to prepare mData for writing.  the given capacity
   * indicates the required minimum storage size for mData, in sizeof(char_type)
   * increments.  this function returns true if the operation succeeds.  it also
   * returns the old data and old flags members if mData is newly allocated.
   * the old data must be released by the caller.
   */
bool
nsTSubstring_CharT::MutatePrep( size_type capacity, char_type** oldData, uint32_t* oldFlags )
  {
    // initialize to no old data
    *oldData = nullptr;
    *oldFlags = 0;

    size_type curCapacity = Capacity();

    // If |capacity > kMaxCapacity|, then our doubling algorithm may not be
    // able to allocate it.  Just bail out in cases like that.  We don't want
    // to be allocating 2GB+ strings anyway.
    PR_STATIC_ASSERT((sizeof(nsStringBuffer) & 0x1) == 0);
    const size_type kMaxCapacity =
      (size_type(-1)/2 - sizeof(nsStringBuffer)) / sizeof(char_type) - 2;
    if (capacity > kMaxCapacity) {
      // Also assert for |capacity| equal to |size_type(-1)|, since we used to
      // use that value to flag immutability.
      NS_ASSERTION(capacity != size_type(-1), "Bogus capacity");
      return false;
    }

    // |curCapacity == 0| means that the buffer is immutable or 0-sized, so we
    // need to allocate a new buffer. We cannot use the existing buffer even
    // though it might be large enough.

    if (curCapacity != 0)
      {
        if (capacity <= curCapacity) {
          mFlags &= ~F_VOIDED;  // mutation clears voided flag
          return true;
        }

        // Use doubling algorithm when forced to increase available capacity.
        size_type temp = curCapacity;
        while (temp < capacity)
          temp <<= 1;
        NS_ASSERTION(XPCOM_MIN(temp, kMaxCapacity) >= capacity,
                     "should have hit the early return at the top");
        capacity = XPCOM_MIN(temp, kMaxCapacity);
      }

    //
    // several cases:
    //
    //  (1) we have a shared buffer (mFlags & F_SHARED)
    //  (2) we have an owned buffer (mFlags & F_OWNED)
    //  (3) we have a fixed buffer (mFlags & F_FIXED)
    //  (4) we have a readonly buffer
    //
    // requiring that we in some cases preserve the data before creating
    // a new buffer complicates things just a bit ;-)
    //

    size_type storageSize = (capacity + 1) * sizeof(char_type);

    // case #1
    if (mFlags & F_SHARED)
      {
        nsStringBuffer* hdr = nsStringBuffer::FromData(mData);
        if (!hdr->IsReadonly())
          {
            nsStringBuffer *newHdr = nsStringBuffer::Realloc(hdr, storageSize);
            if (!newHdr)
              return false; // out-of-memory (original header left intact)

            hdr = newHdr;
            mData = (char_type*) hdr->Data();
            mFlags &= ~F_VOIDED;  // mutation clears voided flag
            return true;
          }
      }

    char_type* newData;
    uint32_t newDataFlags;

      // if we have a fixed buffer of sufficient size, then use it.  this helps
      // avoid heap allocations.
    if ((mFlags & F_CLASS_FIXED) && (capacity < AsFixedString(this)->mFixedCapacity))
      {
        newData = AsFixedString(this)->mFixedBuf;
        newDataFlags = F_TERMINATED | F_FIXED;
      }
    else
      {
        // if we reach here then, we must allocate a new buffer.  we cannot
        // make use of our F_OWNED or F_FIXED buffers because they are not
        // large enough.

        nsStringBuffer* newHdr = nsStringBuffer::Alloc(storageSize);
        if (!newHdr)
          return false; // we are still in a consistent state

        newData = (char_type*) newHdr->Data();
        newDataFlags = F_TERMINATED | F_SHARED;
      }

    // save old data and flags
    *oldData = mData;
    *oldFlags = mFlags;

    mData = newData;
    SetDataFlags(newDataFlags);

    // mLength does not change

    // though we are not necessarily terminated at the moment, now is probably
    // still the best time to set F_TERMINATED.

    return true;
  }