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); }
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; }
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); }
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; }
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; }
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; }
// 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; }
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; }
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); }
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); }
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; }
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; }
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; }
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; }
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); }
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);*/ }
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; }
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; }
/** * 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; }