SeekableChannel.cpp
Go to the documentation of this file.
1 /*
2 //
3 // BEGIN SONGBIRD GPL
4 //
5 // This file is part of the Songbird web player.
6 //
7 // Copyright(c) 2005-2008 POTI, Inc.
8 // http://songbirdnest.com
9 //
10 // This file may be licensed under the terms of of the
11 // GNU General Public License Version 2 (the "GPL").
12 //
13 // Software distributed under the License is distributed
14 // on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
15 // express or implied. See the GPL for the specific language
16 // governing rights and limitations.
17 //
18 // You should have received a copy of the GPL along with this
19 // program. If not, go to http://www.gnu.org/licenses/gpl.html
20 // or write to the Free Software Foundation, Inc.,
21 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 // END SONGBIRD GPL
24 //
25 */
26 
27 /*******************************************************************************
28  *******************************************************************************
29  *
30  * Seekable channel.
31  *
32  *******************************************************************************
33  ******************************************************************************/
34 
40 /*******************************************************************************
41  *
42  * Seekable channel imported services.
43  *
44  ******************************************************************************/
45 
46 /* Local file imports. */
47 #include "SeekableChannel.h"
48 
49 /* Mozilla imports. */
50 #include <nsIInputStream.h>
51 #include <nsIIOService.h>
52 #include <nsIResumableChannel.h>
53 #include <nsIURI.h>
54 #include <nsMemory.h>
55 #include <nsServiceManagerUtils.h>
56 #include <nsStringGlue.h>
57 #include <prlog.h>
58 
59 
60 /*******************************************************************************
61  *
62  * Seekable channel logging services.
63  *
64  ******************************************************************************/
65 
66 #ifdef PR_LOGGING
67 static PRLogModuleInfo* gLog = PR_NewLogModule("sbSeekableChannel");
68 #define LOG(args) if (gLog) PR_LOG(gLog, PR_LOG_DEBUG, args)
69 #else
70 #define LOG(args) /* nothing */
71 #endif
72 
73 
74 /*******************************************************************************
75  *
76  * Seekable channel nsISupports implementation.
77  *
78  ******************************************************************************/
79 
82  nsIStreamListener,
83  nsIRequestObserver,
84  nsIChannelEventSink,
86 
87 
88 /*******************************************************************************
89  *
90  * Seekable channel sbISeekableChannel implementation.
91  *
92  ******************************************************************************/
93 
94 /*
95  * Open
96  *
97  * --> pChannel Base channel.
98  * --> pListener Listener for channel events.
99  *
100  * This function opens a seekable channel using the base channel specified by
101  * pChannel. Events relating to the channel are delivered to the listener
102  * specified by pListener.
103  */
104 
105 NS_IMETHODIMP sbSeekableChannel::Open(
106  nsIChannel *pChannel,
107  sbISeekableChannelListener *pListener)
108 {
109  nsCOMPtr<nsIRequest> pRequest;
110  nsresult result = NS_OK;
111 
112  /* Validate parameters. */
113  if (!pChannel || !pListener)
114  result = NS_ERROR_NULL_POINTER;
115 
116  /* Ensure the channel is closed. */
117  if (NS_SUCCEEDED(result))
118  Close();
119 
120  /* Initialize the channel parameters. */
121  if (NS_SUCCEEDED(result))
122  {
123  mpChannel = pChannel;
124  mpListener = pListener;
125  mContentLength = 0;
126  mBasePos = 0;
127  mPos = 0;
128  mRestarting = PR_FALSE;
129  }
130 
131  /* Set up the channel request load flags. */
132  if (NS_SUCCEEDED(result))
133  {
134  pRequest = do_QueryInterface(mpChannel, &result);
135  if (NS_SUCCEEDED(result))
136  {
137  result = pRequest->SetLoadFlags
138  ( nsIRequest::INHIBIT_CACHING
139  | nsIRequest::INHIBIT_PERSISTENT_CACHING
140  | nsIRequest::LOAD_BYPASS_CACHE);
141  }
142  NS_ASSERTION(NS_SUCCEEDED(result),
143  "Setting load flags failed "
144  ":( Watch out, app will deadlock.");
145  }
146 
147  /* Set up the channel notification callbacks. */
148  if (NS_SUCCEEDED(result))
149  result = mpChannel->SetNotificationCallbacks(this);
150 
151  /* Open the channel. */
152  if (NS_SUCCEEDED(result))
153  result = mpChannel->AsyncOpen(this, nsnull);
154 
155  return (result);
156 }
157 
158 
159 /*
160  * Close
161  *
162  * This function closes the seekable channel.
163  */
164 
165 NS_IMETHODIMP sbSeekableChannel::Close()
166 {
167  DataSet::iterator dataSetIterator;
168  Segment *pSegment;
169  PRBool pending;
170  nsresult result = NS_OK;
171 
172  /* Cancel any pending base channel requests. */
173  if (mpChannel)
174  {
175  pending = PR_FALSE;
176  mpChannel->IsPending(&pending);
177  if (pending)
178  mpChannel->Cancel(NS_ERROR_ABORT);
179  mpChannel->SetNotificationCallbacks(nsnull);
180  }
181 
182  /* Empty the data set. */
183  dataSetIterator = mChannelData.begin();
184  while (dataSetIterator != mChannelData.end())
185  {
186  pSegment = *dataSetIterator++;
187  mChannelData.erase(pSegment);
188  delete (pSegment);
189  }
190 
191  /* Reset the channel parameters. */
192  mpChannel = nsnull;
193  mpListener = nsnull;
194  mContentLength = 0;
195  mPos = 0;
196  mBasePos = 0;
197  mRestarting = PR_FALSE;
198 
199  return (result);
200 }
201 
202 
203 /*
204  * Skip
205  *
206  * --> numBytes Number of bytes to skip.
207  *
208  * This function skips forward in the channel by the number of bytes specified
209  * by numBytes.
210  */
211 
212 NS_IMETHODIMP sbSeekableChannel::Skip(
213  PRUint64 numBytes)
214 {
215  nsresult result = NS_OK;
216 
217  return (result);
218 }
219 
220 
221 /*
222  * Read
223  *
224  * --> buffer Buffer in which to place read data.
225  * --> length Number of bytes to read.
226  * <-- pBytesRead Number of bytes read.
227  *
228  * This function reads from the channel the number of bytes specified by
229  * length and places the read data into the buffer specified by buffer. The
230  * number of bytes actually read is returned in pBytesRead.
231  */
232 
233 NS_IMETHODIMP sbSeekableChannel::Read(
234  char *buffer,
235  PRUint32 length,
236  PRUint32 *pBytesRead)
237 {
238  PRUint32 readLength = length;
239  DataSet::iterator dataSetIterator;
240  Segment findSegment;
241  Segment *pSegment = NULL;
242  nsresult result = NS_OK;
243 
244  /* Validate parameters. */
245  if (!buffer)
246  result = NS_ERROR_NULL_POINTER;
247 
248  /* Check if channel is restarting. */
249  if (NS_SUCCEEDED(result) && (mRestarting))
251 
252  /* Prevent reading past end of file. */
253  if (mPos >= mContentLength)
254  result = NS_ERROR_UNEXPECTED;
255  if (NS_SUCCEEDED(result) && ((mPos + readLength) > mContentLength))
256  readLength = (PRUint32)(mContentLength - mPos);
257 
258  /* Find a segment containing the data to read. */
259  if (NS_SUCCEEDED(result))
260  {
261  findSegment.offset = mPos;
262  findSegment.length = 0;
263  dataSetIterator = mChannelData.find(&findSegment);
264  if (dataSetIterator == mChannelData.end())
266  }
267 
268  /* Check if data segment contains the requested amount of data. */
269  /*zzz should return partial result. */
270  if (NS_SUCCEEDED(result))
271  {
272  pSegment = *dataSetIterator;
273  if ((mPos + readLength) > (pSegment->offset + pSegment->length))
275  }
276 
277  /* Copy data to read buffer. */
278  if (NS_SUCCEEDED(result))
279  {
280  memcpy(buffer,
281  pSegment->buffer + (mPos - pSegment->offset),
282  readLength);
283  mPos += readLength;
284  }
285 
286  /* Restart channel if needed. */
288  {
289  /* If the requested data starts in an available segment, restart */
290  /* from the end of the segment. Otherwise, restart from the current */
291  /* channel position. */
292  if (pSegment)
293  Restart(pSegment->offset + pSegment->length);
294  else
295  Restart(mPos);
296  }
297 
298  /* Return results. */
299  if (NS_SUCCEEDED(result))
300  *pBytesRead = readLength;
301 
302  return (result);
303 }
304 
305 
306 /*
307  * ReadChar
308  *
309  * <-- pChar Read character.
310  *
311  * This function reads a character from the channel and returns it in pChar.
312  */
313 
314 NS_IMETHODIMP sbSeekableChannel::ReadChar(
315  char *pChar)
316 {
317  nsresult result = NS_OK;
318 
319  return (result);
320 }
321 
322 
323 /*
324  * ReadInt32
325  *
326  * <-- pInt32 Read 32-bit integer.
327  *
328  * This function reads a 32-bit integer from the channel and returns it in
329  * pInt32.
330  */
331 
332 NS_IMETHODIMP sbSeekableChannel::ReadInt32(
333  PRInt32 *pInt32)
334 {
335  nsresult result = NS_OK;
336 
337  return (result);
338 }
339 
340 
341 /*
342  * ReadInt64
343  *
344  * <-- pInt64 Read 64-bit integer.
345  *
346  * This function reads a 64-bit integer from the channel and returns it in
347  * pInt64.
348  */
349 
350 NS_IMETHODIMP sbSeekableChannel::ReadInt64(
351  PRInt64 *pInt64)
352 {
353  nsresult result = NS_OK;
354 
355  return (result);
356 }
357 
358 
359 /*
360  * Getters/setters.
361  */
362 
363 NS_IMETHODIMP sbSeekableChannel::GetPos(
364  PRUint64 *pPos)
365 {
366  nsresult result = NS_OK;
367 
368  /* Validate parameters. */
369  if (!pPos)
370  result = NS_ERROR_NULL_POINTER;
371 
372  /* Return results. */
373  if (NS_SUCCEEDED(result))
374  *pPos = mPos;
375 
376  return (result);
377 }
378 
379 
380 NS_IMETHODIMP sbSeekableChannel::SetPos(
381  PRUint64 pos)
382 {
383  DataSet::iterator dataSetIterator;
384  Segment findSegment;
385  nsresult result = NS_OK;
386 
387  /* Check if channel is restarting. */
388  if (mRestarting)
390 
391  /* Find a segment containing the new position. */
392  if (NS_SUCCEEDED(result) && (pos < mContentLength))
393  {
394  findSegment.offset = pos;
395  findSegment.length = 0;
396  dataSetIterator = mChannelData.find(&findSegment);
397  if (dataSetIterator == mChannelData.end())
399  }
400 
401  /* Restart channel if needed. */
402  if (!mRestarting && (result == NS_ERROR_SONGBIRD_SEEKABLE_CHANNEL_RESTART))
403  Restart(pos);
404 
405  /* Set the channel position. */
406  if (NS_SUCCEEDED(result))
407  mPos = pos;
408 
409  return (result);
410 }
411 
412 
413 NS_IMETHODIMP sbSeekableChannel::GetSize(
414  PRUint64 *pSize)
415 {
416  nsresult result = NS_OK;
417 
418  /* Validate parameters. */
419  if (!pSize)
420  result = NS_ERROR_NULL_POINTER;
421 
422  /* Return results. */
423  if (NS_SUCCEEDED(result))
424  *pSize = mContentLength;
425 
426  return (result);
427 }
428 
429 
430 /*
431  * GetCompleted
432  *
433  * <-- pCompleted True if channel reading is complete.
434  *
435  * This function returns in pCompleted the channel reading complete state. If
436  * all the data for the channel has been read or if a channel read error
437  * occured, this function returns true in pCompleted; otherwise, it returns
438  * false.
439  */
440 
441 NS_IMETHODIMP sbSeekableChannel::GetCompleted(
442  PRBool *pCompleted)
443 {
444  nsresult result = NS_OK;
445 
446  /* Validate parameters. */
447  if (!pCompleted)
448  result = NS_ERROR_NULL_POINTER;
449 
450  /* Return results. */
451  *pCompleted = mCompleted;
452 
453  return (result);
454 }
455 
456 
457 /*******************************************************************************
458  *
459  * Seekable channel nsIStreamListener implementation.
460  *
461  ******************************************************************************/
462 
463 /*
464  * OnDataAvailable
465  *
466  * --> pRequest Channel request.
467  * --> pCtx Request context.
468  * --> pStream Input stream.
469  * --> offset Offset within stream.
470  * --> numBytes Number of stream data bytes available.
471  *
472  * This function is called when data from the stream specified by pStream is
473  * available to be read. The data request is specified by pRequest and the
474  * requestor context is specified by pCtx.
475  * The available data is located at the stream offset specified by offset and
476  * is numBytes in length.
477  */
478 
479 NS_IMETHODIMP sbSeekableChannel::OnDataAvailable(
480  nsIRequest *pRequest,
481  nsISupports *pCtx,
482  nsIInputStream *pStream,
483  PRUint32 offset,
484  PRUint32 numBytes)
485 {
486  nsresult result = NS_OK;
487 
488  /* Do nothing if channel is restarting. */
489  if (mRestarting)
491 
492  /* Read the base channel data into a data segment. */
493  if (numBytes > 0)
494  {
495  mDataReceivedSinceStart = PR_TRUE;
496  ReadSegment(pStream, numBytes);
497  }
498 
499  /* Call the OnChannelDataAvailable handler. */
500  /*zzz should read minimum block size before calling handler. */
501  if (mpListener)
502  mpListener->OnChannelDataAvailable(this);
503 
504  return (result);
505 }
506 
507 
508 /*******************************************************************************
509  *
510  * Seekable channel nsIRequestObserver implementation.
511  *
512  ******************************************************************************/
513 
514 /*
515  * OnStartRequest
516  *
517  * --> pRequest Request being started.
518  * --> pCtx Request context.
519  *
520  * This function is called when the request specified by pRequest is started.
521  * The requestor context is specified by pCtx.
522  */
523 
524 NS_IMETHODIMP sbSeekableChannel::OnStartRequest(
525  nsIRequest *pRequest,
526  nsISupports *pCtx)
527 {
528  NS_ENSURE_STATE(mpChannel);
529 
530  PRInt32 contentLength;
531  nsresult result = NS_OK;
532 
533  /* Channel restart is complete. */
534  mRestarting = PR_FALSE;
535 
536  /* Indicate that no data has been received */
537  /* since the start of the request. */
538  mDataReceivedSinceStart = PR_FALSE;
539 
540  /* Get the channel content length, preserving the sign. */
541  if (!mContentLength)
542  {
543  result = mpChannel->GetContentLength(&contentLength);
544  if (NS_SUCCEEDED(result) && (contentLength > 0))
545  mContentLength = (PRInt64) contentLength;
546  }
547 
548  return (result);
549 }
550 
551 
552 /*
553  * OnStopRequest
554  *
555  * --> pRequest Request being stopped.
556  * --> pCtx Request context.
557  * --> status Request status.
558  *
559  * This function is called when the request specified by pRequest is stopped.
560  * The requestor context is specified by pCtx and the request status is
561  * specified by status.
562  */
563 
564 NS_IMETHODIMP sbSeekableChannel::OnStopRequest(
565  nsIRequest *pRequest,
566  nsISupports *pCtx,
567  nsresult status)
568 {
569  nsresult result = NS_OK;
570 
571  /* Do nothing if channel is restarting. */
572  if (mRestarting)
574 
575  /* Channel reading is complete on error or if no data */
576  /* has been received since the request was started. */
577  if (NS_FAILED(status) || !mDataReceivedSinceStart)
578  mCompleted = PR_TRUE;
579 
580  /* Call the OnChannelDataAvailable handler. */
581  if (mpListener)
582  mpListener->OnChannelDataAvailable(this);
583 
584  return (result);
585 }
586 
587 
588 /*******************************************************************************
589  *
590  * Seekable channel nsIChannelEventSink implementation.
591  *
592  ******************************************************************************/
593 
594 /*
595  * OnChannelRedirect
596  *
597  * --> pOrigChannel Original channel.
598  * --> pRedirectedChannel Redirected channel.
599  * --> flags Redirection flags.
600  *
601  * This function handles redirection of the channel specified by pOrigChannel
602  * to the channel specified by pRedirectedChannel. Flags relating to the
603  * redirection are specified by flags.
604  */
605 
606 NS_IMETHODIMP sbSeekableChannel::OnChannelRedirect(
607  nsIChannel *pOrigChannel,
608  nsIChannel *pRedirectedChannel,
609  PRUint32 flags)
610 {
611  nsresult result = NS_OK;
612 
613  /* Redirect channel. */
614  mpChannel = pRedirectedChannel;
615 
616  return (result);
617 }
618 
619 
620 /*******************************************************************************
621  *
622  * Seekable channel nsIInterfaceRequestor implementation.
623  *
624  ******************************************************************************/
625 
626 /*
627  * GetInterface
628  *
629  * --> iid Interface to get.
630  * <-- ppInterface Requested interface.
631  *
632  * This function returns in ppInterface an object implementing the interface
633  * specified by iid for the component.
634  */
635 
636 NS_IMETHODIMP sbSeekableChannel::GetInterface(
637  const nsIID &iid,
638  void **ppInterface)
639 {
640  void *pInterface = nsnull;
641  nsresult result = NS_OK;
642 
643  /* Validate parameters. */
644  NS_ENSURE_ARG_POINTER(ppInterface);
645 
646  /* Query component for the interface. */
647  result = QueryInterface(iid, &pInterface);
648 
649  /* Return results. */
650  *ppInterface = pInterface;
651 
652  return (result);
653 }
654 
655 
656 /*******************************************************************************
657  *
658  * Public seekable channel services.
659  *
660  ******************************************************************************/
661 
662 /*
663  * sbSeekableChannel
664  *
665  * This method is the constructor for the seekable channel class.
666  */
667 
669 :
670  mCompleted(PR_FALSE)
671 {
672 }
673 
674 
675 /*
676  * ~sbSeekableChannel
677  *
678  * This method is the destructor for the seekable channel class.
679  */
680 
682 {
683 }
684 
685 
686 /*******************************************************************************
687  *
688  * Private seekable channel services.
689  *
690  ******************************************************************************/
691 
692 /*
693  * ReadSegment
694  *
695  * --> pStream Stream from which to read.
696  * --> numBytes Number of bytes to read.
697  *
698  * This function reads a segment of data from the stream specified by pStream.
699  * The size of the data segment is specified by numBytes.
700  */
701 
702 nsresult sbSeekableChannel::ReadSegment(
703  nsIInputStream *pStream,
704  PRUint32 numBytes)
705 {
706  Segment *pSegment = NULL;
707  char *buffer = NULL;
708  PRUint64 readOffset = mBasePos;
709  PRUint32 bytesRead;
710  nsresult result = NS_OK;
711 
712  /* Allocate a data segment buffer. */
713  buffer = (char *) nsMemory::Alloc(numBytes);
714  if (!buffer)
715  result = NS_ERROR_OUT_OF_MEMORY;
716 
717  /* Read data from the stream. */
718  if (NS_SUCCEEDED(result))
719  {
720  result = pStream->Read(buffer, numBytes, &bytesRead);
721  if (NS_SUCCEEDED(result))
722  {
723  mBasePos += bytesRead;
724  if (mBasePos > mContentLength)
725  mContentLength = mBasePos;
726  }
727  }
728 
729  /* Create a new data segment buffer. */
730  if (NS_SUCCEEDED(result))
731  {
732  pSegment = new Segment();
733  if (pSegment)
734  {
735  pSegment->offset = readOffset;
736  pSegment->length = bytesRead;
737  pSegment->buffer = buffer;
738  buffer = NULL;
739  }
740  else
741  {
742  result = NS_ERROR_UNEXPECTED;
743  }
744  }
745 
746  /* Insert the segment into the channel data set. */
747  if (NS_SUCCEEDED(result))
748  result = InsertSegment(pSegment);
749  if (NS_SUCCEEDED(result))
750  pSegment = NULL;
751 
752  /* Channel reading is complete if an error occured */
753  /* or if all of the channel data has been read. */
754  if (NS_FAILED(result) || AllDataRead())
755  mCompleted = PR_TRUE;
756 
757  /* Clean up on error. */
758  if (!NS_SUCCEEDED(result))
759  {
760  if (pSegment)
761  delete (pSegment);
762  if (buffer)
763  nsMemory::Free(buffer);
764  }
765 
766  return (result);
767 }
768 
769 
770 /*
771  * InsertSegment
772  *
773  * --> pInsertSegment Data segment to insert.
774  *
775  * This function inserts the data segment specified by pInsertSegment into the
776  * channel data set. If the insert segment intersects any segments in the data
777  * set, this function merges them.
778  */
779 
780 nsresult sbSeekableChannel::InsertSegment(
781  Segment *pInsertSegment)
782 {
783  DataSet::iterator dataSetIterator;
784  Segment *pSegment = NULL;
785  nsresult result = NS_OK;
786 
787  /* Find the first intersecting data segment and merge with it. If new */
788  /* data segment does not intersect any other data segments, simply insert */
789  /* it into data set. */
790  dataSetIterator = mChannelData.find(pInsertSegment);
791  if (dataSetIterator != mChannelData.end())
792  {
793  pSegment = *dataSetIterator;
794  mChannelData.erase(pSegment);
795  result = MergeSegments(pSegment, pInsertSegment, &pSegment);
796  InsertSegment(pSegment);
797  }
798  else
799  {
800  mChannelData.insert(pInsertSegment);
801  }
802 
803  return (result);
804 }
805 
806 
807 /*
808  * MergeSegments
809  *
810  * --> pSegment1, Segments to merge.
811  * pSegment2
812  * <-- ppMergedSegment Merged segment.
813  *
814  * This function merges the segments pSegment1 and pSegment2 and returns the
815  * merged segment in ppMergedSegment. The caller should not use pSegment1 or
816  * pSegment2 after this function returns; this function handles all required
817  * clean up.
818  */
819 
820 nsresult sbSeekableChannel::MergeSegments(
821  Segment *pSegment1,
822  Segment *pSegment2,
823  Segment **ppMergedSegment)
824 {
825  Segment *pToSegment;
826  Segment *pFromSegment;
827  PRUint64 mergedLength;
828  PRUint64 mergeFromOffset;
829  nsresult result = NS_OK;
830 
831  /* Use the segment with the smallest offset as the segment to merge to. */
832  if (pSegment1->offset <= pSegment2->offset)
833  {
834  pToSegment = pSegment1;
835  pFromSegment = pSegment2;
836  }
837  else
838  {
839  pToSegment = pSegment2;
840  pFromSegment = pSegment1;
841  }
842 
843  /* Determine the starting merge offset within the segment to merge from. */
844  mergeFromOffset = pToSegment->offset + pToSegment->length
845  - pFromSegment->offset;
846 
847  /* Merge if the segment to merge from is not */
848  /* fully contained in the segment to merge to. */
849  if (mergeFromOffset < pFromSegment->length)
850  {
851  /* Compute the merged segment length. */
852  mergedLength = pFromSegment->offset + pFromSegment->length
853  - pToSegment->offset;
854 
855  /* Reallocate the segment buffer to merge to. */
856  pToSegment->buffer =
857  (char *) nsMemory::Realloc(pToSegment->buffer, static_cast<PRSize>(mergedLength));
858  if (!pToSegment->buffer)
859  result = NS_ERROR_OUT_OF_MEMORY;
860 
861  /* Copy the merge data. */
862  if (NS_SUCCEEDED(result))
863  {
864  memcpy(pToSegment->buffer + pToSegment->length,
865  pFromSegment->buffer + mergeFromOffset,
866  static_cast<PRSize>(pFromSegment->length - mergeFromOffset));
867  pToSegment->length = mergedLength;
868  }
869  }
870 
871  /* Dispose of the segment merged from. */
872  delete(pFromSegment);
873 
874  /* Dispose of the segment merged to on error. */
875  if (!NS_SUCCEEDED(result))
876  delete(pToSegment);
877 
878  /* Return results. */
879  if (NS_SUCCEEDED(result))
880  *ppMergedSegment = pToSegment;
881 
882  return (result);
883 }
884 
885 
886 /*
887  * AllDataRead
888  *
889  * <-- True if all channel data has been read.
890  *
891  * This function returns true if all of the channel data has been read.
892  */
893 
894 PRBool sbSeekableChannel::AllDataRead()
895 {
896  DataSet::iterator dataSetIterator;
897  Segment *pFirstSegment;
898  PRBool allDataRead = PR_FALSE;
899 
900  /* When all data has been read, the data set will consist of */
901  /* a single segment containing all of the channel content. */
902  dataSetIterator = mChannelData.begin();
903  if (dataSetIterator != mChannelData.end())
904  {
905  pFirstSegment = *dataSetIterator;
906  if ( (pFirstSegment->offset == 0)
907  && (pFirstSegment->length == mContentLength))
908  {
909  allDataRead = PR_TRUE;
910  }
911  }
912 
913  return (allDataRead);
914 }
915 
916 
917 /*
918  * Restart
919  *
920  * --> pos New channel position.
921  *
922  * This function restarts the base channel at the position specified by pos.
923  */
924 
925 nsresult sbSeekableChannel::Restart(
926  PRUint64 pos)
927 {
928  nsCOMPtr<nsIResumableChannel>
929  pResumableChannel;
930  nsCOMPtr<nsIURI> pURI;
931  nsCOMPtr<nsIIOService> pIOService;
932  nsCOMPtr<nsIRequest> pRequest;
933  nsresult result = NS_OK;
934 
935  /* Do nothing if already restarting or if the */
936  /* base channel position is not being changed. */
937  if ((mRestarting) || (mBasePos == pos))
938  return (result);
939 
940  /* Check if channel is resumable. */
941  pResumableChannel = do_QueryInterface(mpChannel, &result);
942 
943  /* Get the channel URI. */
944  if (NS_SUCCEEDED(result))
945  result = mpChannel->GetURI(getter_AddRefs(pURI));
946 
947  /* Shut down channel. */
948  if (NS_SUCCEEDED(result))
949  {
950  mpChannel->Cancel(NS_ERROR_ABORT);
951  mpChannel = nsnull;
952  }
953 
954  /* Get a new channel. */
955  if (NS_SUCCEEDED(result))
956  {
957  pIOService = do_GetService("@mozilla.org/network/io-service;1",
958  &result);
959  }
960  if (NS_SUCCEEDED(result))
961  result = pIOService->NewChannelFromURI(pURI, getter_AddRefs(mpChannel));
962 
963  /* Set up the channel request load flags. */
964  if (NS_SUCCEEDED(result))
965  {
966  pRequest = do_QueryInterface(mpChannel, &result);
967  if (NS_SUCCEEDED(result))
968  {
969  result = pRequest->SetLoadFlags
970  ( nsIRequest::INHIBIT_CACHING
971  | nsIRequest::INHIBIT_PERSISTENT_CACHING
972  | nsIRequest::LOAD_BYPASS_CACHE);
973  }
974  NS_ASSERTION(NS_SUCCEEDED(result),
975  "Setting load flags failed "
976  ":( Watch out, app will deadlock.");
977  }
978 
979  /* Resume channel. */
980  if (NS_SUCCEEDED(result))
981  pResumableChannel = do_QueryInterface(mpChannel, &result);
982  if (NS_SUCCEEDED(result))
983  pResumableChannel->ResumeAt(pos, NS_LITERAL_CSTRING(""));
984  if (NS_SUCCEEDED(result))
985  mpChannel->AsyncOpen(this, nsnull);
986 
987  /* Set new base channel position and restarting indication. */
988  if (NS_SUCCEEDED(result))
989  {
990  mBasePos = pos;
991  mRestarting = PR_TRUE;
992  }
993 
994  return (result);
995 }
996 
997 
998 /*
999  * DumpChannelData
1000  *
1001  * This function dumps the channel data set.
1002  */
1003 
1004 void sbSeekableChannel::DumpChannelData()
1005 {
1006  DataSet::iterator segmentIterator;
1007  Segment *pSegment;
1008 
1009  for (segmentIterator = mChannelData.begin();
1010  segmentIterator != mChannelData.end();
1011  segmentIterator++)
1012  {
1013  pSegment = *segmentIterator;
1014  LOG(("Segment 0x%08x 0x%08x\n",
1015  (PRUint32) (pSegment->offset & 0xFFFFFFFF),
1016  (PRUint32) (pSegment->length & 0xFFFFFFFF)));
1017  LOG((" 0x%08x\n", ((PRUint32 *) pSegment->buffer)[0]));
1018  }
1019 }
1020 
1021 
1022 /*******************************************************************************
1023  *
1024  * Private seekable channel data segment services.
1025  *
1026  ******************************************************************************/
1027 
1028 
1029 /*
1030  * Segment
1031  *
1032  * This method is the constructor for the Segment class.
1033  */
1034 
1035 sbSeekableChannel::Segment::Segment()
1036 :
1037  offset(0),
1038  length(0),
1039  buffer(NULL)
1040 {
1041 }
1042 
1043 
1044 /*
1045  * ~Segment
1046  *
1047  * This method is the destructor for the Segment class.
1048  */
1049 
1050 sbSeekableChannel::Segment::~Segment()
1051 {
1052  if (buffer)
1053  nsMemory::Free(buffer);
1054 }
1055 
1056 
1057 /*
1058  * operator
1059  *
1060  * --> pSegment1, Segments to compare.
1061  * pSegment2
1062  *
1063  * This function implements the comparison operator for a std::set.
1064  * If pSegment1 comes before pSegment2, this function returns true.
1065  * A data segment is considered to come before another if its offset
1066  * is the lesser of the two and if the two segments do not intersect.
1067  * Thus, intersecting segments are considered to be equivalent. This
1068  * property is useful for segment merging.
1069  */
1070 
1071 bool sbSeekableChannel::Segment::operator()(
1072  const Segment *pSegment1,
1073  const Segment *pSegment2) const
1074 {
1075  return ( (pSegment1->offset + pSegment1->length)
1076  < pSegment2->offset);
1077 }
1078 
1079 
return NS_OK
_dialogDatepicker pos
virtual ~sbSeekableChannel()
sbDeviceFirmwareAutoCheckForUpdate prototype flags
const NS_ERROR_ABORT
sbOSDControlService prototype QueryInterface
A seekable wrapper for an nsIChannel.
NS_DECL_ISUPPORTS NS_DECL_SBISEEKABLECHANNEL NS_DECL_NSISTREAMLISTENER NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSICHANNELEVENTSINK NS_DECL_NSIINTERFACEREQUESTOR sbSeekableChannel()
NS_IMPL_THREADSAFE_ISUPPORTS5(sbSeekableChannel, sbISeekableChannel, nsIStreamListener, nsIRequestObserver, nsIChannelEventSink, nsIInterfaceRequestor) NS_IMETHODIMP sbSeekableChannel
attribute PRUInt64 pos
The current read position (for the read methods)
PRUint32 & offset
BogusChannel prototype contentLength
const nsIChannel
#define NS_ERROR_SONGBIRD_SEEKABLE_CHANNEL_RESTART
A listener interface for sbISeekableChannel.
#define LOG(args)
Songbird Seekable Channel Component Definition.
const nsIInterfaceRequestor