Fixing rtm++ bug 56212. The new serializers were a bit too eager about what characters to encode as entities, this caused bad things when sending email that contained double quotes and also when writing a message containing quotes in AIM. sr=vidur, r=nisheeth.

This commit is contained in:
jst%netscape.com 2000-10-13 11:06:05 +00:00
parent 589e7d964c
commit bf199577e4
12 changed files with 330 additions and 70 deletions

View File

@ -390,22 +390,45 @@ ConvertAndWrite(nsAReadableString& aString,
NS_ENSURE_ARG_POINTER(aStream);
NS_ENSURE_ARG_POINTER(aEncoder);
nsresult rv;
PRInt32 charLength;
PRInt32 charLength, startCharLength;
const PRUnichar* unicodeBuf = (const PRUnichar*)nsPromiseFlatString(aString);
PRInt32 unicodeLength = aString.Length();
PRInt32 startLength = unicodeLength;
rv = aEncoder->GetMaxLength(unicodeBuf, unicodeLength, &charLength);
if (NS_SUCCEEDED(rv)) {
nsCAutoString charXferString;
charXferString.SetCapacity(charLength);
char* charXferBuf = (char*)charXferString.GetBuffer();
startCharLength = charLength;
NS_ENSURE_SUCCESS(rv, rv);
rv = aEncoder->Convert(unicodeBuf, &unicodeLength, charXferBuf, &charLength);
if (NS_SUCCEEDED(rv)) {
PRUint32 written;
rv = aStream->Write(charXferBuf, charLength, &written);
nsCAutoString charXferString;
charXferString.SetCapacity(charLength);
char* charXferBuf = (char*)charXferString.GetBuffer();
nsresult convert_rv = NS_OK;
do {
unicodeLength = startLength;
charLength = startCharLength;
convert_rv = aEncoder->Convert(unicodeBuf, &unicodeLength, charXferBuf, &charLength);
NS_ENSURE_SUCCESS(convert_rv, convert_rv);
PRUint32 written;
rv = aStream->Write(charXferBuf, charLength, &written);
NS_ENSURE_SUCCESS(rv, rv);
// If the converter couldn't convert a chraacer we replace the
// character with a characre entity.
if (convert_rv == NS_ERROR_UENC_NOMAPPING) {
nsCAutoString entString("&#");
entString.AppendInt(unicodeBuf[unicodeLength - 1]);
entString.Append(';');
rv = aStream->Write(entString.GetBuffer(), entString.Length(), &written);
NS_ENSURE_SUCCESS(rv, rv);
unicodeBuf += unicodeLength;
startLength -= unicodeLength;
}
}
} while (convert_rv == NS_ERROR_UENC_NOMAPPING);
return rv;
}

View File

@ -38,7 +38,6 @@
#include "nsEscape.h"
static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID);
static NS_DEFINE_CID(kEntityConverterCID, NS_ENTITYCONVERTER_CID);
#define kIndentStr NS_LITERAL_STRING(" ")
#define kMozStr "_moz"
@ -63,6 +62,7 @@ nsHTMLContentSerializer::nsHTMLContentSerializer()
mColPos = 0;
mIndent = 0;
mInBody = PR_FALSE;
mInScriptOrStyle = PR_FALSE;
}
nsHTMLContentSerializer::~nsHTMLContentSerializer()
@ -267,7 +267,12 @@ nsHTMLContentSerializer::AppendElementStart(nsIDOMElement *aElement,
AppendToString(mLineBreak, aStr);
mColPos = 0;
}
if ((name.get() == nsHTMLAtoms::script) ||
(name.get() == nsHTMLAtoms::style)) {
mInScriptOrStyle = PR_TRUE;
}
return NS_OK;
}
@ -296,7 +301,11 @@ nsHTMLContentSerializer::AppendElementEnd(nsIDOMElement *aElement,
nsCOMPtr<nsIParserService> parserService;
GetParserService(getter_AddRefs(parserService));
if (parserService) {
if ((name.get() == nsHTMLAtoms::script) ||
(name.get() == nsHTMLAtoms::style)) {
mInScriptOrStyle = PR_FALSE;
} else if (parserService) {
nsAutoString nameStr(sharedName);
PRBool isContainer;
PRInt32 id;
@ -444,6 +453,27 @@ nsHTMLContentSerializer::AppendToStringWrapped(const nsAReadableString& aStr,
}
}
static PRUint16 kGTVal = 62;
static const char* kEntities[] = {
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "amp", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"lt", "", "gt"
};
static const char* kAttrEntities[] = {
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "quot", "", "", "", "amp", "apos",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"lt", "", "gt"
};
void
nsHTMLContentSerializer::AppendToString(const nsAReadableString& aStr,
nsAWritableString& aOutputStr,
@ -457,17 +487,69 @@ nsHTMLContentSerializer::AppendToString(const nsAReadableString& aStr,
if (aIncrColumn) {
mColPos += aStr.Length();
}
if (aTranslateEntities) {
PRUnichar *encodedBuffer;
encodedBuffer = nsEscapeHTML2(nsPromiseFlatString(aStr), aStr.Length());
if (encodedBuffer) {
aOutputStr.Append(encodedBuffer);
nsCRT::free(encodedBuffer);
return;
if (aTranslateEntities && !mInScriptOrStyle) {
if (mFlags & nsIDocumentEncoder::OutputEncodeEntities) {
nsCOMPtr<nsIParserService> parserService;
GetParserService(getter_AddRefs(parserService));
if (!parserService) {
NS_ERROR("Can't get parser service");
return;
}
nsReadingIterator<PRUnichar> done_reading;
aStr.EndReading(done_reading);
// for each chunk of |aString|...
PRUint32 advanceLength = 0;
nsReadingIterator<PRUnichar> iter;
const char **entityTable = mInAttribute ? kAttrEntities : kEntities;
for (aStr.BeginReading(iter);
iter != done_reading;
iter.advance(PRInt32(advanceLength))) {
PRUint32 fragmentLength = iter.size_forward();
const PRUnichar* c = iter.get();
const PRUnichar* fragmentStart = c;
const PRUnichar* fragmentEnd = c + fragmentLength;
const char* entityText = nsnull;
nsCAutoString entityReplacement;
advanceLength = 0;
// for each character in this chunk, check if it
// needs to be replaced
for (; c < fragmentEnd; c++, advanceLength++) {
PRUnichar val = *c;
if ((val <= kGTVal) && (entityTable[val][0] != 0)) {
entityText = entityTable[val];
break;
} else if (val > 127) {
parserService->HTMLConvertUnicodeToEntity(val, entityReplacement);
if (entityReplacement.Length() > 0) {
entityText = entityReplacement.GetBuffer();
break;
}
}
}
aOutputStr.Append(fragmentStart, advanceLength);
if (entityText) {
aOutputStr.Append(PRUnichar('&'));
aOutputStr.Append(NS_ConvertASCIItoUCS2(entityText));
aOutputStr.Append(PRUnichar(';'));
advanceLength++;
}
}
} else {
nsXMLContentSerializer::AppendToString(aStr, aOutputStr, aTranslateEntities, aIncrColumn);
}
return;
}
aOutputStr.Append(aStr);
}

View File

@ -89,6 +89,7 @@ class nsHTMLContentSerializer : public nsXMLContentSerializer {
PRBool mDoHeader;
PRBool mBodyOnly;
PRInt32 mPreLevel;
PRBool mInScriptOrStyle;
PRInt32 mMaxColumn;

View File

@ -56,6 +56,7 @@ nsXMLContentSerializer::nsXMLContentSerializer()
{
NS_INIT_ISUPPORTS();
mPrefixIndex = 0;
mInAttribute = PR_FALSE;
}
nsXMLContentSerializer::~nsXMLContentSerializer()
@ -219,16 +220,19 @@ nsXMLContentSerializer::AppendDoctype(nsIDOMDocumentType *aDoctype,
AppendToString(quote, aStr);
AppendToString(publicId, aStr);
AppendToString(quote, aStr);
AppendToString(PRUnichar(' '), aStr);
if (systemId.FindChar(PRUnichar('"')) == -1) {
quote = PRUnichar('"');
if (systemId.Length()) {
AppendToString(PRUnichar(' '), aStr);
if (systemId.FindChar(PRUnichar('"')) == -1) {
quote = PRUnichar('"');
}
else {
quote = PRUnichar('\'');
}
AppendToString(quote, aStr);
AppendToString(systemId, aStr);
AppendToString(quote, aStr);
}
else {
quote = PRUnichar('\'');
}
AppendToString(quote, aStr);
AppendToString(systemId, aStr);
AppendToString(quote, aStr);
}
else if (systemId.Length() > 0) {
if (systemId.FindChar(PRUnichar('"')) == -1) {
@ -363,7 +367,11 @@ nsXMLContentSerializer::SerializeAttr(const nsAReadableString& aPrefix,
AppendToString(aName, aStr);
AppendToString(NS_LITERAL_STRING("=\""), aStr);
mInAttribute = PR_TRUE;
AppendToString(aValue, aStr, PR_TRUE);
mInAttribute = PR_FALSE;
AppendToString(NS_LITERAL_STRING("\""), aStr);
}
@ -528,6 +536,16 @@ nsXMLContentSerializer::AppendToString(const PRUnichar aChar,
static PRUint16 kGTVal = 62;
static const char* kEntities[] = {
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "&amp;", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"&lt;", "", "&gt;"
};
static const char* kAttrEntities[] = {
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
@ -550,7 +568,9 @@ nsXMLContentSerializer::AppendToString(const nsAReadableString& aStr,
// for each chunk of |aString|...
PRUint32 advanceLength = 0;
nsReadingIterator<PRUnichar> iter;
const char **entityTable = mInAttribute ? kAttrEntities : kEntities;
for (aStr.BeginReading(iter);
iter != done_reading;
iter.advance(PRInt32(advanceLength))) {
@ -560,12 +580,13 @@ nsXMLContentSerializer::AppendToString(const nsAReadableString& aStr,
const PRUnichar* fragmentEnd = c + fragmentLength;
const char* entityText = nsnull;
advanceLength = 0;
// for each character in this chunk, check if it
// needs to be replaced
for (; c < fragmentEnd; c++, advanceLength++) {
PRUnichar val = *c;
if ((val <= kGTVal) && (kEntities[val][0] != 0)) {
entityText = kEntities[val];
if ((val <= kGTVal) && (entityTable[val][0] != 0)) {
entityText = entityTable[val];
break;
}
}
@ -576,6 +597,8 @@ nsXMLContentSerializer::AppendToString(const nsAReadableString& aStr,
advanceLength++;
}
}
return;
}
aOutputStr.Append(aStr);

View File

@ -94,6 +94,7 @@ class nsXMLContentSerializer : public nsIContentSerializer {
PRInt32 mPrefixIndex;
nsVoidArray mNameSpaceStack;
PRBool mInAttribute;
};
extern nsresult NS_NewXMLContentSerializer(nsIContentSerializer** aSerializer);

View File

@ -1604,7 +1604,7 @@ nsEditor::SaveFile(nsFileSpec *aFileSpec, PRBool aReplaceExisting,
return NS_ERROR_NO_INTERFACE;
// Should we prettyprint?
PRUint32 flags = 0;
PRUint32 flags = nsIDocumentEncoder::OutputEncodeEntities;
NS_WITH_SERVICE(nsIPref, prefService, kPrefServiceCID, &rv);
if (NS_SUCCEEDED(rv) && prefService)
{

View File

@ -1604,7 +1604,7 @@ nsEditor::SaveFile(nsFileSpec *aFileSpec, PRBool aReplaceExisting,
return NS_ERROR_NO_INTERFACE;
// Should we prettyprint?
PRUint32 flags = 0;
PRUint32 flags = nsIDocumentEncoder::OutputEncodeEntities;
NS_WITH_SERVICE(nsIPref, prefService, kPrefServiceCID, &rv);
if (NS_SUCCEEDED(rv) && prefService)
{

View File

@ -390,22 +390,45 @@ ConvertAndWrite(nsAReadableString& aString,
NS_ENSURE_ARG_POINTER(aStream);
NS_ENSURE_ARG_POINTER(aEncoder);
nsresult rv;
PRInt32 charLength;
PRInt32 charLength, startCharLength;
const PRUnichar* unicodeBuf = (const PRUnichar*)nsPromiseFlatString(aString);
PRInt32 unicodeLength = aString.Length();
PRInt32 startLength = unicodeLength;
rv = aEncoder->GetMaxLength(unicodeBuf, unicodeLength, &charLength);
if (NS_SUCCEEDED(rv)) {
nsCAutoString charXferString;
charXferString.SetCapacity(charLength);
char* charXferBuf = (char*)charXferString.GetBuffer();
startCharLength = charLength;
NS_ENSURE_SUCCESS(rv, rv);
rv = aEncoder->Convert(unicodeBuf, &unicodeLength, charXferBuf, &charLength);
if (NS_SUCCEEDED(rv)) {
PRUint32 written;
rv = aStream->Write(charXferBuf, charLength, &written);
nsCAutoString charXferString;
charXferString.SetCapacity(charLength);
char* charXferBuf = (char*)charXferString.GetBuffer();
nsresult convert_rv = NS_OK;
do {
unicodeLength = startLength;
charLength = startCharLength;
convert_rv = aEncoder->Convert(unicodeBuf, &unicodeLength, charXferBuf, &charLength);
NS_ENSURE_SUCCESS(convert_rv, convert_rv);
PRUint32 written;
rv = aStream->Write(charXferBuf, charLength, &written);
NS_ENSURE_SUCCESS(rv, rv);
// If the converter couldn't convert a chraacer we replace the
// character with a characre entity.
if (convert_rv == NS_ERROR_UENC_NOMAPPING) {
nsCAutoString entString("&#");
entString.AppendInt(unicodeBuf[unicodeLength - 1]);
entString.Append(';');
rv = aStream->Write(entString.GetBuffer(), entString.Length(), &written);
NS_ENSURE_SUCCESS(rv, rv);
unicodeBuf += unicodeLength;
startLength -= unicodeLength;
}
}
} while (convert_rv == NS_ERROR_UENC_NOMAPPING);
return rv;
}

View File

@ -38,7 +38,6 @@
#include "nsEscape.h"
static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID);
static NS_DEFINE_CID(kEntityConverterCID, NS_ENTITYCONVERTER_CID);
#define kIndentStr NS_LITERAL_STRING(" ")
#define kMozStr "_moz"
@ -63,6 +62,7 @@ nsHTMLContentSerializer::nsHTMLContentSerializer()
mColPos = 0;
mIndent = 0;
mInBody = PR_FALSE;
mInScriptOrStyle = PR_FALSE;
}
nsHTMLContentSerializer::~nsHTMLContentSerializer()
@ -267,7 +267,12 @@ nsHTMLContentSerializer::AppendElementStart(nsIDOMElement *aElement,
AppendToString(mLineBreak, aStr);
mColPos = 0;
}
if ((name.get() == nsHTMLAtoms::script) ||
(name.get() == nsHTMLAtoms::style)) {
mInScriptOrStyle = PR_TRUE;
}
return NS_OK;
}
@ -296,7 +301,11 @@ nsHTMLContentSerializer::AppendElementEnd(nsIDOMElement *aElement,
nsCOMPtr<nsIParserService> parserService;
GetParserService(getter_AddRefs(parserService));
if (parserService) {
if ((name.get() == nsHTMLAtoms::script) ||
(name.get() == nsHTMLAtoms::style)) {
mInScriptOrStyle = PR_FALSE;
} else if (parserService) {
nsAutoString nameStr(sharedName);
PRBool isContainer;
PRInt32 id;
@ -444,6 +453,27 @@ nsHTMLContentSerializer::AppendToStringWrapped(const nsAReadableString& aStr,
}
}
static PRUint16 kGTVal = 62;
static const char* kEntities[] = {
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "amp", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"lt", "", "gt"
};
static const char* kAttrEntities[] = {
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "quot", "", "", "", "amp", "apos",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"lt", "", "gt"
};
void
nsHTMLContentSerializer::AppendToString(const nsAReadableString& aStr,
nsAWritableString& aOutputStr,
@ -457,17 +487,69 @@ nsHTMLContentSerializer::AppendToString(const nsAReadableString& aStr,
if (aIncrColumn) {
mColPos += aStr.Length();
}
if (aTranslateEntities) {
PRUnichar *encodedBuffer;
encodedBuffer = nsEscapeHTML2(nsPromiseFlatString(aStr), aStr.Length());
if (encodedBuffer) {
aOutputStr.Append(encodedBuffer);
nsCRT::free(encodedBuffer);
return;
if (aTranslateEntities && !mInScriptOrStyle) {
if (mFlags & nsIDocumentEncoder::OutputEncodeEntities) {
nsCOMPtr<nsIParserService> parserService;
GetParserService(getter_AddRefs(parserService));
if (!parserService) {
NS_ERROR("Can't get parser service");
return;
}
nsReadingIterator<PRUnichar> done_reading;
aStr.EndReading(done_reading);
// for each chunk of |aString|...
PRUint32 advanceLength = 0;
nsReadingIterator<PRUnichar> iter;
const char **entityTable = mInAttribute ? kAttrEntities : kEntities;
for (aStr.BeginReading(iter);
iter != done_reading;
iter.advance(PRInt32(advanceLength))) {
PRUint32 fragmentLength = iter.size_forward();
const PRUnichar* c = iter.get();
const PRUnichar* fragmentStart = c;
const PRUnichar* fragmentEnd = c + fragmentLength;
const char* entityText = nsnull;
nsCAutoString entityReplacement;
advanceLength = 0;
// for each character in this chunk, check if it
// needs to be replaced
for (; c < fragmentEnd; c++, advanceLength++) {
PRUnichar val = *c;
if ((val <= kGTVal) && (entityTable[val][0] != 0)) {
entityText = entityTable[val];
break;
} else if (val > 127) {
parserService->HTMLConvertUnicodeToEntity(val, entityReplacement);
if (entityReplacement.Length() > 0) {
entityText = entityReplacement.GetBuffer();
break;
}
}
}
aOutputStr.Append(fragmentStart, advanceLength);
if (entityText) {
aOutputStr.Append(PRUnichar('&'));
aOutputStr.Append(NS_ConvertASCIItoUCS2(entityText));
aOutputStr.Append(PRUnichar(';'));
advanceLength++;
}
}
} else {
nsXMLContentSerializer::AppendToString(aStr, aOutputStr, aTranslateEntities, aIncrColumn);
}
return;
}
aOutputStr.Append(aStr);
}

View File

@ -89,6 +89,7 @@ class nsHTMLContentSerializer : public nsXMLContentSerializer {
PRBool mDoHeader;
PRBool mBodyOnly;
PRInt32 mPreLevel;
PRBool mInScriptOrStyle;
PRInt32 mMaxColumn;

View File

@ -56,6 +56,7 @@ nsXMLContentSerializer::nsXMLContentSerializer()
{
NS_INIT_ISUPPORTS();
mPrefixIndex = 0;
mInAttribute = PR_FALSE;
}
nsXMLContentSerializer::~nsXMLContentSerializer()
@ -219,16 +220,19 @@ nsXMLContentSerializer::AppendDoctype(nsIDOMDocumentType *aDoctype,
AppendToString(quote, aStr);
AppendToString(publicId, aStr);
AppendToString(quote, aStr);
AppendToString(PRUnichar(' '), aStr);
if (systemId.FindChar(PRUnichar('"')) == -1) {
quote = PRUnichar('"');
if (systemId.Length()) {
AppendToString(PRUnichar(' '), aStr);
if (systemId.FindChar(PRUnichar('"')) == -1) {
quote = PRUnichar('"');
}
else {
quote = PRUnichar('\'');
}
AppendToString(quote, aStr);
AppendToString(systemId, aStr);
AppendToString(quote, aStr);
}
else {
quote = PRUnichar('\'');
}
AppendToString(quote, aStr);
AppendToString(systemId, aStr);
AppendToString(quote, aStr);
}
else if (systemId.Length() > 0) {
if (systemId.FindChar(PRUnichar('"')) == -1) {
@ -363,7 +367,11 @@ nsXMLContentSerializer::SerializeAttr(const nsAReadableString& aPrefix,
AppendToString(aName, aStr);
AppendToString(NS_LITERAL_STRING("=\""), aStr);
mInAttribute = PR_TRUE;
AppendToString(aValue, aStr, PR_TRUE);
mInAttribute = PR_FALSE;
AppendToString(NS_LITERAL_STRING("\""), aStr);
}
@ -528,6 +536,16 @@ nsXMLContentSerializer::AppendToString(const PRUnichar aChar,
static PRUint16 kGTVal = 62;
static const char* kEntities[] = {
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "&amp;", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"&lt;", "", "&gt;"
};
static const char* kAttrEntities[] = {
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
@ -550,7 +568,9 @@ nsXMLContentSerializer::AppendToString(const nsAReadableString& aStr,
// for each chunk of |aString|...
PRUint32 advanceLength = 0;
nsReadingIterator<PRUnichar> iter;
const char **entityTable = mInAttribute ? kAttrEntities : kEntities;
for (aStr.BeginReading(iter);
iter != done_reading;
iter.advance(PRInt32(advanceLength))) {
@ -560,12 +580,13 @@ nsXMLContentSerializer::AppendToString(const nsAReadableString& aStr,
const PRUnichar* fragmentEnd = c + fragmentLength;
const char* entityText = nsnull;
advanceLength = 0;
// for each character in this chunk, check if it
// needs to be replaced
for (; c < fragmentEnd; c++, advanceLength++) {
PRUnichar val = *c;
if ((val <= kGTVal) && (kEntities[val][0] != 0)) {
entityText = kEntities[val];
if ((val <= kGTVal) && (entityTable[val][0] != 0)) {
entityText = entityTable[val];
break;
}
}
@ -576,6 +597,8 @@ nsXMLContentSerializer::AppendToString(const nsAReadableString& aStr,
advanceLength++;
}
}
return;
}
aOutputStr.Append(aStr);

View File

@ -94,6 +94,7 @@ class nsXMLContentSerializer : public nsIContentSerializer {
PRInt32 mPrefixIndex;
nsVoidArray mNameSpaceStack;
PRBool mInAttribute;
};
extern nsresult NS_NewXMLContentSerializer(nsIContentSerializer** aSerializer);