1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "GMPUtils.h"
8 #include "nsDirectoryServiceDefs.h"
9 #include "nsIFile.h"
10 #include "nsCOMPtr.h"
11 #include "nsLiteralString.h"
12 #include "nsCRTGlue.h"
13 #include "mozilla/Base64.h"
14 #include "nsISimpleEnumerator.h"
15
16 namespace mozilla {
17
18 bool
GetEMEVoucherPath(nsIFile ** aPath)19 GetEMEVoucherPath(nsIFile** aPath)
20 {
21 nsCOMPtr<nsIFile> path;
22 NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(path));
23 if (!path) {
24 NS_WARNING("GetEMEVoucherPath can't get NS_GRE_DIR!");
25 return false;
26 }
27 path->AppendNative(NS_LITERAL_CSTRING("voucher.bin"));
28 path.forget(aPath);
29 return true;
30 }
31
32 bool
EMEVoucherFileExists()33 EMEVoucherFileExists()
34 {
35 nsCOMPtr<nsIFile> path;
36 bool exists;
37 return GetEMEVoucherPath(getter_AddRefs(path)) &&
38 NS_SUCCEEDED(path->Exists(&exists)) &&
39 exists;
40 }
41
42 void
SplitAt(const char * aDelims,const nsACString & aInput,nsTArray<nsCString> & aOutTokens)43 SplitAt(const char* aDelims,
44 const nsACString& aInput,
45 nsTArray<nsCString>& aOutTokens)
46 {
47 nsAutoCString str(aInput);
48 char* end = str.BeginWriting();
49 const char* start = nullptr;
50 while (!!(start = NS_strtok(aDelims, &end))) {
51 aOutTokens.AppendElement(nsCString(start));
52 }
53 }
54
55 nsCString
ToBase64(const nsTArray<uint8_t> & aBytes)56 ToBase64(const nsTArray<uint8_t>& aBytes)
57 {
58 nsAutoCString base64;
59 nsDependentCSubstring raw(reinterpret_cast<const char*>(aBytes.Elements()),
60 aBytes.Length());
61 nsresult rv = Base64Encode(raw, base64);
62 if (NS_WARN_IF(NS_FAILED(rv))) {
63 return NS_LITERAL_CSTRING("[Base64EncodeFailed]");
64 }
65 return base64;
66 }
67
68 bool
FileExists(nsIFile * aFile)69 FileExists(nsIFile* aFile)
70 {
71 bool exists = false;
72 return aFile && NS_SUCCEEDED(aFile->Exists(&exists)) && exists;
73 }
74
DirectoryEnumerator(nsIFile * aPath,Mode aMode)75 DirectoryEnumerator::DirectoryEnumerator(nsIFile* aPath, Mode aMode)
76 : mMode(aMode)
77 {
78 aPath->GetDirectoryEntries(getter_AddRefs(mIter));
79 }
80
81 already_AddRefed<nsIFile>
Next()82 DirectoryEnumerator::Next()
83 {
84 if (!mIter) {
85 return nullptr;
86 }
87 bool hasMore = false;
88 while (NS_SUCCEEDED(mIter->HasMoreElements(&hasMore)) && hasMore) {
89 nsCOMPtr<nsISupports> supports;
90 nsresult rv = mIter->GetNext(getter_AddRefs(supports));
91 if (NS_FAILED(rv)) {
92 continue;
93 }
94
95 nsCOMPtr<nsIFile> path(do_QueryInterface(supports, &rv));
96 if (NS_FAILED(rv)) {
97 continue;
98 }
99
100 if (mMode == DirsOnly) {
101 bool isDirectory = false;
102 rv = path->IsDirectory(&isDirectory);
103 if (NS_FAILED(rv) || !isDirectory) {
104 continue;
105 }
106 }
107 return path.forget();
108 }
109 return nullptr;
110 }
111
112 bool
ReadIntoArray(nsIFile * aFile,nsTArray<uint8_t> & aOutDst,size_t aMaxLength)113 ReadIntoArray(nsIFile* aFile,
114 nsTArray<uint8_t>& aOutDst,
115 size_t aMaxLength)
116 {
117 if (!FileExists(aFile)) {
118 return false;
119 }
120
121 PRFileDesc* fd = nullptr;
122 nsresult rv = aFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
123 if (NS_FAILED(rv)) {
124 return false;
125 }
126
127 int32_t length = PR_Seek(fd, 0, PR_SEEK_END);
128 PR_Seek(fd, 0, PR_SEEK_SET);
129
130 if (length < 0 || (size_t)length > aMaxLength) {
131 NS_WARNING("EME file is longer than maximum allowed length");
132 PR_Close(fd);
133 return false;
134 }
135 aOutDst.SetLength(length);
136 int32_t bytesRead = PR_Read(fd, aOutDst.Elements(), length);
137 PR_Close(fd);
138 return (bytesRead == length);
139 }
140
141 bool
ReadIntoString(nsIFile * aFile,nsCString & aOutDst,size_t aMaxLength)142 ReadIntoString(nsIFile* aFile,
143 nsCString& aOutDst,
144 size_t aMaxLength)
145 {
146 nsTArray<uint8_t> buf;
147 bool rv = ReadIntoArray(aFile, buf, aMaxLength);
148 if (rv) {
149 buf.AppendElement(0); // Append null terminator, required by nsC*String.
150 aOutDst = nsDependentCString((const char*)buf.Elements(), buf.Length() - 1);
151 }
152 return rv;
153 }
154
155 bool
Init(nsIFile * aInfoFile)156 GMPInfoFileParser::Init(nsIFile* aInfoFile)
157 {
158 nsTArray<nsCString> lines;
159 static const size_t MAX_GMP_INFO_FILE_LENGTH = 5 * 1024;
160
161 nsAutoCString info;
162 if (!ReadIntoString(aInfoFile, info, MAX_GMP_INFO_FILE_LENGTH)) {
163 NS_WARNING("Failed to read info file in GMP process.");
164 return false;
165 }
166
167 // Note: we pass "\r\n" to SplitAt so that we'll split lines delimited
168 // by \n (Unix), \r\n (Windows) and \r (old MacOSX).
169 SplitAt("\r\n", info, lines);
170
171 for (nsCString line : lines) {
172 // Field name is the string up to but not including the first ':'
173 // character on the line.
174 int32_t colon = line.FindChar(':');
175 if (colon <= 0) {
176 // Not allowed to be the first character.
177 // Info field name must be at least one character.
178 continue;
179 }
180 nsAutoCString key(Substring(line, 0, colon));
181 ToLowerCase(key);
182 key.Trim(" ");
183
184 nsCString* value = new nsCString(Substring(line, colon + 1));
185 value->Trim(" ");
186 mValues.Put(key, value); // Hashtable assumes ownership of value.
187 }
188
189 return true;
190 }
191
192 bool
Contains(const nsCString & aKey) const193 GMPInfoFileParser::Contains(const nsCString& aKey) const {
194 nsCString key(aKey);
195 ToLowerCase(key);
196 return mValues.Contains(key);
197 }
198
199 nsCString
Get(const nsCString & aKey) const200 GMPInfoFileParser::Get(const nsCString& aKey) const {
201 MOZ_ASSERT(Contains(aKey));
202 nsCString key(aKey);
203 ToLowerCase(key);
204 nsCString* p = nullptr;
205 if (mValues.Get(key, &p)) {
206 return nsCString(*p);
207 }
208 return EmptyCString();
209 }
210
211 bool
HaveGMPFor(const nsCString & aAPI,nsTArray<nsCString> && aTags)212 HaveGMPFor(const nsCString& aAPI,
213 nsTArray<nsCString>&& aTags)
214 {
215 nsCOMPtr<mozIGeckoMediaPluginService> mps =
216 do_GetService("@mozilla.org/gecko-media-plugin-service;1");
217 if (NS_WARN_IF(!mps)) {
218 return false;
219 }
220
221 bool hasPlugin = false;
222 if (NS_FAILED(mps->HasPluginForAPI(aAPI, &aTags, &hasPlugin))) {
223 return false;
224 }
225 return hasPlugin;
226 }
227
228
229 } // namespace mozilla
230