~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/netwerk/base/src/nsUnicharStreamLoader.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 
2
/* ***** BEGIN LICENSE BLOCK *****
 
3
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
4
 *
 
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/
 
9
 *
 
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
 
13
 * License.
 
14
 *
 
15
 * The Original Code is mozilla.org code.
 
16
 *
 
17
 * The Initial Developer of the Original Code is
 
18
 * Netscape Communications Corporation.
 
19
 * Portions created by the Initial Developer are Copyright (C) 2002
 
20
 * the Initial Developer. All Rights Reserved.
 
21
 *
 
22
 * Contributor(s):
 
23
 *    Boris Zbarsky <bzbarsky@mit.edu>  (original author)
 
24
 *
 
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 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.
 
36
 *
 
37
 * ***** END LICENSE BLOCK ***** */
 
38
 
 
39
#include "nsUnicharStreamLoader.h"
 
40
#include "nsIPipe.h"
 
41
#include "nsIChannel.h"
 
42
#include "nsNetUtil.h"
 
43
#include "nsProxiedService.h"
 
44
#include "nsIChannel.h"
 
45
#include "nsIUnicharInputStream.h"
 
46
#include "nsIConverterInputStream.h"
 
47
#include "nsIPipe.h"
 
48
 
 
49
#ifdef DEBUG // needed for IsASCII assertion
 
50
#include "nsReadableUtils.h"
 
51
#endif // DEBUG
 
52
 
 
53
static NS_DEFINE_CID(kProxyObjectManagerCID, NS_PROXYEVENT_MANAGER_CID);
 
54
 
 
55
NS_IMETHODIMP
 
56
nsUnicharStreamLoader::Init(nsIChannel *aChannel,
 
57
                            nsIUnicharStreamLoaderObserver *aObserver,
 
58
                            nsISupports *aContext,
 
59
                            PRUint32 aSegmentSize)
 
60
{
 
61
  NS_ENSURE_ARG_POINTER(aChannel);
 
62
  NS_ENSURE_ARG_POINTER(aObserver);
 
63
 
 
64
  if (aSegmentSize <= 0) {
 
65
    aSegmentSize = nsIUnicharStreamLoader::DEFAULT_SEGMENT_SIZE;
 
66
  }
 
67
  
 
68
  nsresult rv = aChannel->AsyncOpen(this, aContext);
 
69
 
 
70
  if (NS_FAILED(rv)) {
 
71
    // don't callback synchronously as it puts the caller
 
72
    // in a recursive situation and breaks the asynchronous
 
73
    // semantics of nsIStreamLoader
 
74
    nsresult rv2 = NS_OK;
 
75
    nsCOMPtr<nsIProxyObjectManager> pIProxyObjectManager = 
 
76
      do_GetService(kProxyObjectManagerCID, &rv2);
 
77
    if (NS_FAILED(rv2))
 
78
      return rv2;
 
79
 
 
80
    nsCOMPtr<nsIUnicharStreamLoaderObserver> pObserver;
 
81
    rv2 =
 
82
      pIProxyObjectManager->GetProxyForObject(NS_CURRENT_EVENTQ, 
 
83
                                              NS_GET_IID(nsIUnicharStreamLoaderObserver),
 
84
                                              aObserver, 
 
85
                                              PROXY_ASYNC | PROXY_ALWAYS,
 
86
                                              getter_AddRefs(pObserver));
 
87
    if (NS_FAILED(rv2))
 
88
      return rv2;
 
89
 
 
90
    rv = pObserver->OnStreamComplete(this, aContext, rv, nsnull);
 
91
  }
 
92
 
 
93
  mObserver = aObserver;
 
94
  mContext = aContext;
 
95
  mCharset.Truncate();
 
96
  mChannel = nsnull; // Leave this null till OnStopRequest
 
97
  mSegmentSize = aSegmentSize;
 
98
  return rv;
 
99
}
 
