// combine segments into a single string, returning the allocated string // (or NULL) while emptying the list char *combineContinuations(nsTArray<Continuation>& aArray) { // Sanity check if (aArray.Length() == 0) return NULL; // Get an upper bound for the length PRUint32 length = 0; for (PRUint32 i = 0; i < aArray.Length(); i++) { length += aArray[i].length; } // Allocate char *result = (char *) nsMemory::Alloc(length + 1); // Concatenate if (result) { *result = '\0'; for (PRUint32 i = 0; i < aArray.Length(); i++) { Continuation cont = aArray[i]; if (! cont.value) break; char *c = result + strlen(result); strncat(result, cont.value, cont.length); if (cont.needsPercentDecoding) { nsUnescape(c); } if (cont.wasQuotedString) { RemoveQuotedStringEscapes(c); } } // return null if empty value if (*result == '\0') { nsMemory::Free(result); result = NULL; } } else { // Handle OOM NS_WARNING("Out of memory\n"); } return result; }
// moved almost verbatim from mimehdrs.cpp // char * // MimeHeaders_get_parameter (const char *header_value, const char *parm_name, // char **charset, char **language) // // The format of these header lines is // <token> [ ';' <token> '=' <token-or-quoted-string> ]* NS_IMETHODIMP nsMIMEHeaderParamImpl::GetParameterInternal(const char *aHeaderValue, const char *aParamName, char **aCharset, char **aLang, char **aResult) { if (!aHeaderValue || !*aHeaderValue || !aResult) return NS_ERROR_INVALID_ARG; *aResult = nsnull; if (aCharset) *aCharset = nsnull; if (aLang) *aLang = nsnull; const char *str = aHeaderValue; // skip leading white space. for (; *str && nsCRT::IsAsciiSpace(*str); ++str) ; const char *start = str; // aParamName is empty. return the first (possibly) _unnamed_ 'parameter' // For instance, return 'inline' in the following case: // Content-Disposition: inline; filename=..... if (!aParamName || !*aParamName) { for (; *str && *str != ';' && !nsCRT::IsAsciiSpace(*str); ++str) ; if (str == start) return NS_ERROR_UNEXPECTED; *aResult = (char *) nsMemory::Clone(start, (str - start) + 1); NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY); (*aResult)[str - start] = '\0'; // null-terminate return NS_OK; } /* Skip forward to first ';' */ for (; *str && *str != ';' && *str != ','; ++str) ; if (*str) str++; /* Skip over following whitespace */ for (; *str && nsCRT::IsAsciiSpace(*str); ++str) ; // Some broken http servers just specify parameters // like 'filename' without specifying disposition // method. Rewind to the first non-white-space // character. if (!*str) str = start; // RFC2231 - The legitimate parm format can be: // A. title=ThisIsTitle // B. title*=us-ascii'en-us'This%20is%20wierd. // C. title*0*=us-ascii'en'This%20is%20wierd.%20We // title*1*=have%20to%20support%20this. // title*2="Else..." // D. title*0="Hey, what you think you are doing?" // title*1="There is no charset and lang info." PRInt32 paramLen = strlen(aParamName); while (*str) { const char *tokenStart = str; const char *tokenEnd = 0; const char *valueStart = str; const char *valueEnd = 0; PRBool seenEquals = PR_FALSE; NS_ASSERTION(!nsCRT::IsAsciiSpace(*str), "should be after whitespace."); // Skip forward to the end of this token. for (; *str && !nsCRT::IsAsciiSpace(*str) && *str != '=' && *str != ';'; str++) ; tokenEnd = str; // Skip over whitespace, '=', and whitespace while (nsCRT::IsAsciiSpace(*str)) ++str; if (*str == '=') { ++str; seenEquals = PR_TRUE; } while (nsCRT::IsAsciiSpace(*str)) ++str; PRBool needUnquote = PR_FALSE; if (*str != '"') { // The value is a token, not a quoted string. valueStart = str; for (valueEnd = str; *valueEnd && !nsCRT::IsAsciiSpace (*valueEnd) && *valueEnd != ';'; valueEnd++) ; str = valueEnd; } else { // The value is a quoted string. needUnquote = PR_TRUE; ++str; valueStart = str; for (valueEnd = str; *valueEnd; ++valueEnd) { if (*valueEnd == '\\') ++valueEnd; else if (*valueEnd == '"') break; } str = valueEnd + 1; } // See if this is the simplest case (case A above), // a 'single' line value with no charset and lang. // If so, copy it and return. if (tokenEnd - tokenStart == paramLen && seenEquals && !nsCRT::strncasecmp(tokenStart, aParamName, paramLen)) { // if the parameter spans across multiple lines we have to strip out the // line continuation -- jht 4/29/98 nsCAutoString tempStr(valueStart, valueEnd - valueStart); tempStr.StripChars("\r\n"); char *res = ToNewCString(tempStr); NS_ENSURE_TRUE(res, NS_ERROR_OUT_OF_MEMORY); if (needUnquote) RemoveQuotedStringEscapes(res); *aResult = res; // keep going, we may find a RFC 2231 encoded alternative } // case B, C, and D else if (tokenEnd - tokenStart > paramLen && !nsCRT::strncasecmp(tokenStart, aParamName, paramLen) && seenEquals && *(tokenStart + paramLen) == '*') { const char *cp = tokenStart + paramLen + 1; // 1st char pass '*' PRBool needUnescape = *(tokenEnd - 1) == '*'; // the 1st line of a multi-line parameter or a single line that needs // unescaping. ( title*0*= or title*= ) // only allowed for token form, not for quoted-string if (!needUnquote && ((*cp == '0' && needUnescape) || (tokenEnd - tokenStart == paramLen + 1))) { // look for single quotation mark(') const char *sQuote1 = PL_strchr(valueStart, 0x27); const char *sQuote2 = (char *) (sQuote1 ? PL_strchr(sQuote1 + 1, 0x27) : nsnull); // Two single quotation marks must be present even in // absence of charset and lang. if (!sQuote1 || !sQuote2) NS_WARNING("Mandatory two single quotes are missing in header parameter\n"); if (aCharset && sQuote1 > valueStart && sQuote1 < valueEnd) { *aCharset = (char *) nsMemory::Clone(valueStart, sQuote1 - valueStart + 1); if (*aCharset) *(*aCharset + (sQuote1 - valueStart)) = 0; } if (aLang && sQuote1 && sQuote2 && sQuote2 > sQuote1 + 1 && sQuote2 < valueEnd) { *aLang = (char *) nsMemory::Clone(sQuote1 + 1, sQuote2 - (sQuote1 + 1) + 1); if (*aLang) *(*aLang + (sQuote2 - (sQuote1 + 1))) = 0; } // Be generous and handle gracefully when required // single quotes are absent. if (sQuote1) { if(!sQuote2) sQuote2 = sQuote1; } else sQuote2 = valueStart - 1; if (sQuote2 && sQuote2 + 1 < valueEnd) { if (*aResult) { // drop non-2231-encoded value, instead prefer the one using // the RFC2231 encoding nsMemory::Free(*aResult); } *aResult = (char *) nsMemory::Alloc(valueEnd - (sQuote2 + 1) + 1); if (*aResult) { memcpy(*aResult, sQuote2 + 1, valueEnd - (sQuote2 + 1)); *(*aResult + (valueEnd - (sQuote2 + 1))) = 0; if (needUnescape) { nsUnescape(*aResult); if (tokenEnd - tokenStart == paramLen + 1) // we're done; this is case B return NS_OK; } } } } // end of if-block : title*0*= or title*= // a line of multiline param with no need for unescaping : title*[0-9]= // or 2nd or later lines of a multiline param : title*[1-9]*= else if (nsCRT::IsAsciiDigit(PRUnichar(*cp))) { PRInt32 len = 0; if (*aResult) // 2nd or later lines of multiline parameter { len = strlen(*aResult); char *ns = (char *) nsMemory::Realloc(*aResult, len + (valueEnd - valueStart) + 1); if (!ns) { nsMemory::Free(*aResult); } *aResult = ns; } else if (*cp == '0') // must be; 1st line : title*0= { *aResult = (char *) nsMemory::Alloc(valueEnd - valueStart + 1); } // else {} something is really wrong; out of memory if (*aResult) { // append a partial value memcpy(*aResult + len, valueStart, valueEnd - valueStart); *(*aResult + len + (valueEnd - valueStart)) = 0; if (needUnescape) nsUnescape(*aResult + len); } else return NS_ERROR_OUT_OF_MEMORY; } // end of if-block : title*[0-9]= or title*[1-9]*= } // str now points after the end of the value. // skip over whitespace, ';', whitespace. while (nsCRT::IsAsciiSpace(*str)) ++str; if (*str == ';') ++str; while (nsCRT::IsAsciiSpace(*str)) ++str; } if (*aResult) return NS_OK; else return NS_ERROR_INVALID_ARG; // aParameter not found !! }
nsresult nsMIMEHeaderParamImpl::DoParameterInternal(const char *aHeaderValue, const char *aParamName, ParamDecoding aDecoding, char **aCharset, char **aLang, char **aResult) { if (!aHeaderValue || !*aHeaderValue || !aResult) return NS_ERROR_INVALID_ARG; *aResult = nullptr; if (aCharset) *aCharset = nullptr; if (aLang) *aLang = nullptr; nsCAutoString charset; bool acceptContinuations = (aDecoding != RFC_5987_DECODING); const char *str = aHeaderValue; // skip leading white space. for (; *str && nsCRT::IsAsciiSpace(*str); ++str) ; const char *start = str; // aParamName is empty. return the first (possibly) _unnamed_ 'parameter' // For instance, return 'inline' in the following case: // Content-Disposition: inline; filename=..... if (!aParamName || !*aParamName) { for (; *str && *str != ';' && !nsCRT::IsAsciiSpace(*str); ++str) ; if (str == start) return NS_ERROR_FIRST_HEADER_FIELD_COMPONENT_EMPTY; *aResult = (char *) nsMemory::Clone(start, (str - start) + 1); NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY); (*aResult)[str - start] = '\0'; // null-terminate return NS_OK; } /* Skip forward to first ';' */ for (; *str && *str != ';' && *str != ','; ++str) ; if (*str) str++; /* Skip over following whitespace */ for (; *str && nsCRT::IsAsciiSpace(*str); ++str) ; // Some broken http servers just specify parameters // like 'filename' without specifying disposition // method. Rewind to the first non-white-space // character. if (!*str) str = start; // RFC2231 - The legitimate parm format can be: // A. title=ThisIsTitle // B. title*=us-ascii'en-us'This%20is%20wierd. // C. title*0*=us-ascii'en'This%20is%20wierd.%20We // title*1*=have%20to%20support%20this. // title*2="Else..." // D. title*0="Hey, what you think you are doing?" // title*1="There is no charset and lang info." // RFC5987: only A and B // collect results for the different algorithms (plain filename, // RFC5987/2231-encoded filename, + continuations) separately and decide // which to use at the end char *caseAResult = NULL; char *caseBResult = NULL; char *caseCDResult = NULL; // collect continuation segments nsTArray<Continuation> segments; // our copies of the charset parameter, kept separately as they might // differ for the two formats nsDependentCSubstring charsetB, charsetCD; nsDependentCSubstring lang; PRInt32 paramLen = strlen(aParamName); while (*str) { // find name/value const char *nameStart = str; const char *nameEnd = NULL; const char *valueStart = str; const char *valueEnd = NULL; bool isQuotedString = false; NS_ASSERTION(!nsCRT::IsAsciiSpace(*str), "should be after whitespace."); // Skip forward to the end of this token. for (; *str && !nsCRT::IsAsciiSpace(*str) && *str != '=' && *str != ';'; str++) ; nameEnd = str; PRInt32 nameLen = nameEnd - nameStart; // Skip over whitespace, '=', and whitespace while (nsCRT::IsAsciiSpace(*str)) ++str; if (!*str) { break; } if (*str++ != '=') { // don't accept parameters without "=" goto increment_str; } while (nsCRT::IsAsciiSpace(*str)) ++str; if (*str != '"') { // The value is a token, not a quoted string. valueStart = str; for (valueEnd = str; *valueEnd && !nsCRT::IsAsciiSpace (*valueEnd) && *valueEnd != ';'; valueEnd++) ; str = valueEnd; } else { isQuotedString = true; ++str; valueStart = str; for (valueEnd = str; *valueEnd; ++valueEnd) { if (*valueEnd == '\\') ++valueEnd; else if (*valueEnd == '"') break; } str = valueEnd; // *valueEnd != null means that *valueEnd is quote character. if (*valueEnd) str++; } // See if this is the simplest case (case A above), // a 'single' line value with no charset and lang. // If so, copy it and return. if (nameLen == paramLen && !nsCRT::strncasecmp(nameStart, aParamName, paramLen)) { if (caseAResult) { // we already have one caseA result, ignore subsequent ones goto increment_str; } // if the parameter spans across multiple lines we have to strip out the // line continuation -- jht 4/29/98 nsCAutoString tempStr(valueStart, valueEnd - valueStart); tempStr.StripChars("\r\n"); char *res = ToNewCString(tempStr); NS_ENSURE_TRUE(res, NS_ERROR_OUT_OF_MEMORY); if (isQuotedString) RemoveQuotedStringEscapes(res); caseAResult = res; // keep going, we may find a RFC 2231/5987 encoded alternative } // case B, C, and D else if (nameLen > paramLen && !nsCRT::strncasecmp(nameStart, aParamName, paramLen) && *(nameStart + paramLen) == '*') { // 1st char past '*' const char *cp = nameStart + paramLen + 1; // if param name ends in "*" we need do to RFC5987 "ext-value" decoding bool needExtDecoding = *(nameEnd - 1) == '*'; bool caseB = nameLen == paramLen + 1; bool caseCStart = (*cp == '0') && needExtDecoding; // parse the segment number PRInt32 segmentNumber = -1; if (!caseB) { PRInt32 segLen = (nameEnd - cp) - (needExtDecoding ? 1 : 0); segmentNumber = parseSegmentNumber(cp, segLen); if (segmentNumber == -1) { acceptContinuations = false; goto increment_str; } } // CaseB and start of CaseC: requires charset and optional language // in quotes (quotes required even if lang is blank) if (caseB || (caseCStart && acceptContinuations)) { // look for single quotation mark(') const char *sQuote1 = PL_strchr(valueStart, 0x27); const char *sQuote2 = sQuote1 ? PL_strchr(sQuote1 + 1, 0x27) : nullptr; // Two single quotation marks must be present even in // absence of charset and lang. if (!sQuote1 || !sQuote2) { NS_WARNING("Mandatory two single quotes are missing in header parameter\n"); } const char *charsetStart = NULL; PRInt32 charsetLength = 0; const char *langStart = NULL; PRInt32 langLength = 0; const char *rawValStart = NULL; PRInt32 rawValLength = 0; if (sQuote2 && sQuote1) { // both delimiters present: charSet'lang'rawVal rawValStart = sQuote2 + 1; rawValLength = valueEnd - rawValStart; langStart = sQuote1 + 1; langLength = sQuote2 - langStart; charsetStart = valueStart; charsetLength = sQuote1 - charsetStart; } else if (sQuote1) { // one delimiter; assume charset'rawVal rawValStart = sQuote1 + 1; rawValLength = valueEnd - rawValStart; charsetStart = valueStart; charsetLength = sQuote1 - valueStart; } else { // no delimiter: just rawVal rawValStart = valueStart; rawValLength = valueEnd - valueStart; } if (langLength != 0) { lang.Assign(langStart, langLength); } // keep the charset for later if (caseB) { charsetB.Assign(charsetStart, charsetLength); } else { // if caseCorD charsetCD.Assign(charsetStart, charsetLength); } // non-empty value part if (rawValLength > 0) { if (!caseBResult && caseB) { // allocate buffer for the raw value char *tmpResult = (char *) nsMemory::Clone(rawValStart, rawValLength + 1); if (!tmpResult) { goto increment_str; } *(tmpResult + rawValLength) = 0; nsUnescape(tmpResult); caseBResult = tmpResult; } else { // caseC bool added = addContinuation(segments, 0, rawValStart, rawValLength, needExtDecoding, isQuotedString); if (!added) { // continuation not added, stop processing them acceptContinuations = false; } } } } // end of if-block : title*0*= or title*= // caseD: a line of multiline param with no need for unescaping : title*[0-9]= // or 2nd or later lines of a caseC param : title*[1-9]*= else if (acceptContinuations && segmentNumber != -1) { PRUint32 valueLength = valueEnd - valueStart; bool added = addContinuation(segments, segmentNumber, valueStart, valueLength, needExtDecoding, isQuotedString); if (!added) { // continuation not added, stop processing them acceptContinuations = false; } } // end of if-block : title*[0-9]= or title*[1-9]*= } // str now points after the end of the value. // skip over whitespace, ';', whitespace. increment_str: while (nsCRT::IsAsciiSpace(*str)) ++str; if (*str == ';') { ++str; } else { // stop processing the header field; either we are done or the // separator was missing break; } while (nsCRT::IsAsciiSpace(*str)) ++str; } caseCDResult = combineContinuations(segments); if (caseBResult && !charsetB.IsEmpty()) { // check that the 2231/5987 result decodes properly given the // specified character set if (!IsValidOctetSequenceForCharset(charsetB, caseBResult)) caseBResult = NULL; } if (caseCDResult && !charsetCD.IsEmpty()) { // check that the 2231/5987 result decodes properly given the // specified character set if (!IsValidOctetSequenceForCharset(charsetCD, caseCDResult)) caseCDResult = NULL; } if (caseBResult) { // prefer simple 5987 format over 2231 with continuations *aResult = caseBResult; caseBResult = NULL; charset.Assign(charsetB); } else if (caseCDResult) { // prefer 2231/5987 with or without continuations over plain format *aResult = caseCDResult; caseCDResult = NULL; charset.Assign(charsetCD); } else if (caseAResult) { *aResult = caseAResult; caseAResult = NULL; } // free unused stuff nsMemory::Free(caseAResult); nsMemory::Free(caseBResult); nsMemory::Free(caseCDResult); // if we have a result if (*aResult) { // then return charset and lang as well if (aLang && !lang.IsEmpty()) { PRUint32 len = lang.Length(); *aLang = (char *) nsMemory::Clone(lang.BeginReading(), len + 1); if (*aLang) { *(*aLang + len) = 0; } } if (aCharset && !charset.IsEmpty()) { PRUint32 len = charset.Length(); *aCharset = (char *) nsMemory::Clone(charset.BeginReading(), len + 1); if (*aCharset) { *(*aCharset + len) = 0; } } } return *aResult ? NS_OK : NS_ERROR_INVALID_ARG; }
nsresult nsMIMEHeaderParamImpl::DoParameterInternal(const char *aHeaderValue, const char *aParamName, ParamDecoding aDecoding, char **aCharset, char **aLang, char **aResult) { if (!aHeaderValue || !*aHeaderValue || !aResult) return NS_ERROR_INVALID_ARG; *aResult = nsnull; if (aCharset) *aCharset = nsnull; if (aLang) *aLang = nsnull; const char *str = aHeaderValue; // skip leading white space. for (; *str && nsCRT::IsAsciiSpace(*str); ++str) ; const char *start = str; // aParamName is empty. return the first (possibly) _unnamed_ 'parameter' // For instance, return 'inline' in the following case: // Content-Disposition: inline; filename=..... if (!aParamName || !*aParamName) { for (; *str && *str != ';' && !nsCRT::IsAsciiSpace(*str); ++str) ; if (str == start) return NS_ERROR_FIRST_HEADER_FIELD_COMPONENT_EMPTY; *aResult = (char *) nsMemory::Clone(start, (str - start) + 1); NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY); (*aResult)[str - start] = '\0'; // null-terminate return NS_OK; } /* Skip forward to first ';' */ for (; *str && *str != ';' && *str != ','; ++str) ; if (*str) str++; /* Skip over following whitespace */ for (; *str && nsCRT::IsAsciiSpace(*str); ++str) ; // Some broken http servers just specify parameters // like 'filename' without specifying disposition // method. Rewind to the first non-white-space // character. if (!*str) str = start; // RFC2231 - The legitimate parm format can be: // A. title=ThisIsTitle // B. title*=us-ascii'en-us'This%20is%20wierd. // C. title*0*=us-ascii'en'This%20is%20wierd.%20We // title*1*=have%20to%20support%20this. // title*2="Else..." // D. title*0="Hey, what you think you are doing?" // title*1="There is no charset and lang info." // RFC5987: only A and B PRInt32 paramLen = strlen(aParamName); bool haveCaseAValue = false; PRInt32 nextContinuation = 0; // next value in series, or -1 if error while (*str) { const char *tokenStart = str; const char *tokenEnd = 0; const char *valueStart = str; const char *valueEnd = 0; bool seenEquals = false; NS_ASSERTION(!nsCRT::IsAsciiSpace(*str), "should be after whitespace."); // Skip forward to the end of this token. for (; *str && !nsCRT::IsAsciiSpace(*str) && *str != '=' && *str != ';'; str++) ; tokenEnd = str; // Skip over whitespace, '=', and whitespace while (nsCRT::IsAsciiSpace(*str)) ++str; if (*str == '=') { ++str; seenEquals = true; } while (nsCRT::IsAsciiSpace(*str)) ++str; bool needUnquote = false; if (*str != '"') { // The value is a token, not a quoted string. valueStart = str; for (valueEnd = str; *valueEnd && !nsCRT::IsAsciiSpace (*valueEnd) && *valueEnd != ';'; valueEnd++) ; str = valueEnd; } else { // The value is a quoted string. needUnquote = true; ++str; valueStart = str; for (valueEnd = str; *valueEnd; ++valueEnd) { if (*valueEnd == '\\') ++valueEnd; else if (*valueEnd == '"') break; } str = valueEnd + 1; } // See if this is the simplest case (case A above), // a 'single' line value with no charset and lang. // If so, copy it and return. if (tokenEnd - tokenStart == paramLen && seenEquals && !nsCRT::strncasecmp(tokenStart, aParamName, paramLen)) { if (*aResult) { // either seen earlier caseA value already--we prefer first--or caseA // came after a continuation: either way, prefer other value goto increment_str; } // if the parameter spans across multiple lines we have to strip out the // line continuation -- jht 4/29/98 nsCAutoString tempStr(valueStart, valueEnd - valueStart); tempStr.StripChars("\r\n"); char *res = ToNewCString(tempStr); NS_ENSURE_TRUE(res, NS_ERROR_OUT_OF_MEMORY); if (needUnquote) RemoveQuotedStringEscapes(res); *aResult = res; haveCaseAValue = true; // keep going, we may find a RFC 2231/5987 encoded alternative } // case B, C, and D else if (tokenEnd - tokenStart > paramLen && !nsCRT::strncasecmp(tokenStart, aParamName, paramLen) && seenEquals && *(tokenStart + paramLen) == '*') { const char *cp = tokenStart + paramLen + 1; // 1st char past '*' bool needUnescape = *(tokenEnd - 1) == '*'; bool caseB = (tokenEnd - tokenStart) == paramLen + 1; bool caseCorDStart = (*cp == '0') && needUnescape; bool acceptContinuations = (aDecoding != RFC_5987_DECODING); // CaseB and start of CaseC: requires charset and optional language // in quotes (quotes required even if lang is blank) if (caseB || (caseCorDStart && acceptContinuations)) { if (caseCorDStart) { if (nextContinuation++ != 0) { // error: already started a continuation. Skip future // continuations and return whatever initial parts were in order. nextContinuation = -1; goto increment_str; } } // look for single quotation mark(') const char *sQuote1 = PL_strchr(valueStart, 0x27); const char *sQuote2 = (char *) (sQuote1 ? PL_strchr(sQuote1 + 1, 0x27) : nsnull); // Two single quotation marks must be present even in // absence of charset and lang. if (!sQuote1 || !sQuote2) { // log the warning and skip to next parameter NS_WARNING("Mandatory two single quotes are missing in header parameter, parameter ignored\n"); goto increment_str; } // charset part is required if (! (sQuote1 > valueStart && sQuote1 < valueEnd)) { // log the warning and skip to next parameter NS_WARNING("Mandatory charset part missing in header parameter, parameter ignored\n"); goto increment_str; } if (aCharset) { *aCharset = (char *) nsMemory::Clone(valueStart, sQuote1 - valueStart + 1); if (*aCharset) *(*aCharset + (sQuote1 - valueStart)) = 0; } if (aLang && sQuote2 > sQuote1 + 1 && sQuote2 < valueEnd) { *aLang = (char *) nsMemory::Clone(sQuote1 + 1, sQuote2 - (sQuote1 + 1) + 1); if (*aLang) *(*aLang + (sQuote2 - (sQuote1 + 1))) = 0; } if (sQuote2 + 1 < valueEnd) { if (*aResult) { // caseA value already read, or caseC/D value already read // but we're now reading caseB: either way, drop old value nsMemory::Free(*aResult); haveCaseAValue = false; } *aResult = (char *) nsMemory::Alloc(valueEnd - (sQuote2 + 1) + 1); if (*aResult) { memcpy(*aResult, sQuote2 + 1, valueEnd - (sQuote2 + 1)); *(*aResult + (valueEnd - (sQuote2 + 1))) = 0; if (needUnescape) { nsUnescape(*aResult); if (caseB) return NS_OK; // caseB wins over everything else } } } } // end of if-block : title*0*= or title*= // caseD: a line of multiline param with no need for unescaping : title*[0-9]= // or 2nd or later lines of a caseC param : title*[1-9]*= else if (acceptContinuations && nsCRT::IsAsciiDigit(PRUnichar(*cp))) { PRInt32 nextSegment = atoi(cp); // no leading zeros allowed except for ... position 0 bool broken = nextSegment > 0 && *cp == '0'; if (broken || nextSegment != nextContinuation++) { // error: gap in continuation or unneccessary leading 0. // Skip future continuations and return whatever initial parts were // in order. nextContinuation = -1; goto increment_str; } if (haveCaseAValue && *aResult) { // drop caseA value nsMemory::Free(*aResult); *aResult = 0; haveCaseAValue = false; } PRInt32 len = 0; if (*aResult) // 2nd or later lines of multiline parameter { len = strlen(*aResult); char *ns = (char *) nsMemory::Realloc(*aResult, len + (valueEnd - valueStart) + 1); if (!ns) { nsMemory::Free(*aResult); } *aResult = ns; } else { NS_ASSERTION(*cp == '0', "Not first value in continuation"); // must be; 1st line : title*0= *aResult = (char *) nsMemory::Alloc(valueEnd - valueStart + 1); } if (*aResult) { // append a partial value memcpy(*aResult + len, valueStart, valueEnd - valueStart); *(*aResult + len + (valueEnd - valueStart)) = 0; if (needUnescape) nsUnescape(*aResult + len); } else return NS_ERROR_OUT_OF_MEMORY; } // end of if-block : title*[0-9]= or title*[1-9]*= } // str now points after the end of the value. // skip over whitespace, ';', whitespace. increment_str: while (nsCRT::IsAsciiSpace(*str)) ++str; if (*str == ';') ++str; while (nsCRT::IsAsciiSpace(*str)) ++str; } if (*aResult) return NS_OK; else return NS_ERROR_INVALID_ARG; // aParameter not found !! }