1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=2 et tw=78: */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is Mozilla Communicator client code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsLoggingSink.h"
40 #include "nsHTMLTags.h"
42 #include "nsReadableUtils.h"
46 static NS_DEFINE_IID(kIContentSinkIID
, NS_ICONTENT_SINK_IID
);
47 static NS_DEFINE_IID(kIHTMLContentSinkIID
, NS_IHTML_CONTENT_SINK_IID
);
48 static NS_DEFINE_IID(kILoggingSinkIID
, NS_ILOGGING_SINK_IID
);
49 static NS_DEFINE_IID(kISupportsIID
, NS_ISUPPORTS_IID
);
52 NS_NewHTMLLoggingSink(nsIContentSink
** aInstancePtrResult
)
54 NS_PRECONDITION(nsnull
!= aInstancePtrResult
, "null ptr");
55 if (nsnull
== aInstancePtrResult
) {
56 return NS_ERROR_NULL_POINTER
;
58 nsLoggingSink
* it
= new nsLoggingSink();
60 return NS_ERROR_OUT_OF_MEMORY
;
62 return it
->QueryInterface(kIContentSinkIID
, (void**) aInstancePtrResult
);
65 nsLoggingSink::nsLoggingSink() {
72 nsLoggingSink::~nsLoggingSink() {
74 if(mOutput
&& mAutoDeleteOutput
) {
80 NS_IMPL_ISUPPORTS3(nsLoggingSink
, nsILoggingSink
, nsIContentSink
, nsIHTMLContentSink
)
83 nsLoggingSink::SetOutputStream(PRFileDesc
*aStream
,PRBool autoDeleteOutput
) {
85 mAutoDeleteOutput
=autoDeleteOutput
;
90 void WriteTabs(PRFileDesc
* out
,int aTabCount
) {
92 for(tabs
=0;tabs
<aTabCount
;++tabs
)
97 nsLoggingSink::WillParse() {
102 nsLoggingSink::WillBuildModel() {
104 WriteTabs(mOutput
,++mLevel
);
105 PR_fprintf(mOutput
, "<begin>\n");
107 //proxy the call to the real sink if you have one.
109 mSink
->WillBuildModel();
116 nsLoggingSink::DidBuildModel() {
118 WriteTabs(mOutput
,--mLevel
);
119 PR_fprintf(mOutput
, "</begin>\n");
121 //proxy the call to the real sink if you have one.
122 nsresult theResult
=NS_OK
;
124 theResult
=mSink
->DidBuildModel();
131 nsLoggingSink::WillInterrupt() {
132 nsresult theResult
=NS_OK
;
134 //proxy the call to the real sink if you have one.
136 theResult
=mSink
->WillInterrupt();
143 nsLoggingSink::WillResume() {
144 nsresult theResult
=NS_OK
;
146 //proxy the call to the real sink if you have one.
148 theResult
=mSink
->WillResume();
155 nsLoggingSink::SetParser(nsIParser
* aParser
) {
156 nsresult theResult
=NS_OK
;
158 //proxy the call to the real sink if you have one.
160 theResult
=mSink
->SetParser(aParser
);
163 NS_IF_RELEASE(mParser
);
167 NS_IF_ADDREF(mParser
);
173 nsLoggingSink::OpenContainer(const nsIParserNode
& aNode
) {
175 OpenNode("container", aNode
); //do the real logging work...
177 nsresult theResult
=NS_OK
;
179 //then proxy the call to the real sink if you have one.
181 theResult
=mSink
->OpenContainer(aNode
);
189 nsLoggingSink::CloseContainer(const nsHTMLTag aTag
) {
191 nsresult theResult
=NS_OK
;
193 nsHTMLTag nodeType
= nsHTMLTag(aTag
);
194 if ((nodeType
>= eHTMLTag_unknown
) &&
195 (nodeType
<= nsHTMLTag(NS_HTML_TAG_MAX
))) {
196 const PRUnichar
* tag
= nsHTMLTags::GetStringValue(nodeType
);
197 theResult
= CloseNode(NS_ConvertUTF16toUTF8(tag
).get());
199 else theResult
= CloseNode("???");
201 //then proxy the call to the real sink if you have one.
203 theResult
=mSink
->CloseContainer(aTag
);
211 nsLoggingSink::AddLeaf(const nsIParserNode
& aNode
) {
214 nsresult theResult
=NS_OK
;
216 //then proxy the call to the real sink if you have one.
218 theResult
=mSink
->AddLeaf(aNode
);
226 * This gets called by the parser when you want to add
227 * a PI node to the current container in the content
230 * @updated gess 3/25/98
235 nsLoggingSink::AddProcessingInstruction(const nsIParserNode
& aNode
){
238 DebugDump("<",aNode
.GetText(),(mNodeStackPos
)*2);
241 nsresult theResult
=NS_OK
;
243 //then proxy the call to the real sink if you have one.
245 theResult
=mSink
->AddProcessingInstruction(aNode
);
252 * This gets called by the parser when it encounters
253 * a DOCTYPE declaration in the HTML document.
257 nsLoggingSink::AddDocTypeDecl(const nsIParserNode
& aNode
) {
260 DebugDump("<",aNode
.GetText(),(mNodeStackPos
)*2);
263 nsresult theResult
=NS_OK
;
265 //then proxy the call to the real sink if you have one.
267 theResult
=mSink
->AddDocTypeDecl(aNode
);
275 * This gets called by the parser when you want to add
276 * a comment node to the current container in the content
279 * @updated gess 3/25/98
284 nsLoggingSink::AddComment(const nsIParserNode
& aNode
){
287 DebugDump("<",aNode
.GetText(),(mNodeStackPos
)*2);
290 nsresult theResult
=NS_OK
;
292 //then proxy the call to the real sink if you have one.
294 theResult
=mSink
->AddComment(aNode
);
302 nsLoggingSink::OpenHead() {
303 WriteTabs(mOutput
,++mLevel
);
304 PR_fprintf(mOutput
,"<open container=head>\n");
306 nsresult theResult
=NS_OK
;
308 //then proxy the call to the real sink if you have one.
310 theResult
=mSink
->OpenHead();
317 nsLoggingSink::OpenNode(const char* aKind
, const nsIParserNode
& aNode
) {
318 WriteTabs(mOutput
,++mLevel
);
320 PR_fprintf(mOutput
,"<open container=");
322 nsHTMLTag nodeType
= nsHTMLTag(aNode
.GetNodeType());
323 if ((nodeType
>= eHTMLTag_unknown
) &&
324 (nodeType
<= nsHTMLTag(NS_HTML_TAG_MAX
))) {
325 const PRUnichar
* tag
= nsHTMLTags::GetStringValue(nodeType
);
326 PR_fprintf(mOutput
, "\"%s\"", NS_ConvertUTF16toUTF8(tag
).get());
330 GetNewCString(aNode
.GetText(), &text
);
332 PR_fprintf(mOutput
, "\"%s\"", text
);
333 nsMemory::Free(text
);
337 if (WillWriteAttributes(aNode
)) {
338 PR_fprintf(mOutput
, ">\n");
339 WriteAttributes(aNode
);
340 PR_fprintf(mOutput
, "</open>\n");
343 PR_fprintf(mOutput
, ">\n");
350 nsLoggingSink::CloseNode(const char* aKind
) {
351 WriteTabs(mOutput
,mLevel
--);
352 PR_fprintf(mOutput
, "<close container=\"%s\">\n", aKind
);
358 nsLoggingSink::WriteAttributes(const nsIParserNode
& aNode
) {
360 WriteTabs(mOutput
,1+mLevel
);
362 PRInt32 ac
= aNode
.GetAttributeCount();
363 for (PRInt32 i
= 0; i
< ac
; ++i
) {
366 const nsAString
& k
= aNode
.GetKeyAt(i
);
367 const nsAString
& v
= aNode
.GetValueAt(i
);
369 GetNewCString(k
, &key
);
371 PR_fprintf(mOutput
, " <attr key=\"%s\" value=\"", key
);
378 PRUnichar first
= tmp
.First();
379 if ((first
== '"') || (first
== '\'')) {
380 if (tmp
.Last() == first
) {
382 PRInt32 pos
= tmp
.Length() - 1;
387 // Mismatched quotes - leave them in
390 GetNewCString(tmp
, &value
);
393 PR_fprintf(mOutput
, "%s\"/>\n", value
);
394 WriteTabs(mOutput
,1+mLevel
);
395 nsMemory::Free(value
);
400 WriteTabs(mOutput
,1+mLevel
);
405 nsLoggingSink::WillWriteAttributes(const nsIParserNode
& aNode
)
407 PRInt32 ac
= aNode
.GetAttributeCount();
415 nsLoggingSink::LeafNode(const nsIParserNode
& aNode
)
417 WriteTabs(mOutput
,1+mLevel
);
418 nsHTMLTag nodeType
= nsHTMLTag(aNode
.GetNodeType());
420 if ((nodeType
>= eHTMLTag_unknown
) &&
421 (nodeType
<= nsHTMLTag(NS_HTML_TAG_MAX
))) {
422 const PRUnichar
* tag
= nsHTMLTags::GetStringValue(nodeType
);
425 PR_fprintf(mOutput
, "<leaf tag=\"%s\"", NS_ConvertUTF16toUTF8(tag
).get());
427 PR_fprintf(mOutput
, "<leaf tag=\"???\"");
429 if (WillWriteAttributes(aNode
)) {
430 PR_fprintf(mOutput
, ">\n");
431 WriteAttributes(aNode
);
432 PR_fprintf(mOutput
, "</leaf>\n");
435 PR_fprintf(mOutput
, "/>\n");
443 case eHTMLTag_whitespace
:
445 GetNewCString(aNode
.GetText(), &str
);
447 PR_fprintf(mOutput
, "<text value=\"%s\"/>\n", str
);
452 case eHTMLTag_newline
:
453 PR_fprintf(mOutput
, "<newline/>\n");
456 case eHTMLTag_entity
:
457 tmp
.Append(aNode
.GetText());
459 pos
= tmp
.Length() - 1;
463 PR_fprintf(mOutput
, "<entity value=\"%s\"/>\n", NS_LossyConvertUTF16toASCII(tmp
).get());
467 NS_NOTREACHED("unsupported leaf node type");
474 nsLoggingSink::QuoteText(const nsAString
& aValue
, nsString
& aResult
) {
477 if you're stepping through the string anyway, why not use iterators instead of forcing the string to copy?
479 const nsPromiseFlatString
& flat
= PromiseFlatString(aValue
);
480 const PRUnichar
* cp
= flat
.get();
481 const PRUnichar
* end
= cp
+ aValue
.Length();
483 PRUnichar ch
= *cp
++;
485 aResult
.AppendLiteral(""");
487 else if (ch
== '&') {
488 aResult
.AppendLiteral("&");
490 else if ((ch
< 32) || (ch
>= 127)) {
491 aResult
.AppendLiteral("&#");
492 aResult
.AppendInt(PRInt32(ch
), 10);
493 aResult
.Append(PRUnichar(';'));
503 * Use this method to convert nsString to char*.
504 * REMEMBER: Match this call with nsMemory::Free(aResult);
506 * @update 04/04/99 harishd
507 * @param aValue - The string value
508 * @param aResult - String coverted to char*.
511 nsLoggingSink::GetNewCString(const nsAString
& aValue
, char** aResult
)
513 nsresult result
=NS_OK
;
515 result
=QuoteText(aValue
,temp
);
516 if(NS_SUCCEEDED(result
)) {
517 *aResult
= temp
.IsEmpty() ? nsnull
: ToNewCString(temp
);
523 * This gets called when handling illegal contents, especially
524 * in dealing with tables. This method creates a new context.
526 * @update 04/04/99 harishd
527 * @param aPosition - The position from where the new context begins.
530 nsLoggingSink::BeginContext(PRInt32 aPosition
)
536 * This method terminates any new context that got created by
537 * BeginContext and switches back to the main context.
539 * @update 04/04/99 harishd
540 * @param aPosition - Validates the end of a context.
543 nsLoggingSink::EndContext(PRInt32 aPosition
)