100
 
 
101
NS_METHOD
 
102
nsUnicharStreamLoader::Create(nsISupports *aOuter,
 
103
                              REFNSIID aIID,
 
104
                              void **aResult)
 
105
{
 
106
  if (aOuter) return NS_ERROR_NO_AGGREGATION;
 
107
 
 
108
  nsUnicharStreamLoader* it = new nsUnicharStreamLoader();
 
109
  if (it == nsnull)
 
110
    return NS_ERROR_OUT_OF_MEMORY;
 
111
  NS_ADDREF(it);
 
112
  nsresult rv = it->QueryInterface(aIID, aResult);
 
113
  NS_RELEASE(it);
 
114
  return rv;
 
115
}
 
116
 
 
117
NS_IMPL_ISUPPORTS3(nsUnicharStreamLoader, nsIUnicharStreamLoader,
 
118
                   nsIRequestObserver, nsIStreamListener)
 
119
 
 
120
/* readonly attribute nsIChannel channel; */
 
121
NS_IMETHODIMP 
 
122
nsUnicharStreamLoader::GetChannel(nsIChannel **aChannel)
 
123
{
 
124
  NS_IF_ADDREF(*aChannel = mChannel);
 
125
  return NS_OK;
 
126
}
 
127
 
 
128
/* readonly attribute nsACString charset */
 
129
NS_IMETHODIMP
 
130
nsUnicharStreamLoader::GetCharset(nsACString& aCharset)
 
131
{
 
132
  aCharset = mCharset;
 
133
  return NS_OK;
 
134
}
 
135
 
 
136
/* nsIRequestObserver implementation */
 
137
NS_IMETHODIMP
 
138
nsUnicharStreamLoader::OnStartRequest(nsIRequest* request,
 
139
                                      nsISupports *ctxt)
 
140
{
 
141
  return NS_OK;
 
142
}
 
143
 
 
144
NS_IMETHODIMP 
 
145
nsUnicharStreamLoader::OnStopRequest(nsIRequest *request,
 
146
                                     nsISupports *ctxt,
 
147
                                     nsresult aStatus)
 
148
{
 
149
  // if we trigger this assertion, then it means that the channel called
 
150
  // OnStopRequest before returning from AsyncOpen, which is totally
 
151
  // unexpected behavior.
 
152
  if (!mObserver) {
 
153
    NS_ERROR("No way we should not have an mObserver here!");
 
154
    return NS_ERROR_UNEXPECTED;
 
155
  }
 
156
 
 
157
  if (mInputStream) {
 
158
    nsresult rv;
 
159
    // We got some data at some point.  I guess we should tell our
 
160
    // observer about it or something....
 
161
 
 
162
    // Make sure mChannel points to the channel that we ended up with
 
163
    mChannel = do_QueryInterface(request);
 
164
 
 
165
    // Determine the charset
 
166
    PRUint32 readCount = 0;
 
167
    rv = mInputStream->ReadSegments(WriteSegmentFun,
 
168
                                    this,
 
169
                                    mSegmentSize, 
 
170
                                    &readCount);
 
171
    if (NS_FAILED(rv)) {
 
172
      rv = mObserver->OnStreamComplete(this, mContext, rv, nsnull);
 
173
      goto cleanup;
 
174
    }
 
175
 
 
176
    nsCOMPtr<nsIConverterInputStream> uin =
 
177
      do_CreateInstance("@mozilla.org/intl/converter-input-stream;1",
 
178
                        &rv);
 
179
    if (NS_FAILED(rv)) {
 
180
      rv = mObserver->OnStreamComplete(this, mContext, rv, nsnull);
 
181
      goto cleanup;
 
182
    }
 
183
 
 
184
    rv = uin->Init(mInputStream,
 
185
                   mCharset.get(),
 
186
                   mSegmentSize,
 
187
                   PR_TRUE);
 
188
    
 
189
    if (NS_FAILED(rv)) {
 
190
      rv = mObserver->OnStreamComplete(this, mContext, rv, nsnull);
 
191
      goto cleanup;
 
192
    }
 
193
    
 
194
    mObserver->OnStreamComplete(this, mContext, aStatus, uin);
 
195
 
 
196
  } else {
 
197
    // We never got any data, so just tell our observer that we are
 
198
    // done and give them no stream
 
199
    mObserver->OnStreamComplete(this, mContext, aStatus, nsnull);
 
200
  }
 
201
  
 
202
  // Clean up.
 
203
 cleanup:
 
204
  mObserver = nsnull;
 
205
  mChannel = nsnull;
 
206
  mContext = nsnull;
 
207
  mInputStream = nsnull;
 
208
  mOutputStream = nsnull;
 
209
  return NS_OK;
 
210
}
 
