1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
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.org 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.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 #include "nsTXTToHTMLConv.h"
39 #include "nsNetUtil.h"
40 #include "nsStringStream.h"
41 #include "nsAutoPtr.h"
43 #define TOKEN_DELIMITERS NS_LITERAL_STRING("\t\r\n ").get()
45 // nsISupports methods
46 NS_IMPL_ISUPPORTS4(nsTXTToHTMLConv
,
53 // nsIStreamConverter methods
55 nsTXTToHTMLConv::Convert(nsIInputStream
*aFromStream
,
56 const char *aFromType
, const char *aToType
,
57 nsISupports
*aCtxt
, nsIInputStream
* *_retval
)
59 return NS_ERROR_NOT_IMPLEMENTED
;
63 nsTXTToHTMLConv::AsyncConvertData(const char *aFromType
,
65 nsIStreamListener
*aListener
,
68 NS_ASSERTION(aListener
, "null pointer");
69 mListener
= aListener
;
74 // nsIRequestObserver methods
76 nsTXTToHTMLConv::OnStartRequest(nsIRequest
* request
, nsISupports
*aContext
)
78 mBuffer
.AssignLiteral("<html>\n<head><title>");
79 mBuffer
.Append(mPageTitle
);
80 mBuffer
.AppendLiteral("</title></head>\n<body>\n");
81 if (mPreFormatHTML
) { // Use <pre> tags
82 mBuffer
.AppendLiteral("<pre>\n");
85 // Push mBuffer to the listener now, so the initial HTML will not
86 // be parsed in OnDataAvailable().
88 nsCOMPtr
<nsIChannel
> channel
= do_QueryInterface(request
);
90 channel
->SetContentType(NS_LITERAL_CSTRING("text/html"));
91 // else, assume there is a channel somewhere that knows what it is doing!
93 nsresult rv
= mListener
->OnStartRequest(request
, aContext
);
94 if (NS_FAILED(rv
)) return rv
;
96 // The request may have been canceled, and if that happens, we want to
97 // suppress calls to OnDataAvailable.
98 request
->GetStatus(&rv
);
99 if (NS_FAILED(rv
)) return rv
;
101 nsCOMPtr
<nsIInputStream
> inputData
;
102 rv
= NS_NewStringInputStream(getter_AddRefs(inputData
), mBuffer
);
103 if (NS_FAILED(rv
)) return rv
;
105 rv
= mListener
->OnDataAvailable(request
, aContext
,
106 inputData
, 0, mBuffer
.Length());
107 if (NS_FAILED(rv
)) return rv
;
113 nsTXTToHTMLConv::OnStopRequest(nsIRequest
* request
, nsISupports
*aContext
,
118 // we still have an outstanding token
119 NS_ASSERTION(mToken
->prepend
,
120 "Non prepending tokens should be handled in "
121 "OnDataAvailable. There should only be a single "
122 "prepending token left to be processed.");
123 (void)CatHTML(0, mBuffer
.Length());
125 if (mPreFormatHTML
) {
126 mBuffer
.AppendLiteral("</pre>\n");
128 mBuffer
.AppendLiteral("\n</body></html>");
130 nsCOMPtr
<nsIInputStream
> inputData
;
132 rv
= NS_NewStringInputStream(getter_AddRefs(inputData
), mBuffer
);
133 if (NS_FAILED(rv
)) return rv
;
135 rv
= mListener
->OnDataAvailable(request
, aContext
,
136 inputData
, 0, mBuffer
.Length());
137 if (NS_FAILED(rv
)) return rv
;
139 return mListener
->OnStopRequest(request
, aContext
, aStatus
);
142 // nsITXTToHTMLConv methods
144 nsTXTToHTMLConv::SetTitle(const PRUnichar
*aTitle
)
146 mPageTitle
.Assign(aTitle
);
151 nsTXTToHTMLConv::PreFormatHTML(PRBool value
)
153 mPreFormatHTML
= value
;
157 // nsIStreamListener method
159 nsTXTToHTMLConv::OnDataAvailable(nsIRequest
* request
, nsISupports
*aContext
,
160 nsIInputStream
*aInStream
,
161 PRUint32 aOffset
, PRUint32 aCount
)
165 PRUint32 amtRead
= 0;
166 nsAutoArrayPtr
<char> buffer(new char[aCount
+1]);
167 if (!buffer
) return NS_ERROR_OUT_OF_MEMORY
;
171 // XXX readSegments, to avoid the first copy?
172 rv
= aInStream
->Read(buffer
, aCount
-amtRead
, &read
);
173 if (NS_FAILED(rv
)) return rv
;
176 // XXX charsets?? non-latin1 characters?? utf-16??
177 AppendASCIItoUTF16(buffer
, mBuffer
);
180 PRInt32 front
= -1, back
= -1, tokenLoc
= -1, cursor
= 0;
182 while ( (tokenLoc
= FindToken(cursor
, &mToken
)) > -1) {
183 if (mToken
->prepend
) {
184 front
= mBuffer
.RFindCharInSet(TOKEN_DELIMITERS
, tokenLoc
);
186 back
= mBuffer
.FindCharInSet(TOKEN_DELIMITERS
, tokenLoc
);
189 back
= front
+ mToken
->token
.Length();
192 // didn't find an ending, buffer up.
193 mBuffer
.Left(pushBuffer
, front
);
197 // found the end of the token.
198 cursor
= CatHTML(front
, back
);
201 PRInt32 end
= mBuffer
.RFind(TOKEN_DELIMITERS
, mBuffer
.Length());
202 mBuffer
.Left(pushBuffer
, PR_MAX(cursor
, end
));
203 mBuffer
.Cut(0, PR_MAX(cursor
, end
));
206 if (!pushBuffer
.IsEmpty()) {
207 nsCOMPtr
<nsIInputStream
> inputData
;
209 rv
= NS_NewStringInputStream(getter_AddRefs(inputData
), pushBuffer
);
213 rv
= mListener
->OnDataAvailable(request
, aContext
,
214 inputData
, 0, pushBuffer
.Length());
218 } while (amtRead
< aCount
);
223 // nsTXTToHTMLConv methods
224 nsTXTToHTMLConv::nsTXTToHTMLConv()
227 mPreFormatHTML
= PR_FALSE
;
230 static PRBool
CleanupTokens(void *aElement
, void *aData
)
232 if (aElement
) delete (convToken
*)aElement
;
236 nsTXTToHTMLConv::~nsTXTToHTMLConv()
238 mTokens
.EnumerateForwards((nsVoidArrayEnumFunc
)CleanupTokens
, nsnull
);
242 nsTXTToHTMLConv::Init()
246 // build up the list of tokens to handle
247 convToken
*token
= new convToken
;
248 if (!token
) return NS_ERROR_OUT_OF_MEMORY
;
249 token
->prepend
= PR_FALSE
;
250 token
->token
.Assign(PRUnichar('<'));
251 token
->modText
.AssignLiteral("<");
252 mTokens
.AppendElement(token
);
254 token
= new convToken
;
255 if (!token
) return NS_ERROR_OUT_OF_MEMORY
;
256 token
->prepend
= PR_FALSE
;
257 token
->token
.Assign(PRUnichar('>'));
258 token
->modText
.AssignLiteral(">");
259 mTokens
.AppendElement(token
);
261 token
= new convToken
;
262 if (!token
) return NS_ERROR_OUT_OF_MEMORY
;
263 token
->prepend
= PR_FALSE
;
264 token
->token
.Assign(PRUnichar('&'));
265 token
->modText
.AssignLiteral("&");
266 mTokens
.AppendElement(token
);
268 token
= new convToken
;
269 if (!token
) return NS_ERROR_OUT_OF_MEMORY
;
270 token
->prepend
= PR_TRUE
;
271 token
->token
.AssignLiteral("http://"); // XXX need to iterate through all protos
272 mTokens
.AppendElement(token
);
274 token
= new convToken
;
275 if (!token
) return NS_ERROR_OUT_OF_MEMORY
;
276 token
->prepend
= PR_TRUE
;
277 token
->token
.Assign(PRUnichar('@'));
278 token
->modText
.AssignLiteral("mailto:");
279 mTokens
.AppendElement(token
);
285 nsTXTToHTMLConv::FindToken(PRInt32 cursor
, convToken
* *_retval
)
287 PRInt32 loc
= -1, firstToken
= mBuffer
.Length();
289 for (PRInt8 i
=0; i
< mTokens
.Count(); i
++) {
290 loc
= mBuffer
.Find(((convToken
*)mTokens
[i
])->token
, cursor
);
292 if (loc
< firstToken
) {
300 *_retval
= (convToken
*)mTokens
[token
];
305 nsTXTToHTMLConv::CatHTML(PRInt32 front
, PRInt32 back
)
308 PRInt32 modLen
= mToken
->modText
.Length();
309 if (!mToken
->prepend
) {
310 // replace the entire token (from delimiter to delimiter)
311 mBuffer
.Cut(front
, back
- front
);
312 mBuffer
.Insert(mToken
->modText
, front
);
313 cursor
= front
+modLen
;
317 mBuffer
.Mid(linkText
, front
, back
-front
);
318 mBuffer
.Insert(NS_LITERAL_STRING("<a href=\""), front
);
321 mBuffer
.Insert(mToken
->modText
, cursor
);
322 cursor
+= modLen
-front
+back
;
323 mBuffer
.Insert(NS_LITERAL_STRING("\">"), cursor
);
325 mBuffer
.Insert(linkText
, cursor
);
326 cursor
+= linkText
.Length();
327 mBuffer
.Insert(NS_LITERAL_STRING("</a>"), cursor
);
330 mToken
= nsnull
; // indicates completeness