Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/media/FileMediaResource.cpp
Line
Count
Source (jump to first uncovered line)
1
/* vim:set ts=2 sw=2 sts=2 et cindent: */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#include "FileMediaResource.h"
7
8
#include "mozilla/AbstractThread.h"
9
#include "mozilla/dom/BlobImpl.h"
10
#include "mozilla/dom/BlobURLProtocolHandler.h"
11
#include "nsContentUtils.h"
12
#include "nsIFileChannel.h"
13
#include "nsIFileStreams.h"
14
#include "nsNetUtil.h"
15
16
namespace mozilla {
17
18
void
19
FileMediaResource::EnsureSizeInitialized()
20
0
{
21
0
  mLock.AssertCurrentThreadOwns();
22
0
  NS_ASSERTION(mInput, "Must have file input stream");
23
0
  if (mSizeInitialized && mNotifyDataEndedProcessed) {
24
0
    return;
25
0
  }
26
0
27
0
  if (!mSizeInitialized) {
28
0
    // Get the file size and inform the decoder.
29
0
    uint64_t size;
30
0
    nsresult res = mInput->Available(&size);
31
0
    if (NS_SUCCEEDED(res) && size <= INT64_MAX) {
32
0
      mSize = (int64_t)size;
33
0
    }
34
0
  }
35
0
  mSizeInitialized = true;
36
0
  if (!mNotifyDataEndedProcessed && mSize >= 0) {
37
0
    mCallback->AbstractMainThread()->Dispatch(
38
0
      NewRunnableMethod<nsresult>("MediaResourceCallback::NotifyDataEnded",
39
0
                                  mCallback.get(),
40
0
                                  &MediaResourceCallback::NotifyDataEnded,
41
0
                                  NS_OK));
42
0
  }
43
0
  mNotifyDataEndedProcessed = true;
44
0
}
45
46
nsresult
47
FileMediaResource::GetCachedRanges(MediaByteRangeSet& aRanges)
48
0
{
49
0
  MutexAutoLock lock(mLock);
50
0
51
0
  EnsureSizeInitialized();
52
0
  if (mSize == -1) {
53
0
    return NS_ERROR_FAILURE;
54
0
  }
55
0
  aRanges += MediaByteRange(0, mSize);
56
0
  return NS_OK;
57
0
}
58
59
nsresult
60
FileMediaResource::Open(nsIStreamListener** aStreamListener)
61
0
{
62
0
  NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
63
0
  MOZ_ASSERT(aStreamListener);
64
0
65
0
  *aStreamListener = nullptr;
66
0
  nsresult rv = NS_OK;
67
0
68
0
  // The channel is already open. We need a synchronous stream that
69
0
  // implements nsISeekableStream, so we have to find the underlying
70
0
  // file and reopen it
71
0
  nsCOMPtr<nsIFileChannel> fc(do_QueryInterface(mChannel));
72
0
  if (fc) {
73
0
    nsCOMPtr<nsIFile> file;
74
0
    rv = fc->GetFile(getter_AddRefs(file));
75
0
    NS_ENSURE_SUCCESS(rv, rv);
76
0
77
0
    rv = NS_NewLocalFileInputStream(
78
0
      getter_AddRefs(mInput), file, -1, -1, nsIFileInputStream::SHARE_DELETE);
79
0
    NS_ENSURE_SUCCESS(rv, rv);
80
0
  } else if (dom::IsBlobURI(mURI)) {
81
0
    RefPtr<dom::BlobImpl> blobImpl;
82
0
    rv = NS_GetBlobForBlobURI(mURI, getter_AddRefs(blobImpl));
83
0
    NS_ENSURE_SUCCESS(rv, rv);
84
0
    MOZ_ASSERT(blobImpl);
85
0
86
0
    ErrorResult err;
87
0
    blobImpl->CreateInputStream(getter_AddRefs(mInput), err);
88
0
    if (NS_WARN_IF(err.Failed())) {
89
0
      return err.StealNSResult();
90
0
    }
91
0
  }
92
0
93
0
  mSeekable = do_QueryInterface(mInput);
94
0
  if (!mSeekable) {
95
0
    // XXX The file may just be a .url or similar
96
0
    // shortcut that points to a Web site. We need to fix this by
97
0
    // doing an async open and waiting until we locate the real resource,
98
0
    // then using that (if it's still a file!).
99
0
    return NS_ERROR_FAILURE;
100
0
  }
101
0
102
0
  return NS_OK;
103
0
}
104
105
nsresult
106
FileMediaResource::Close()
107
0
{
108
0
  NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
109
0
110
0
  // Since mChennel is only accessed by main thread, there is no necessary to
111
0
  // take the lock.
112
0
  if (mChannel) {
113
0
    mChannel->Cancel(NS_ERROR_PARSED_DATA_CACHED);
114
0
    mChannel = nullptr;
115
0
  }
116
0
117
0
  return NS_OK;
118
0
}
119
120
already_AddRefed<nsIPrincipal>
121
FileMediaResource::GetCurrentPrincipal()
122
0
{
123
0
  NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
124
0
125
0
  nsCOMPtr<nsIPrincipal> principal;
126
0
  nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
127
0
  if (!secMan || !mChannel)
128
0
    return nullptr;
129
0
  secMan->GetChannelResultPrincipal(mChannel, getter_AddRefs(principal));
130
0
  return principal.forget();
131
0
}
132
133
nsresult
134
FileMediaResource::ReadFromCache(char* aBuffer, int64_t aOffset,
135
                                 uint32_t aCount)
136
0
{
137
0
  MutexAutoLock lock(mLock);
138
0
139
0
  EnsureSizeInitialized();
140
0
  if (!aCount) {
141
0
    return NS_OK;
142
0
  }
143
0
  int64_t offset = 0;
144
0
  nsresult res = mSeekable->Tell(&offset);
145
0
  NS_ENSURE_SUCCESS(res,res);
146
0
  res = mSeekable->Seek(nsISeekableStream::NS_SEEK_SET, aOffset);
147
0
  NS_ENSURE_SUCCESS(res,res);
148
0
  uint32_t bytesRead = 0;
149
0
  do {
150
0
    uint32_t x = 0;
151
0
    uint32_t bytesToRead = aCount - bytesRead;
152
0
    res = mInput->Read(aBuffer, bytesToRead, &x);
153
0
    bytesRead += x;
154
0
    if (!x) {
155
0
      res = NS_ERROR_FAILURE;
156
0
    }
157
0
  } while (bytesRead != aCount && res == NS_OK);
158
0
159
0
  // Reset read head to original position so we don't disturb any other
160
0
  // reading thread.
161
0
  nsresult seekres = mSeekable->Seek(nsISeekableStream::NS_SEEK_SET, offset);
162
0
163
0
  // If a read failed in the loop above, we want to return its failure code.
164
0
  NS_ENSURE_SUCCESS(res,res);
165
0
166
0
  // Else we succeed if the reset-seek succeeds.
167
0
  return seekres;
168
0
}
169
170
nsresult
171
FileMediaResource::UnsafeRead(char* aBuffer, uint32_t aCount, uint32_t* aBytes)
172
0
{
173
0
  EnsureSizeInitialized();
174
0
  return mInput->Read(aBuffer, aCount, aBytes);
175
0
}
176
177
nsresult
178
FileMediaResource::ReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount,
179
                          uint32_t* aBytes)