211
 
 
212
/* nsIStreamListener implementation */
 
213
NS_METHOD
 
214
nsUnicharStreamLoader::WriteSegmentFun(nsIInputStream *aInputStream,
 
215
                                       void *aClosure,
 
216
                                       const char *aSegment,
 
217
                                       PRUint32 aToOffset,
 
218
                                       PRUint32 aCount,
 
219
                                       PRUint32 *aWriteCount)
 
220
{
 
221
  nsUnicharStreamLoader *self = (nsUnicharStreamLoader *) aClosure;
 
222
  if (self->mCharset.IsEmpty()) {
 
223
    // First time through.  Call our observer.
 
224
    NS_ASSERTION(self->mObserver, "This should never be possible");
 
225
 
 
226
    nsresult rv = self->mObserver->OnDetermineCharset(self,
 
227
                                                      self->mContext,
 
228
                                                      aSegment,
 
229
                                                      aCount,
 
230
                                                      self->mCharset);
 
231
    
 
232
    if (NS_FAILED(rv) || self->mCharset.IsEmpty()) {
 
233
      // The observer told us nothing useful
 
234
      self->mCharset = NS_LITERAL_CSTRING("ISO-8859-1");
 
235
    }
 
236
 
 
237
    NS_ASSERTION(IsASCII(self->mCharset),
 
238
                 "Why is the charset name non-ascii?  Whose bright idea was that?");
 
239
  }
 
240
  // Don't consume any data
 
241
  *aWriteCount = 0;
 
242
  return NS_BASE_STREAM_WOULD_BLOCK;
 
243
}
 
244
 
 
245
 
 
246
NS_IMETHODIMP
 
247
nsUnicharStreamLoader::OnDataAvailable(nsIRequest *aRequest,
 
248
                                       nsISupports *aContext,
 
249
                                       nsIInputStream *aInputStream, 
 
250
                                       PRUint32 aSourceOffset,
 
251
                                       PRUint32 aCount)
 
252
{
 
253
  nsresult rv = NS_OK;
 
254
  if (!mInputStream) {
 
255
    // We are not initialized.  Time to set things up.
 
256
    NS_ASSERTION(!mOutputStream, "Why are we sorta-initialized?");
 
257
    rv = NS_NewPipe(getter_AddRefs(mInputStream),
 
258
                    getter_AddRefs(mOutputStream),
 
259
                    mSegmentSize,
 
260
                    PRUint32(-1),  // give me all the data you can!
 
261
                    PR_TRUE,  // non-blocking input
 
262
                    PR_TRUE); // non-blocking output
 
263
    if (NS_FAILED(rv))
 
264
      return rv;
 
265
  }
 
266
 
 
267
  PRUint32 writeCount = 0;
 
268
  do {
 
269
    rv = mOutputStream->WriteFrom(aInputStream, aCount, &writeCount);
 
270
    if (NS_FAILED(rv)) return rv;
 
271
    aCount -= writeCount;
 
272
  } while (aCount > 0);
 
273
 
 
274
  return NS_OK;
 
275
}