QTAtomReader.cpp
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 :miv */
3 /*
4 //=BEGIN SONGBIRD GPL
5 //
6 // This file is part of the Songbird web player.
7 //
8 // Copyright(c) 2005-2009 POTI, Inc.
9 // http://www.songbirdnest.com
10 //
11 // This file may be licensed under the terms of of the
12 // GNU General Public License Version 2 (the GPL).
13 //
14 // Software distributed under the License is distributed
15 // on an AS IS basis, WITHOUT WARRANTY OF ANY KIND, either
16 // express or implied. See the GPL for the specific language
17 // governing rights and limitations.
18 //
19 // You should have received a copy of the GPL along with this
20 // program. If not, go to http://www.gnu.org/licenses/gpl.html
21 // or write to the Free Software Foundation, Inc.,
22 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 //
24 //=END SONGBIRD GPL
25 */
26 
32 //------------------------------------------------------------------------------
33 //
34 // QuickTime atom reader imported services.
35 //
36 //------------------------------------------------------------------------------
37 
38 // Self imports.
39 #include "QTAtomReader.h"
40 
41 // Mozilla imports.
42 #include <nsComponentManagerUtils.h>
43 #include <prnetdb.h>
44 
45 
46 //------------------------------------------------------------------------------
47 //
48 // QuickTime atom reader services.
49 //
50 //------------------------------------------------------------------------------
51 
57  mAtomHdrSize(20)
58 {
59 }
60 
61 
67 {
68 }
69 
70 
77 nsresult
78 QTAtomReader::Open(nsIFile* aFile)
79 {
80  // Validate arguments.
81  NS_ENSURE_ARG_POINTER(aFile);
82 
83  // Function variables.
84  nsresult rv;
85 
86  // Save the file object.
87  mFile = aFile;
88 
89  // Get and initialize a file input stream.
90  mFileInputStream = do_CreateInstance
91  ("@mozilla.org/network/file-input-stream;1", &rv);
92  NS_ENSURE_SUCCESS(rv, rv);
93  rv = mFileInputStream->Init(mFile, PR_RDONLY, 0, 0);
94  NS_ENSURE_SUCCESS(rv, rv);
95 
96  // Get seekable and generic input streams. */
97  mSeekableStream = do_QueryInterface(mFileInputStream, &rv);
98  NS_ENSURE_SUCCESS(rv, rv);
99  mInputStream = do_QueryInterface(mFileInputStream, &rv);
100  NS_ENSURE_SUCCESS(rv, rv);
101 
102  return NS_OK;
103 }
104 
105 
110 void
112 {
113  // Close the stream.
114  if (mInputStream)
115  mInputStream->Close();
116  mInputStream = nsnull;
117 }
118 
119 
128 nsresult
129 QTAtomReader::GetFairPlayAccountName(nsAString& aAccountName)
130 {
131  PRUint32 atom[2];
132  PRUint64 offset = 0;
133  nsresult rv;
134 
135  // Get the starting end offset.
136  PRInt64 fileSize;
137  PRUint64 endOffset;
138  rv = mFile->GetFileSize(&fileSize);
139  NS_ENSURE_SUCCESS(rv, rv);
140  endOffset = fileSize;
141 
142  // Set the atom header size.
143  mAtomHdrSize = 8;
144 
145  // Get the meta-data atom.
146  rv = AtomPathGet("/moov/udta/meta", &atom, &offset, &endOffset);
147  NS_ENSURE_SUCCESS(rv, rv);
148 
149  // Get the FairPlay account name atom, skipping the sample description table
150  // atom header.
151  offset += 12;
152  rv = AtomPathGet("/ilst/apID/data", &atom, &offset, &endOffset);
153  NS_ENSURE_SUCCESS(rv, rv);
154 
155  // Get the FairPlay account name size and offset.
156  offset += 16;
157  PRUint32 accountNameSize = (PRUint32)(endOffset - offset);
158 
159  // Allocate an account name buffer and set up for auto-disposal.
160  char* accountNameBuffer = (char*) NS_Alloc(accountNameSize + 1);
161  NS_ENSURE_TRUE(accountNameBuffer, NS_ERROR_OUT_OF_MEMORY);
162  sbAutoNSMemPtr autoAccountNameBuffer(accountNameBuffer);
163 
164  // Read the account name.
165  PRUint32 bytesRead;
166  rv = mSeekableStream->Seek(nsISeekableStream::NS_SEEK_SET, offset);
167  NS_ENSURE_SUCCESS(rv, rv);
168  rv = mInputStream->Read(accountNameBuffer, accountNameSize, &bytesRead);
169  NS_ENSURE_SUCCESS(rv, rv);
170  NS_ENSURE_TRUE(bytesRead >= accountNameSize, NS_ERROR_FAILURE);
171  accountNameBuffer[accountNameSize] = '\0';
172 
173  // Return results.
174  aAccountName.Assign(NS_ConvertUTF8toUTF16(accountNameBuffer));
175 
176  return NS_OK;
177 }
178 
179 
188 nsresult
190 {
191  PRUint32 atom[2];
192  PRUint64 offset = 0;
193  nsresult rv;
194 
195  // Get the starting end offset.
196  PRInt64 fileSize;
197  PRUint64 endOffset;
198  rv = mFile->GetFileSize(&fileSize);
199  NS_ENSURE_SUCCESS(rv, rv);
200  endOffset = fileSize;
201 
202  // Set the atom header size.
203  mAtomHdrSize = 8;
204 
205  // Get the sample description table atom.
206  rv = AtomPathGet("/moov/trak/mdia/minf/stbl/stsd",
207  &atom,
208  &offset,
209  &endOffset);
210  NS_ENSURE_SUCCESS(rv, rv);
211 
212  // Get the FairPlay DRM atom, skipping the sample description table
213  // atom header.
214  offset += 16;
215  rv = AtomPathGet("/drms", &atom, &offset, &endOffset);
216  NS_ENSURE_SUCCESS(rv, rv);
217 
218  // Get the FairPlay user name atom, skipping the FairPlay DRM atom header.
219  offset += 0x24;
220  rv = AtomPathGet("/sinf/schi/name", &atom, &offset, &endOffset);
221  NS_ENSURE_SUCCESS(rv, rv);
222 
223  // Get the FairPlay user name size and offset.
224  offset += 8;
225  PRUint32 userNameSize = (PRUint32)(endOffset - offset);
226 
227  // Allocate a user name buffer and set up for auto-disposal.
228  char* userNameBuffer = (char*) NS_Alloc(userNameSize + 1);
229  NS_ENSURE_TRUE(userNameBuffer, NS_ERROR_OUT_OF_MEMORY);
230  sbAutoNSMemPtr autoUserNameBuffer(userNameBuffer);
231 
232  // Read the user name.
233  PRUint32 bytesRead;
234  rv = mSeekableStream->Seek(nsISeekableStream::NS_SEEK_SET, offset);
235  NS_ENSURE_SUCCESS(rv, rv);
236  rv = mInputStream->Read(userNameBuffer, userNameSize, &bytesRead);
237  NS_ENSURE_SUCCESS(rv, rv);
238  NS_ENSURE_TRUE(bytesRead >= userNameSize, NS_ERROR_FAILURE);
239  userNameBuffer[userNameSize] = '\0';
240 
241  // Return results.
242  aUserName.Assign(NS_ConvertUTF8toUTF16(userNameBuffer));
243 
244  return NS_OK;
245 }
246 
247 
256 nsresult
258 {
259  // Validate arguments.
260  NS_ENSURE_ARG_POINTER(aUserID);
261 
262  // Function variables.
263  PRUint32 atom[2];
264  PRUint64 offset = 0;
265  nsresult rv;
266 
267  // Get the starting end offset.
268  PRInt64 fileSize;
269  PRUint64 endOffset;
270  rv = mFile->GetFileSize(&fileSize);
271  NS_ENSURE_SUCCESS(rv, rv);
272  endOffset = fileSize;
273 
274  // Set the atom header size.
275  mAtomHdrSize = 8;
276 
277  // Get the sample description table atom.
278  rv = AtomPathGet("/moov/trak/mdia/minf/stbl/stsd",
279  &atom,
280  &offset,
281  &endOffset);
282  NS_ENSURE_SUCCESS(rv, rv);
283 
284  // Get the FairPlay DRM atom, skipping the sample description table
285  // atom header.
286  offset += 16;
287  rv = AtomPathGet("/drms", &atom, &offset, &endOffset);
288  NS_ENSURE_SUCCESS(rv, rv);
289 
290  // Get the FairPlay user ID atom, skipping the FairPlay DRM atom header.
291  offset += 0x24;
292  rv = AtomPathGet("/sinf/schi/user", &atom, &offset, &endOffset);
293  NS_ENSURE_SUCCESS(rv, rv);
294 
295  // Read the user ID.
296  PRUint32 userIDAtom[3];
297  PRUint32 bytesRead;
298  PRUint32 userID;
299  rv = mSeekableStream->Seek(nsISeekableStream::NS_SEEK_SET, offset);
300  NS_ENSURE_SUCCESS(rv, rv);
301  rv = mInputStream->Read((char *) userIDAtom, sizeof(userIDAtom), &bytesRead);
302  NS_ENSURE_SUCCESS(rv, rv);
303  NS_ENSURE_TRUE(bytesRead >= sizeof(userIDAtom), NS_ERROR_FAILURE);
304  userID = PR_ntohl(userIDAtom[2]);
305 
306  // Return results.
307  *aUserID = userID;
308 
309  return NS_OK;
310 }
311 
312 
320 nsresult
321 QTAtomReader::GetIEKInfoUserIDs(nsTArray<PRUint32>& aUserIDList)
322 {
323  PRUint32 atom[2];
324  PRUint64 offset;
325  nsresult rv;
326 
327  // Get the starting offsets.
328  PRInt64 fileSize;
329  PRUint64 endOffset;
330  rv = mFile->GetFileSize(&fileSize);
331  NS_ENSURE_SUCCESS(rv, rv);
332  offset = 0x4C;
333  endOffset = fileSize;
334 
335  // Get the root atom.
336  rv = AtomPathGet("/sean", &atom, &offset, &endOffset);
337  NS_ENSURE_SUCCESS(rv, rv);
338  offset += mAtomHdrSize;
339 
340  // Get the FairPlay user IDs.
341  while (1) {
342  // Get the next FairPlay user ID atom.
343  PRUint64 userIDEndOffset = endOffset;
344  rv = AtomPathGet("/user", &atom, &offset, &userIDEndOffset);
345  if (NS_FAILED(rv))
346  break;
347 
348  // Read the user ID.
349  PRUint32 userIDAtom[3];
350  PRUint32 userID;
351  PRUint32 bytesRead;
352  rv = mSeekableStream->Seek(nsISeekableStream::NS_SEEK_SET, offset);
353  NS_ENSURE_SUCCESS(rv, rv);
354  rv = mInputStream->Read((char *) userIDAtom,
355  sizeof(userIDAtom),
356  &bytesRead);
357  NS_ENSURE_SUCCESS(rv, rv);
358  NS_ENSURE_TRUE(bytesRead >= sizeof(userIDAtom), NS_ERROR_FAILURE);
359  userID = PR_ntohl(userIDAtom[2]);
360 
361  // Add the user ID to the list.
362  aUserIDList.AppendElement(userID);
363 
364  // Advance past the user ID atom.
365  offset += atom[0];
366  }
367 
368  return NS_OK;
369 }
370 
371 
386 nsresult
387 QTAtomReader::AtomPathGet(const char* aAtomPath,
388  void* aAtom,
389  PRUint64* aStartOffset,
390  PRUint64* aEndOffset)
391 {
392  // Validate parameters.
393  NS_ASSERTION(aAtomPath, "aAtomPath is null");
394  NS_ASSERTION(aAtom, "aAtom is null");
395  NS_ASSERTION(aStartOffset, "aStartOffset is null");
396  NS_ASSERTION(aEndOffset, "aEndOffset is null");
397 
398  // Function variables.
399  PRUint32 atom[2];
400  nsresult rv;
401 
402  // Get the offsets.
403  PRUint64 offset = *aStartOffset;
404  PRUint64 endOffset = *aEndOffset;
405 
406  // Search for each atom in the specified path.
407  int numAtoms = strlen(aAtomPath) / 5;
408  const char* pAtomType = aAtomPath;
409  for (int i = 0; i < numAtoms; i++) {
410  // Skip leading "/".
411  pAtomType += 1;
412 
413  // Skip parent atom header.
414  if (i > 0)
415  offset += mAtomHdrSize;
416 
417  // Get the atom type.
418  PRUint32 atomType = (pAtomType[0] << 24) |
419  (pAtomType[1] << 16) |
420  (pAtomType[2] << 8) |
421  pAtomType[3];
422  pAtomType += 4;
423 
424  // Get the atom offset.
425  rv = AtomGet(atomType, &atom, &offset, &endOffset);
426  if (NS_FAILED(rv))
427  return rv;
428  }
429 
430  // Return results.
431  memcpy(aAtom, atom, sizeof(atom));
432  *aStartOffset = offset;
433  *aEndOffset = endOffset;
434 
435  return NS_OK;
436 }
437 
438 
453 nsresult
454 QTAtomReader::AtomGet(PRUint32 aAtomType,
455  void* aAtom,
456  PRUint64* aStartOffset,
457  PRUint64* aEndOffset)
458 {
459  // Validate parameters.
460  NS_ASSERTION(aAtom, "aAtom is null");
461  NS_ASSERTION(aStartOffset, "aStartOffset is null");
462  NS_ASSERTION(aEndOffset, "aEndOffset is null");
463 
464  // Function variables.
465  PRUint32 atom[2];
466  nsresult rv;
467 
468  // Get the offsets.
469  PRUint64 offset = *aStartOffset;
470  PRUint64 endOffset = *aEndOffset;
471 
472  // Search for the specified atom.
473  PRBool found = PR_FALSE;
474  while (offset < endOffset) {
475  // Seek to the current offset.
476  rv = mSeekableStream->Seek(nsISeekableStream::NS_SEEK_SET, offset);
477  NS_ENSURE_SUCCESS(rv, rv);
478 
479  // Read the current atom.
480  PRUint32 bytesRead;
481  rv = mInputStream->Read((char *) atom, sizeof(atom), &bytesRead);
482  NS_ENSURE_SUCCESS(rv, rv);
483  NS_ENSURE_TRUE(bytesRead >= sizeof(atom), NS_ERROR_FAILURE);
484 
485  // Convert the atom fields to host byte order.
486  atom[0] = PR_ntohl(atom[0]);
487  atom[1] = PR_ntohl(atom[1]);
488 
489  // Get the atom fields.
490  PRUint32 curAtomSize = atom[0];
491  PRUint32 curAtomType = atom[1];
492 
493  // Validate atom size.
494  NS_ENSURE_TRUE(curAtomSize >= mAtomHdrSize, NS_ERROR_FAILURE);
495 
496  // Check if the current atom is the one to get.
497  if (curAtomType == aAtomType) {
498  found = PR_TRUE;
499  break;
500  } else {
501  offset += curAtomSize;
502  }
503  }
504 
505  // Check if the atom was found.
506  if (!found)
507  return NS_ERROR_FAILURE;
508 
509  // Return results.
510  memcpy(aAtom, atom, sizeof(atom));
511  *aStartOffset = offset;
512  *aEndOffset = offset + atom[0];
513 
514  return NS_OK;
515 }
516 
517 
return NS_OK
const PR_RDONLY
void Close(void)
nsresult GetFairPlayAccountName(nsAString &aAccountName)
virtual ~QTAtomReader()
nsresult GetFairPlayUserName(nsAString &aUserName)
nsresult Open(nsIFile *aFile)
PRUint32 & offset
QuickTime Atom Reader Definitions.
nsresult GetIEKInfoUserIDs(nsTArray< PRUint32 > &aUserIDList)
nsresult AtomPathGet(const char *aAtomPath, void *aAtom, PRUint64 *aStartOffset, PRUint64 *aEndOffset)
_getSelectedPageStyle s i
nsresult GetFairPlayUserID(PRUint32 *aUserID)