180
0
{
181
0
  NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
182
0
183
0
  nsresult rv;
184
0
  {
185
0
    MutexAutoLock lock(mLock);
186
0
    rv = UnsafeSeek(nsISeekableStream::NS_SEEK_SET, aOffset);
187
0
    if (NS_FAILED(rv)) return rv;
188
0
    rv = UnsafeRead(aBuffer, aCount, aBytes);
189
0
  }
190
0
  return rv;
191
0
}
192
193
already_AddRefed<MediaByteBuffer>
194
FileMediaResource::UnsafeMediaReadAt(int64_t aOffset, uint32_t aCount)
195
0
{
196
0
  RefPtr<MediaByteBuffer> bytes = new MediaByteBuffer();
197
0
  bool ok = bytes->SetLength(aCount, fallible);
198
0
  NS_ENSURE_TRUE(ok, nullptr);
199
0
  nsresult rv = UnsafeSeek(nsISeekableStream::NS_SEEK_SET, aOffset);
200
0
  NS_ENSURE_SUCCESS(rv, nullptr);
201
0
  char* curr = reinterpret_cast<char*>(bytes->Elements());
202
0
  const char* start = curr;
203
0
  while (aCount > 0) {
204
0
    uint32_t bytesRead;
205
0
    rv = UnsafeRead(curr, aCount, &bytesRead);
206
0
    NS_ENSURE_SUCCESS(rv, nullptr);
207
0
    if (!bytesRead) {
208
0
      break;
209
0
    }
210
0
    aCount -= bytesRead;
211
0
    curr += bytesRead;
212
0
  }
213
0
  bytes->SetLength(curr - start);
214
0
  return bytes.forget();
215
0
}
216
217
nsresult
218
FileMediaResource::UnsafeSeek(int32_t aWhence, int64_t aOffset)
219
0
{
220
0
  NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
221
0
222
0
  if (!mSeekable)
223
0
    return NS_ERROR_FAILURE;
224
0
  EnsureSizeInitialized();
225
0
  return mSeekable->Seek(aWhence, aOffset);
226
0
}
227
228
} // mozilla namespace