1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
5
* The contents of this file are subject to the Netscape Public License
6
* Version 1.1 (the "License"); you may not use this file except in
7
* compliance with the License. You may obtain a copy of the License at
8
* http://www.mozilla.org/NPL/
10
* Software distributed under the License is distributed on an "AS IS" basis,
11
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
* for the specific language governing rights and limitations under the
15
* The Original Code is Mozilla Communicator client code.
17
* The Initial Developer of the Original Code is
18
* Netscape Communications Corporation.
19
* Portions created by the Initial Developer are Copyright (C) 1998
20
* the Initial Developer. All Rights Reserved.
25
* Alternatively, the contents of this file may be used under the terms of
26
* either the GNU General Public License Version 2 or later (the "GPL"), or
27
* 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 NPL, 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 NPL, 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);
51
// list of tags that have skipped content
52
static const char gSkippedContentTags[] = {
63
NS_NewHTMLLoggingSink(nsIContentSink** aInstancePtrResult)
65
NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr");
66
if (nsnull == aInstancePtrResult) {
67
return NS_ERROR_NULL_POINTER;
69
nsLoggingSink* it = new nsLoggingSink();
71
return NS_ERROR_OUT_OF_MEMORY;
73
return it->QueryInterface(kIContentSinkIID, (void**) aInstancePtrResult);
76
nsLoggingSink::nsLoggingSink() {
83
nsLoggingSink::~nsLoggingSink() {
85
if(mOutput && mAutoDeleteOutput) {
91
NS_IMPL_ADDREF(nsLoggingSink)
92
NS_IMPL_RELEASE(nsLoggingSink)
95
nsLoggingSink::QueryInterface(const nsIID& aIID, void** aInstancePtr)
97
NS_PRECONDITION(nsnull != aInstancePtr, "null ptr");
98
if (nsnull == aInstancePtr) {
99
return NS_ERROR_NULL_POINTER;
101
if (aIID.Equals(kISupportsIID)) {
102
nsISupports* tmp = this;
103
*aInstancePtr = (void*) tmp;
105
else if (aIID.Equals(kIContentSinkIID)) {
106
nsIContentSink* tmp = this;
107
*aInstancePtr = (void*) tmp;
109
else if (aIID.Equals(kIHTMLContentSinkIID)) {
110
nsIHTMLContentSink* tmp = this;
111
*aInstancePtr = (void*) tmp;
113
else if (aIID.Equals(kILoggingSinkIID)) {
114
nsILoggingSink* tmp = this;
115
*aInstancePtr = (void*) tmp;
118
*aInstancePtr = nsnull;
119
return NS_NOINTERFACE;
126
nsLoggingSink::SetOutputStream(PRFileDesc *aStream,PRBool autoDeleteOutput) {
128
mAutoDeleteOutput=autoDeleteOutput;
133
void WriteTabs(PRFileDesc * out,int aTabCount) {
135
for(tabs=0;tabs<aTabCount;++tabs)
136
PR_fprintf(out, " ");
141
nsLoggingSink::WillBuildModel() {
143
WriteTabs(mOutput,++mLevel);
144
PR_fprintf(mOutput, "<begin>\n");
146
//proxy the call to the real sink if you have one.
148
mSink->WillBuildModel();
155
nsLoggingSink::DidBuildModel() {
157
WriteTabs(mOutput,--mLevel);
158
PR_fprintf(mOutput, "</begin>\n");
160
//proxy the call to the real sink if you have one.
161
nsresult theResult=NS_OK;
163
theResult=mSink->DidBuildModel();
170
nsLoggingSink::WillInterrupt() {
171
nsresult theResult=NS_OK;
173
//proxy the call to the real sink if you have one.
175
theResult=mSink->WillInterrupt();
182
nsLoggingSink::WillResume() {
183
nsresult theResult=NS_OK;
185
//proxy the call to the real sink if you have one.
187
theResult=mSink->WillResume();
194
nsLoggingSink::SetParser(nsIParser* aParser) {
195
nsresult theResult=NS_OK;
197
//proxy the call to the real sink if you have one.
199
theResult=mSink->SetParser(aParser);
202
NS_IF_RELEASE(mParser);
206
NS_IF_ADDREF(mParser);
212
nsLoggingSink::OpenContainer(const nsIParserNode& aNode) {
214
OpenNode("container", aNode); //do the real logging work...
216
nsresult theResult=NS_OK;
218
//then proxy the call to the real sink if you have one.
220
theResult=mSink->OpenContainer(aNode);
228
nsLoggingSink::CloseContainer(const nsHTMLTag aTag) {
230
nsresult theResult=NS_OK;
232
nsHTMLTag nodeType = nsHTMLTag(aTag);
233
if ((nodeType >= eHTMLTag_unknown) &&
234
(nodeType <= nsHTMLTag(NS_HTML_TAG_MAX))) {
235
const PRUnichar* tag = nsHTMLTags::GetStringValue(nodeType);
236
theResult = CloseNode(NS_ConvertUCS2toUTF8(tag).get());
238
else theResult= CloseNode("???");
240
//then proxy the call to the real sink if you have one.
242
theResult=mSink->CloseContainer(aTag);
250
nsLoggingSink::AddHeadContent(const nsIParserNode& aNode) {
253
nsresult theResult=NS_OK;
255
//then proxy the call to the real sink if you have one.
257
theResult=mSink->AddHeadContent(aNode);
265
nsLoggingSink::AddLeaf(const nsIParserNode& aNode) {
268
nsresult theResult=NS_OK;
270
//then proxy the call to the real sink if you have one.
272
theResult=mSink->AddLeaf(aNode);
280
* This gets called by the parser when you want to add
281
* a PI node to the current container in the content
284
* @updated gess 3/25/98
289
nsLoggingSink::AddProcessingInstruction(const nsIParserNode& aNode){
292
DebugDump("<",aNode.GetText(),(mNodeStackPos)*2);
295
nsresult theResult=NS_OK;
297
//then proxy the call to the real sink if you have one.
299
theResult=mSink->AddProcessingInstruction(aNode);
306
* This gets called by the parser when it encounters
307
* a DOCTYPE declaration in the HTML document.
311
nsLoggingSink::AddDocTypeDecl(const nsIParserNode& aNode) {
314
DebugDump("<",aNode.GetText(),(mNodeStackPos)*2);
317
nsresult theResult=NS_OK;
319
//then proxy the call to the real sink if you have one.
321
theResult=mSink->AddDocTypeDecl(aNode);
329
* This gets called by the parser when you want to add
330
* a comment node to the current container in the content
333
* @updated gess 3/25/98
338
nsLoggingSink::AddComment(const nsIParserNode& aNode){
341
DebugDump("<",aNode.GetText(),(mNodeStackPos)*2);
344
nsresult theResult=NS_OK;
346
//then proxy the call to the real sink if you have one.
348
theResult=mSink->AddComment(aNode);
357
nsLoggingSink::SetTitle(const nsString& aValue) {
360
GetNewCString(aValue, &tmp);
361
WriteTabs(mOutput,++mLevel);
363
PR_fprintf(mOutput, "<title value=\"%s\"/>\n", tmp);
368
nsresult theResult=NS_OK;
370
//then proxy the call to the real sink if you have one.
372
theResult=mSink->SetTitle(aValue);
381
nsLoggingSink::OpenHTML(const nsIParserNode& aNode) {
382
OpenNode("html", aNode);
384
nsresult theResult=NS_OK;
386
//then proxy the call to the real sink if you have one.
388
theResult=mSink->OpenHTML(aNode);
396
nsLoggingSink::CloseHTML() {
399
nsresult theResult=NS_OK;
401
//then proxy the call to the real sink if you have one.
403
theResult=mSink->CloseHTML();
411
nsLoggingSink::OpenHead(const nsIParserNode& aNode) {
412
OpenNode("head", aNode);
414
nsresult theResult=NS_OK;
416
//then proxy the call to the real sink if you have one.
418
theResult=mSink->OpenHead(aNode);
425
nsLoggingSink::CloseHead() {
428
nsresult theResult=NS_OK;
430
//then proxy the call to the real sink if you have one.
432
theResult=mSink->CloseHead();
439
nsLoggingSink::OpenBody(const nsIParserNode& aNode) {
440
OpenNode("body", aNode);
442
nsresult theResult=NS_OK;
444
//then proxy the call to the real sink if you have one.
446
theResult=mSink->OpenBody(aNode);
453
nsLoggingSink::CloseBody() {
456
nsresult theResult=NS_OK;
458
//then proxy the call to the real sink if you have one.
460
theResult=mSink->CloseBody();
467
nsLoggingSink::OpenForm(const nsIParserNode& aNode) {
468
OpenNode("form", aNode);
470
nsresult theResult=NS_OK;
472
//then proxy the call to the real sink if you have one.
474
theResult=mSink->OpenForm(aNode);
481
nsLoggingSink::CloseForm() {
484
nsresult theResult=NS_OK;
486
//then proxy the call to the real sink if you have one.
488
theResult=mSink->CloseForm();
495
nsLoggingSink::OpenMap(const nsIParserNode& aNode) {
496
OpenNode("map", aNode);
498
nsresult theResult=NS_OK;
500
//then proxy the call to the real sink if you have one.
502
theResult=mSink->OpenMap(aNode);
509
nsLoggingSink::CloseMap() {
512
nsresult theResult=NS_OK;
514
//then proxy the call to the real sink if you have one.
516
theResult=mSink->CloseMap();
523
nsLoggingSink::OpenFrameset(const nsIParserNode& aNode) {
524
OpenNode("frameset", aNode);
526
nsresult theResult=NS_OK;
528
//then proxy the call to the real sink if you have one.
530
theResult=mSink->OpenFrameset(aNode);
537
nsLoggingSink::CloseFrameset() {
538
CloseNode("frameset");
540
nsresult theResult=NS_OK;
542
//then proxy the call to the real sink if you have one.
544
theResult=mSink->CloseFrameset();
552
nsLoggingSink::OpenNode(const char* aKind, const nsIParserNode& aNode) {
553
WriteTabs(mOutput,++mLevel);
555
PR_fprintf(mOutput,"<open container=");
557
nsHTMLTag nodeType = nsHTMLTag(aNode.GetNodeType());
558
if ((nodeType >= eHTMLTag_unknown) &&
559
(nodeType <= nsHTMLTag(NS_HTML_TAG_MAX))) {
560
const PRUnichar* tag = nsHTMLTags::GetStringValue(nodeType);
561
PR_fprintf(mOutput, "\"%s\"", NS_ConvertUCS2toUTF8(tag).get());
565
GetNewCString(aNode.GetText(), &text);
567
PR_fprintf(mOutput, "\"%s\"", text);
568
nsMemory::Free(text);
572
if (WillWriteAttributes(aNode)) {
573
PR_fprintf(mOutput, ">\n");
574
WriteAttributes(aNode);
575
PR_fprintf(mOutput, "</open>\n");
578
PR_fprintf(mOutput, ">\n");
585
nsLoggingSink::CloseNode(const char* aKind) {
586
WriteTabs(mOutput,mLevel--);
587
PR_fprintf(mOutput, "<close container=\"%s\">\n", aKind);
593
nsLoggingSink::WriteAttributes(const nsIParserNode& aNode) {
595
WriteTabs(mOutput,1+mLevel);
597
PRInt32 ac = aNode.GetAttributeCount();
598
for (PRInt32 i = 0; i < ac; ++i) {
601
const nsAString& k = aNode.GetKeyAt(i);
602
const nsAString& v = aNode.GetValueAt(i);
604
GetNewCString(k, &key);
606
PR_fprintf(mOutput, " <attr key=\"%s\" value=\"", key);
613
PRUnichar first = tmp.First();
614
if ((first == '"') || (first == '\'')) {
615
if (tmp.Last() == first) {
617
PRInt32 pos = tmp.Length() - 1;
622
// Mismatched quotes - leave them in
625
GetNewCString(tmp, &value);
628
PR_fprintf(mOutput, "%s\"/>\n", value);
629
WriteTabs(mOutput,1+mLevel);
630
nsMemory::Free(value);
635
if (0 != strchr(gSkippedContentTags, aNode.GetNodeType())) {
636
nsCOMPtr<nsIDTD> dtd;
637
mParser->GetDTD(getter_AddRefs(dtd));
638
NS_ENSURE_TRUE(dtd, NS_ERROR_FAILURE);
643
dtd->CollectSkippedContent(aNode.GetNodeType(), theString, lineNo);
644
char* content = nsnull;
645
GetNewCString(theString, &content);
647
PR_fprintf(mOutput, " <content value=\"");
648
PR_fprintf(mOutput, "%s\"/>\n", content) ;
649
nsMemory::Free(content);
652
WriteTabs(mOutput,1+mLevel);
657
nsLoggingSink::WillWriteAttributes(const nsIParserNode& aNode)
659
PRInt32 ac = aNode.GetAttributeCount();
663
if (0 != strchr(gSkippedContentTags, aNode.GetNodeType())) {
664
nsCOMPtr<nsIDTD> dtd;
665
mParser->GetDTD(getter_AddRefs(dtd));
666
NS_ENSURE_TRUE(dtd, NS_ERROR_FAILURE);
671
dtd->CollectSkippedContent(aNode.GetNodeType(), content, lineNo);
672
if (!content.IsEmpty()) {
680
nsLoggingSink::LeafNode(const nsIParserNode& aNode)
682
WriteTabs(mOutput,1+mLevel);
683
nsHTMLTag nodeType = nsHTMLTag(aNode.GetNodeType());
685
if ((nodeType >= eHTMLTag_unknown) &&
686
(nodeType <= nsHTMLTag(NS_HTML_TAG_MAX))) {
687
const PRUnichar* tag = nsHTMLTags::GetStringValue(nodeType);
690
PR_fprintf(mOutput, "<leaf tag=\"%s\"", NS_ConvertUCS2toUTF8(tag).get());
691
else PR_fprintf(mOutput, "<leaf tag=\"???\"");
693
if (WillWriteAttributes(aNode)) {
694
PR_fprintf(mOutput, ">\n");
695
WriteAttributes(aNode);
696
PR_fprintf(mOutput, "</leaf>\n");
699
PR_fprintf(mOutput, "/>\n");
707
case eHTMLTag_whitespace:
709
GetNewCString(aNode.GetText(), &str);
711
PR_fprintf(mOutput, "<text value=\"%s\"/>\n", str);
716
case eHTMLTag_newline:
717
PR_fprintf(mOutput, "<newline/>\n");
720
case eHTMLTag_entity:
721
tmp.Append(aNode.GetText());
723
pos = tmp.Length() - 1;
727
PR_fprintf(mOutput, "<entity value=\"%s\"/>\n", NS_LossyConvertUCS2toASCII(tmp).get());
731
NS_NOTREACHED("unsupported leaf node type");
738
nsLoggingSink::QuoteText(const nsAString& aValue, nsString& aResult) {
741
if you're stepping through the string anyway, why not use iterators instead of forcing the string to copy?
743
const nsPromiseFlatString& flat = PromiseFlatString(aValue);
744
const PRUnichar* cp = flat.get();
745
const PRUnichar* end = cp + aValue.Length();
747
PRUnichar ch = *cp++;
749
aResult.Append(NS_LITERAL_STRING("""));
751
else if (ch == '&') {
752
aResult.Append(NS_LITERAL_STRING("&"));
754
else if ((ch < 32) || (ch >= 127)) {
755
aResult.Append(NS_LITERAL_STRING("&#"));
756
aResult.AppendInt(PRInt32(ch), 10);
757
aResult.Append(PRUnichar(';'));
767
* Use this method to convert nsString to char*.
768
* REMEMBER: Match this call with nsMemory::Free(aResult);
770
* @update 04/04/99 harishd
771
* @param aValue - The string value
772
* @param aResult - String coverted to char*.
775
nsLoggingSink::GetNewCString(const nsAString& aValue, char** aResult)
777
nsresult result=NS_OK;
779
result=QuoteText(aValue,temp);
780
if(NS_SUCCEEDED(result)) {
781
if(!temp.IsEmpty()) {
782
*aResult = ToNewCString(temp);
789
* This gets called when handling illegal contents, especially
790
* in dealing with tables. This method creates a new context.
792
* @update 04/04/99 harishd
793
* @param aPosition - The position from where the new context begins.
796
nsLoggingSink::BeginContext(PRInt32 aPosition)
802
* This method terminates any new context that got created by
803
* BeginContext and switches back to the main context.
805
* @update 04/04/99 harishd
806
* @param aPosition - Validates the end of a context.
809
nsLoggingSink::EndContext(PRInt32 aPosition)