/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 |