// Reads over a boundary and sets start to the position after the end of the // boundary. Returns false if no boundary is found immediately. bool PushOverBoundary(const nsACString& aBoundaryString, nsACString::const_iterator& aStart, nsACString::const_iterator& aEnd) { // We copy the end iterator to keep the original pointing to the real end // of the string. nsACString::const_iterator end(aEnd); const char* beginning = aStart.get(); if (FindInReadable(aBoundaryString, aStart, end)) { // We either should find the body immediately, or after 2 chars with the // 2 chars being '-', everything else is failure. if ((aStart.get() - beginning) == 0) { aStart.advance(aBoundaryString.Length()); return true; } if ((aStart.get() - beginning) == 2) { if (*(--aStart) == '-' && *(--aStart) == '-') { aStart.advance(aBoundaryString.Length() + 2); return true; } } } return false; }
bool FindCharInReadable( char aChar, nsACString::const_iterator& aSearchStart, const nsACString::const_iterator& aSearchEnd ) { int32_t fragmentLength = aSearchEnd.get() - aSearchStart.get(); const char* charFoundAt = nsCharTraits<char>::find(aSearchStart.get(), fragmentLength, aChar); if ( charFoundAt ) { aSearchStart.advance( charFoundAt - aSearchStart.get() ); return true; } aSearchStart.advance(fragmentLength); return false; }
// static bool FetchUtil::ExtractHeader(nsACString::const_iterator& aStart, nsACString::const_iterator& aEnd, nsCString& aHeaderName, nsCString& aHeaderValue, bool* aWasEmptyHeader) { MOZ_ASSERT(aWasEmptyHeader); // Set it to a valid value here so we don't forget later. *aWasEmptyHeader = false; const char* beginning = aStart.get(); nsACString::const_iterator end(aEnd); if (!FindCRLF(aStart, end)) { return false; } if (aStart.get() == beginning) { *aWasEmptyHeader = true; return true; } nsAutoCString header(beginning, aStart.get() - beginning); nsACString::const_iterator headerStart, iter, headerEnd; header.BeginReading(headerStart); header.EndReading(headerEnd); iter = headerStart; if (!FindCharInReadable(':', iter, headerEnd)) { return false; } aHeaderName.Assign(StringHead(header, iter - headerStart)); aHeaderName.CompressWhitespace(); if (!NS_IsValidHTTPToken(aHeaderName)) { return false; } aHeaderValue.Assign(Substring(++iter, headerEnd)); if (!NS_IsReasonableHTTPHeaderValue(aHeaderValue)) { return false; } aHeaderValue.CompressWhitespace(); return PushOverLine(aStart, aEnd); }
inline PRBool nsSMILParserUtils::ParseMetricMultiplicand(nsACString::const_iterator& aSpec, const nsACString::const_iterator& aEnd, PRInt32& multiplicand) { PRBool result = PR_FALSE; size_t len = aEnd.get() - aSpec.get(); nsACString::const_iterator spec(aSpec); if (len) { switch (*spec++) { case 'h': multiplicand = MSEC_PER_HOUR; result = PR_TRUE; break; case 'm': if (len >= 2) { if (*spec == 's') { ++spec; multiplicand = 1; result = PR_TRUE; } else if (len >= 3 && *spec++ == 'i' && *spec++ == 'n') { multiplicand = MSEC_PER_MIN; result = PR_TRUE; } } break; case 's': multiplicand = MSEC_PER_SEC; result = PR_TRUE; break; } } if (result) { aSpec = spec; } return result; }
inline PRBool nsSMILParserUtils::ConsumeSubstring(nsACString::const_iterator& aIter, const nsACString::const_iterator& aIterEnd, const char *aSubstring) { size_t substrLen = PL_strlen(aSubstring); typedef nsACString::const_iterator::difference_type diff_type; if (aIterEnd.get() - aIter.get() < static_cast<diff_type>(substrLen)) return PR_FALSE; PRBool result = PR_FALSE; if (PL_strstr(aIter.get(), aSubstring) == aIter.get()) { aIter.advance(substrLen); result = PR_TRUE; } return result; }
PRBool nsSMILParserUtils::ParseClockComponent(nsACString::const_iterator& aSpec, const nsACString::const_iterator& aEnd, double& aResult, PRBool& aIsReal, PRBool& aCouldBeMin, PRBool& aCouldBeSec) { nsresult rv; char const *begin = aSpec.get(); double value = GetFloat(aSpec, aEnd, &rv); // Check a number was found if (NS_FAILED(rv)) return PR_FALSE; // Check it's not expressed in exponential form size_t len = aSpec.get() - begin; PRBool isExp = (PL_strnpbrk(begin, "eE", len) != nsnull); if (isExp) return PR_FALSE; // Don't allow real numbers of the form "23." if (*(aSpec.get() - 1) == '.') return PR_FALSE; // Number looks good aResult = value; // Set some flags so we can check this number is valid once we know // whether it's an hour, minute string etc. aIsReal = (PL_strnchr(begin, '.', len) != nsnull); aCouldBeMin = (value < 60.0 && (len == 2)); aCouldBeSec = (value < 60.0 || (value == 60.0 && begin[0] == '5')); // Take care of rounding error aCouldBeSec &= (len >= 2 && (begin[2] == '\0' || begin[2] == '.' || IsSpace(begin[2]))); return PR_TRUE; }
inline double nsSMILParserUtils::GetFloat(nsACString::const_iterator& aIter, const nsACString::const_iterator& aIterEnd, nsresult *aErrorCode) { char *end; const char *start = aIter.get(); double value = PR_strtod(start, &end); nsresult rv = NS_OK; if (end == start || end > aIterEnd.get()) { rv = NS_ERROR_FAILURE; } else { aIter.advance(end - start); } if (aErrorCode) { *aErrorCode = rv; } return value; }
// The end of a body is marked by a CRLF followed by the boundary. So the // CRLF is part of the boundary and not the body, but any prior CRLFs are // part of the body. This will position the iterator at the beginning of the // boundary (after the CRLF). bool ParseBody(const nsACString& aBoundaryString, nsACString::const_iterator& aStart, nsACString::const_iterator& aEnd) { const char* beginning = aStart.get(); // Find the boundary marking the end of the body. nsACString::const_iterator end(aEnd); if (!FindInReadable(aBoundaryString, aStart, end)) { return false; } // We found a boundary, strip the just prior CRLF, and consider // everything else the body section. if (aStart.get() - beginning < 2) { // Only the first entry can have a boundary right at the beginning. Even // an empty body will have a CRLF before the boundary. So this is // a failure. return false; } // Check that there is a CRLF right before the boundary. aStart.advance(-2); // Skip optional hyphens. if (*aStart == '-' && *(aStart.get()+1) == '-') { if (aStart.get() - beginning < 2) { return false; } aStart.advance(-2); } if (*aStart != nsCRT::CR || *(aStart.get()+1) != nsCRT::LF) { return false; } nsAutoCString body(beginning, aStart.get() - beginning); // Restore iterator to after the \r\n as we promised. // We do not need to handle the extra hyphens case since our boundary // parser in PushOverBoundary() aStart.advance(2); if (!mFormData) { mFormData = new nsFormData(); } NS_ConvertUTF8toUTF16 name(mName); if (mFilename.IsVoid()) { mFormData->Append(name, NS_ConvertUTF8toUTF16(body)); } else { // Unfortunately we've to copy the data first since all our strings are // going to free it. We also need fallible alloc, so we can't just use // ToNewCString(). char* copy = static_cast<char*>(moz_xmalloc(body.Length())); if (!copy) { NS_WARNING("Failed to copy File entry body."); return false; } nsCString::const_iterator bodyIter, bodyEnd; body.BeginReading(bodyIter); body.EndReading(bodyEnd); char *p = copy; while (bodyIter != bodyEnd) { *p++ = *bodyIter++; } p = nullptr; nsRefPtr<Blob> file = File::CreateMemoryFile(mParentObject, reinterpret_cast<void *>(copy), body.Length(), NS_ConvertUTF8toUTF16(mFilename), NS_ConvertUTF8toUTF16(mContentType), /* aLastModifiedDate */ 0); Optional<nsAString> dummy; mFormData->Append(name, *file, dummy); } return true; }
bool ParseHeader(nsACString::const_iterator& aStart, nsACString::const_iterator& aEnd, bool* aWasEmptyHeader) { MOZ_ASSERT(aWasEmptyHeader); // Set it to a valid value here so we don't forget later. *aWasEmptyHeader = false; const char* beginning = aStart.get(); nsACString::const_iterator end(aEnd); if (!FindCRLF(aStart, end)) { return false; } if (aStart.get() == beginning) { *aWasEmptyHeader = true; return true; } nsAutoCString header(beginning, aStart.get() - beginning); nsACString::const_iterator headerStart, headerEnd; header.BeginReading(headerStart); header.EndReading(headerEnd); if (!FindCharInReadable(':', headerStart, headerEnd)) { return false; } nsAutoCString headerName(StringHead(header, headerStart.size_backward())); headerName.CompressWhitespace(); if (!NS_IsValidHTTPToken(headerName)) { return false; } nsAutoCString headerValue(Substring(++headerStart, headerEnd)); if (!NS_IsReasonableHTTPHeaderValue(headerValue)) { return false; } headerValue.CompressWhitespace(); if (headerName.LowerCaseEqualsLiteral("content-disposition")) { nsCCharSeparatedTokenizer tokenizer(headerValue, ';'); bool seenFormData = false; while (tokenizer.hasMoreTokens()) { const nsDependentCSubstring& token = tokenizer.nextToken(); if (token.IsEmpty()) { continue; } if (token.EqualsLiteral("form-data")) { seenFormData = true; continue; } if (seenFormData && StringBeginsWith(token, NS_LITERAL_CSTRING("name="))) { mName = StringTail(token, token.Length() - 5); mName.Trim(" \""); continue; } if (seenFormData && StringBeginsWith(token, NS_LITERAL_CSTRING("filename="))) { mFilename = StringTail(token, token.Length() - 9); mFilename.Trim(" \""); continue; } } if (mName.IsVoid()) { // Could not parse a valid entry name. return false; } } else if (headerName.LowerCaseEqualsLiteral("content-type")) { mContentType = headerValue; } return true; }