MetadataHandlerWMA.cpp
Go to the documentation of this file.
1 /*
2  *=BEGIN SONGBIRD GPL
3  *
4  * This file is part of the Songbird web player.
5  *
6  * Copyright(c) 2005-2009 POTI, Inc.
7  * http://www.songbirdnest.com
8  *
9  * This file may be licensed under the terms of of the
10  * GNU General Public License Version 2 (the ``GPL'').
11  *
12  * Software distributed under the License is distributed
13  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
14  * express or implied. See the GPL for the specific language
15  * governing rights and limitations.
16  *
17  * You should have received a copy of the GPL along with this
18  * program. If not, go to http://www.gnu.org/licenses/gpl.html
19  * or write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  *
22  *=END SONGBIRD GPL
23  */
24 
30 // INCLUDES ===================================================================
31 #include "MetadataHandlerWMA.h"
32 
33 /* Songbird interfaces */
34 #include "sbStandardProperties.h"
35 #include "sbIPropertyArray.h"
36 #include "sbPropertiesCID.h"
37 #include "sbMemoryUtils.h"
39 #include <sbStringUtils.h>
40 #include <sbFileUtils.h>
41 #include <sbAutoCOMInitializer.h>
42 
43 #include <nsIChannel.h>
44 #include <nsIContentSniffer.h>
45 #include <nsIFileStreams.h>
46 #include <nsIFileURL.h>
47 #include <nsIIOService.h>
48 #include <nsIURI.h>
49 
50 #include <nsNetUtil.h>
51 #include <nsUnicharUtils.h>
52 #include <prlog.h>
53 #include <prprf.h>
54 
55 #include <atlbase.h>
56 #include <wmsdk.h>
57 #include <wmp.h>
58 #include <wininet.h>
59 
60 #ifdef PR_LOGGING
61  static PRLogModuleInfo* gLog = PR_NewLogModule("sbMetadataHandlerWMA");
62  #define LOG(args) \
63  PR_BEGIN_MACRO \
64  if (gLog) PR_LOG(gLog, PR_LOG_WARN, args); \
65  PR_END_MACRO
66  #define TRACE(args) \
67  PR_BEGIN_MACRO \
68  if (gLog) PR_LOG(gLog, PR_LOG_DEBUG, args); \
69  PR_END_MACRO
70  #ifdef __GNUC__
71  #define __FUNCTION__ __PRETTY_FUNCTION__
72  #endif
73 #else
74  #define LOG(args) /* nothing */
75  #define TRACE(args) /* nothing */
76 #endif
77 
78 // DEFINES ====================================================================
79 
80 #define COM_ENSURE_SUCCESS(_val) \
81  PR_BEGIN_MACRO \
82  nsresult __rv = _val; \
83  if (FAILED(__rv)) { \
84  NS_ENSURE_SUCCESS_BODY(_val, _val); \
85  return NS_ERROR_FAILURE; \
86  } \
87  PR_END_MACRO
88 
89 #define countof(_array) \
90  sizeof(_array) / sizeof(_array[0])
91 
92 #define SB_ARTIST SB_PROPERTY_ARTISTNAME
93 #define SB_TITLE SB_PROPERTY_TRACKNAME
94 #define SB_ALBUM SB_PROPERTY_ALBUMNAME
95 #define SB_GENRE SB_PROPERTY_GENRE
96 #define SB_TRACKNO SB_PROPERTY_TRACKNUMBER
97 #define SB_VENDOR SB_PROPERTY_SOFTWAREVENDOR
98 #define SB_COPYRIGHT SB_PROPERTY_COPYRIGHT
99 #define SB_COMPOSER SB_PROPERTY_COMPOSERNAME
100 #define SB_CONDUCTOR SB_PROPERTY_CONDUCTORNAME
101 #define SB_DIRECTOR "director"
102 #define SB_BPM SB_PROPERTY_BPM
103 #define SB_LYRICS SB_PROPERTY_LYRICS
104 #define SB_YEAR SB_PROPERTY_YEAR
105 #define SB_BITRATE SB_PROPERTY_BITRATE
106 #define SB_RATING SB_PROPERTY_RATING
107 #define SB_COMMENT SB_PROPERTY_COMMENT
108 #define SB_LENGTH SB_PROPERTY_DURATION
109 #define SB_ALBUMARTIST SB_PROPERTY_ALBUMARTISTNAME
110 #define SB_PROTECTED SB_PROPERTY_ISDRMPROTECTED
111 
112 #define WMP_ARTIST "Author"
113 #define WMP_TITLE "Title"
114 #define WMP_ALBUM "WM/AlbumTitle"
115 #define WMP_GENRE "WM/Genre"
116 #define WMP_TRACKNO "WM/TrackNumber"
117 #define WMP_VENDOR "WM/ToolName"
118 #define WMP_COPYRIGHT "Copyright"
119 #define WMP_COMPOSER "WM/Composer"
120 #define WMP_CONDUCTOR "WM/Conductor"
121 #define WMP_DIRECTOR "WM/Director"
122 #define WMP_BPM "WM/BeatsPerMinute"
123 #define WMP_LYRICS "WM/Lyrics"
124 #define WMP_YEAR "WM/Year"
125 #define WMP_BITRATE "Bitrate"
126 #define WMP_RATING "Rating"
127 #define WMP_COMMENT "Description"
128 #define WMP_LENGTH "Duration"
129 #define WMP_ALBUMARTIST "WM/AlbumArtist"
130 #define WMP_PROTECTED "Is_Protected"
131 
132 // Property namespace for Gracenote properties
133 // Note that this must match those used in sbGracenoteDefines.h, so
134 // be sure to change those if you change these.
135 #define SB_GN_EXTENDEDDATA "http://gracenote.com/pos/1.0#extendedData"
136 #define SB_GN_TAGID "http://gracenote.com/pos/1.0#tagId"
137 #define WMP_GN_EXTENDEDDATA "GN/ExtData"
138 #define WMP_GN_TAGID "GN/UniqueFileIdentifier"
139 
140 
141 // These are the keys we're going to read from the WM interface
142 // and push to the SB interface.
143 typedef struct
144 {
145  PRUnichar const * const songbirdName;
146  TCHAR const * const wmpName;
147  WMT_ATTR_DATATYPE type;
149 
150 #define KEY_MAP_ENTRY(_entry, _type) { NS_L(SB_##_entry), \
151  NS_L(WMP_##_entry), \
152  _type }
153 
155  KEY_MAP_ENTRY(ARTIST, WMT_TYPE_STRING),
156  KEY_MAP_ENTRY(TITLE, WMT_TYPE_STRING),
157  KEY_MAP_ENTRY(ALBUM, WMT_TYPE_STRING),
158  KEY_MAP_ENTRY(GENRE, WMT_TYPE_STRING),
159  KEY_MAP_ENTRY(TRACKNO, WMT_TYPE_STRING),
160  KEY_MAP_ENTRY(VENDOR, WMT_TYPE_STRING),
161  KEY_MAP_ENTRY(COPYRIGHT, WMT_TYPE_STRING),
162  KEY_MAP_ENTRY(COMPOSER, WMT_TYPE_STRING),
163  KEY_MAP_ENTRY(CONDUCTOR, WMT_TYPE_STRING),
164  KEY_MAP_ENTRY(COMMENT, WMT_TYPE_STRING),
165  KEY_MAP_ENTRY(BPM, WMT_TYPE_STRING),
166  KEY_MAP_ENTRY(LYRICS, WMT_TYPE_STRING),
167  KEY_MAP_ENTRY(YEAR, WMT_TYPE_STRING),
168  KEY_MAP_ENTRY(BITRATE, WMT_TYPE_DWORD),
169  KEY_MAP_ENTRY(RATING, WMT_TYPE_STRING),
170 // KEY_MAP_ENTRY(DESCRIPTION, WMT_TYPE_STRING),
171 // KEY_MAP_ENTRY(DIRECTOR, WMT_TYPE_STRING),
172  KEY_MAP_ENTRY(LENGTH, WMT_TYPE_QWORD),
173  KEY_MAP_ENTRY(ALBUMARTIST, WMT_TYPE_STRING),
174  KEY_MAP_ENTRY(PROTECTED, WMT_TYPE_BOOL),
175  KEY_MAP_ENTRY(GN_EXTENDEDDATA, WMT_TYPE_BINARY),
176  KEY_MAP_ENTRY(GN_TAGID, WMT_TYPE_BINARY),
177 };
178 #undef KEY_MAP_ENTRY
179 
180 // CLASSES ====================================================================
181 
185 
187  m_Completed(PR_FALSE)
188 {
189 }
190 
192 {
193 }
194 
195 NS_IMETHODIMP sbMetadataHandlerWMA::GetContractID(nsACString &aContractID)
196 {
197  aContractID.AssignLiteral(SONGBIRD_METADATAHANDLERWMA_CONTRACTID);
198  return NS_OK;
199 }
200 
201 NS_IMETHODIMP
202 sbMetadataHandlerWMA::GetChannel(nsIChannel** _retval)
203 {
204  NS_ENSURE_ARG_POINTER(_retval);
205  NS_IF_ADDREF(*_retval = m_Channel);
206  return NS_OK;
207 }
208 
209 NS_IMETHODIMP
210 sbMetadataHandlerWMA::SetChannel(nsIChannel* aURLChannel)
211 {
212  nsresult rv;
213  m_Channel = aURLChannel;
214  NS_ENSURE_STATE(m_Channel);
215 
216  nsCOMPtr<nsIURI> pURI;
217  rv = m_Channel->GetURI(getter_AddRefs(pURI));
218  NS_ENSURE_SUCCESS(rv, rv);
219 
220  nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(pURI, &rv);
221  if (NS_FAILED(rv)) {
222  NS_WARNING("WMA METADATA: Remote files not currently supported");
223  return NS_OK;
224  }
225 
226  // Let's have a look at the file...
227  nsCOMPtr<nsIFile> file;
228  rv = fileURL->GetFile(getter_AddRefs(file));
229  NS_ENSURE_SUCCESS(rv, rv);
230 
231  // How about we start with the cooked path?
232  rv = file->GetPath(m_FilePath);
233  NS_ENSURE_SUCCESS(rv, rv);
234 
235  return NS_OK;
236 }
237 
238 NS_IMETHODIMP
239 sbMetadataHandlerWMA::OnChannelData(nsISupports* aChannel)
240 {
241  return NS_OK;
242 }
243 
244 NS_IMETHODIMP
245 sbMetadataHandlerWMA::GetCompleted(PRBool* _retval)
246 {
247  NS_ENSURE_ARG_POINTER(_retval);
248  *_retval = m_Completed;
249 
250  return NS_OK;
251 }
252 
253 NS_IMETHODIMP
254 sbMetadataHandlerWMA::Close()
255 {
256  if (m_ChannelHandler)
257  m_ChannelHandler->Close();
258 
259  m_Channel = nsnull;
260  m_ChannelHandler = nsnull;
261  m_PropertyArray = nsnull;
262  m_FilePath = EmptyString();
263 
264  return NS_OK;
265 }
266 
267 NS_IMETHODIMP
268 sbMetadataHandlerWMA::Vote(const nsAString& aURL,
269  PRInt32* _retval)
270 {
271  NS_ENSURE_ARG_POINTER(_retval);
272  nsAutoString strUrl(aURL);
273  ToLowerCase(strUrl);
274 
275  if (
276  ( strUrl.Find( ".wma", PR_TRUE ) != -1 ) ||
277  ( strUrl.Find( ".wmv", PR_TRUE ) != -1 ) ||
278  ( strUrl.Find( ".wm", PR_TRUE ) != -1 ) ||
279  ( strUrl.Find( ".asf", PR_TRUE ) != -1 ) ||
280  ( strUrl.Find( ".asx", PR_TRUE ) != -1 )
281  )
282  *_retval = 140;
283  else
284  *_retval = -1;
285 
286  return NS_OK;
287 }
288 
289 NS_IMETHODIMP
290 sbMetadataHandlerWMA::Read(PRInt32* _retval)
291 {
292  TRACE(("%s[%p]", __FUNCTION__, this));
293  NS_ENSURE_ARG_POINTER(_retval);
294  sbAutoCOMInitializer comInit(COINIT_MULTITHREADED);
295 
296  // We're never asynchronous.
297  m_Completed = PR_TRUE;
298  *_retval = 0;
299 
300  NS_ENSURE_TRUE(m_Channel, NS_ERROR_FAILURE);
301  NS_ENSURE_TRUE(!m_FilePath.IsEmpty(), NS_ERROR_UNEXPECTED);
302  nsresult rv = NS_ERROR_UNEXPECTED;
303 
304  m_PropertyArray = do_CreateInstance(SB_MUTABLEPROPERTYARRAY_CONTRACTID, &rv);
305  NS_ENSURE_SUCCESS(rv, rv);
306 
307  // Try to use the WMFSDK for this data because it's probably faster than
308  // initializing the Windows Media Player ActiveX control.
309  rv = ReadMetadataWMFSDK(m_FilePath, _retval);
310  if (NS_SUCCEEDED(rv))
311  return rv;
312 
313  // The WMF SDK failed on the file (probably because it is protected), so let
314  // the ActiveX control take a crack at it.
315  rv = ReadMetadataWMP(m_FilePath, _retval);
316  if (NS_SUCCEEDED(rv))
317  return rv;
318 
319  TRACE(("%s[%p] - failed to read data", __FUNCTION__, this));
320  return NS_ERROR_INVALID_ARG; // This will cause a useful warning in the metadata job.
321 }
322 
323 NS_IMETHODIMP
324 sbMetadataHandlerWMA::Write(PRInt32 *_retval)
325 {
326  NS_ENSURE_ARG_POINTER(_retval);
327  NS_ENSURE_TRUE(!m_FilePath.IsEmpty(), NS_ERROR_NOT_INITIALIZED);
328  NS_ENSURE_TRUE(m_PropertyArray, NS_ERROR_NOT_INITIALIZED);
329 
330  sbAutoCOMInitializer comInit(COINIT_MULTITHREADED);
331 
332  nsresult rv;
333  HRESULT hr;
334 
335  *_retval = 0;
336  nsCOMPtr<sbIMutablePropertyArray> propArray;
337  m_PropertyArray.forget(getter_AddRefs(propArray));
338 
339  CComPtr<IWMMetadataEditor> editor;
340  hr = WMCreateEditor(&editor);
341  COM_ENSURE_SUCCESS(hr);
342 
343  hr = editor->Open(m_FilePath.get());
344  COM_ENSURE_SUCCESS(hr);
345 
346  CComPtr<IWMHeaderInfo3> header;
347  hr = editor->QueryInterface(&header);
348  COM_ENSURE_SUCCESS(hr);
349 
350  sbAutoNSTypePtr<WORD> indices;
351  WORD indicesSize = 0;
352 
353  nsString value;
354 
355  // special case primary image url
356  rv = propArray->GetPropertyValue(NS_LITERAL_STRING(SB_PROPERTY_PRIMARYIMAGEURL),
357  value);
358  if (NS_UNLIKELY(NS_SUCCEEDED(rv))) {
359  PRBool success;
361  value,
362  header,
363  success);
364  if (NS_SUCCEEDED(rv)) {
365  if (success) {
366  ++*_retval;
367  }
368  } else {
369  nsresult __rv = rv;
370  NS_ENSURE_SUCCESS_BODY(rv, rv);
371  }
372  }
373 
374  for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(kMetadataKeys); ++i) {
375  rv = propArray->GetPropertyValue(nsDependentString(kMetadataKeys[i].songbirdName),
376  value);
377  if (NS_LIKELY(rv == NS_ERROR_NOT_AVAILABLE)) {
378  // no data
379  continue;
380  }
381  NS_ENSURE_SUCCESS(rv, rv);
382 
383  // find the index of the existing attribute, if any
384  WORD indicesCount = 0;
385  hr = header->GetAttributeIndices(0xFFFF,
386  kMetadataKeys[i].wmpName,
387  NULL,
388  NULL,
389  &indicesCount);
390  COM_ENSURE_SUCCESS(hr);
391  if (indicesCount > indicesSize) {
392  indices = reinterpret_cast<WORD*>(NS_Alloc(sizeof(WORD) * indicesCount));
393  NS_ENSURE_TRUE(indices, NS_ERROR_OUT_OF_MEMORY);
394  indicesSize = indicesCount;
395  }
396  indicesCount = indicesSize;
397  hr = header->GetAttributeIndices(0xFFFF,
398  kMetadataKeys[i].wmpName,
399  NULL,
400  indices.get(),
401  &indicesCount);
402  COM_ENSURE_SUCCESS(hr);
403 
404  const BYTE* data = NULL;
405  QWORD dataBuffer;
406  DWORD dataLength = 0;
407  switch (kMetadataKeys[i].type) {
408  case WMT_TYPE_STRING: {
409  data = reinterpret_cast<const BYTE*>(value.get());
410  dataLength = value.Length() * sizeof(PRUnichar);
411  break;
412  }
413  case WMT_TYPE_DWORD: {
414  DWORD* dword = reinterpret_cast<DWORD*>(&dataBuffer);
415  PRInt32 success = PR_sscanf(NS_ConvertUTF16toUTF8(value).BeginReading(),
416  "%lu",
417  dword);
418  if (NS_UNLIKELY(success < 1)) {
419  // the value is not a number but we expected one
420  continue;
421  }
422  data = reinterpret_cast<BYTE*>(dword);
423  dataLength = sizeof(DWORD);
424  break;
425  }
426  case WMT_TYPE_QWORD: {
427  PRInt32 success = PR_sscanf(NS_ConvertUTF16toUTF8(value).BeginReading(),
428  "%llu",
429  &dataBuffer);
430  if (NS_UNLIKELY(success < 1)) {
431  // the value is not a number but we expected one
432  continue;
433  }
434  data = reinterpret_cast<BYTE*>(&dataBuffer);
435  dataLength = sizeof(QWORD);
436  break;
437  }
438  default: {
439  LOG(("%s: don't know how to handle type %i",
440  __FUNCTION__,
441  kMetadataKeys[i].type));
442  NS_WARNING(__FUNCTION__ ": don't know how to handle type");
443  continue;
444  }
445  }
446  if (indicesCount > 0) {
447  if (dataLength == 0) {
448  TRACE(("%s: Deleting %S\n", __FUNCTION__, kMetadataKeys[i].wmpName));
449  hr = header->DeleteAttribute(0xFFFF,
450  *(indices.get()));
451  } else {
452  TRACE(("%s: Modifying %S\n", __FUNCTION__, kMetadataKeys[i].wmpName));
453  hr = header->ModifyAttribute(0xFFFF,
454  *(indices.get()),
455  kMetadataKeys[i].type,
456  NULL,
457  data,
458  dataLength);
459  }
460  COM_ENSURE_SUCCESS(hr);
461  } else {
462  TRACE(("%s: Adding %S\n", __FUNCTION__, kMetadataKeys[i].wmpName));
463  WORD index;
464  hr = header->AddAttribute(0,
465  kMetadataKeys[i].wmpName,
466  &index,
467  kMetadataKeys[i].type,
468  0,
469  data,
470  dataLength);
471  COM_ENSURE_SUCCESS(hr);
472  }
473  ++*_retval;
474  }
475 
476  hr = editor->Flush();
477  COM_ENSURE_SUCCESS(hr);
478 
479  return NS_OK;
480 } //Write
481 
482 NS_IMETHODIMP
483 sbMetadataHandlerWMA::GetImageData(PRInt32 aType,
484  nsACString &aMimeType,
485  PRUint32 *aDataLen,
486  PRUint8 **aData)
487 {
488  NS_ENSURE_ARG_POINTER(aDataLen);
489  NS_ENSURE_ARG_POINTER(aData);
490  NS_ENSURE_TRUE(!m_FilePath.IsEmpty(), NS_ERROR_NOT_INITIALIZED);
491 
492  nsresult rv;
493  rv = ReadAlbumArtWMFSDK(m_FilePath, aMimeType, aDataLen, aData);
494  if (NS_SUCCEEDED(rv)) {
495  return rv;
496  }
497 
498  // can't use WMFSDK, try WMP instead.
499  rv = ReadAlbumArtWMP(m_FilePath, aMimeType, aDataLen, aData);
500  NS_ENSURE_SUCCESS(rv, rv);
501 
502  return NS_OK;
503 }
504 
505 NS_IMETHODIMP
506 sbMetadataHandlerWMA::SetImageData(PRInt32 aType,
507  const nsAString &aURL)
508 {
509  NS_ENSURE_TRUE(!m_FilePath.IsEmpty(), NS_ERROR_NOT_INITIALIZED);
510 
511  HRESULT hr;
512  nsresult rv;
513 
514  CComPtr<IWMMetadataEditor> editor;
515  hr = WMCreateEditor(&editor);
516  COM_ENSURE_SUCCESS(hr);
517 
518  hr = editor->Open(m_FilePath.get());
519  COM_ENSURE_SUCCESS(hr);
520 
521  CComPtr<IWMHeaderInfo3> header;
522  hr = editor->QueryInterface(&header);
523  COM_ENSURE_SUCCESS(hr);
524 
525  PRBool success;
526  rv = SetImageDataInternal(aType, aURL, header, success);
527  NS_ENSURE_SUCCESS(rv, rv);
528 
529  if (success) {
530  hr = editor->Flush();
531  COM_ENSURE_SUCCESS(hr);
532  } else {
533  hr = editor->Close();
534  COM_ENSURE_SUCCESS(hr);
535  }
536 
537  return NS_OK;
538 }
539 
540 NS_IMETHODIMP
542  const nsAString &aURL,
543  IWMHeaderInfo3 *aHeader,
544  PRBool &aSuccess)
545 {
546  NS_ENSURE_ARG_POINTER(aHeader);
547 
548  HRESULT hr;
549  nsresult rv;
550  sbAutoNSTypePtr<WORD> indices;
551 
552  // find the index of the existing attribute, if any
553  WORD indicesCount = 0;
554  hr = aHeader->GetAttributeIndices(0xFFFF,
555  g_wszWMPicture,
556  NULL,
557  NULL,
558  &indicesCount);
559  COM_ENSURE_SUCCESS(hr);
560  indices = reinterpret_cast<WORD*>(NS_Alloc(sizeof(WORD) * indicesCount));
561  NS_ENSURE_TRUE(indices, NS_ERROR_OUT_OF_MEMORY);
562  hr = aHeader->GetAttributeIndices(0xFFFF,
563  g_wszWMPicture,
564  NULL,
565  indices.get(),
566  &indicesCount);
567  COM_ENSURE_SUCCESS(hr);
568 
569  nsCString data;
570  WM_PICTURE *picData = (WM_PICTURE*)data.BeginWriting();
571  WORD targetIndex = static_cast<WORD>(-1);
572  if (indicesCount > 0) {
573  for (WORD offset = 0; offset < indicesCount; ++offset) {
574  WORD nameLength = 0;
575  DWORD dataLength = data.Length();
576  WMT_ATTR_DATATYPE type;
577  // get the size of the data
578  hr = aHeader->GetAttributeByIndexEx(0xFFFF,
579  indices.get()[offset],
580  NULL,
581  &nameLength,
582  &type,
583  NULL,
584  reinterpret_cast<BYTE*>(data.BeginWriting()),
585  &dataLength);
586  // now we can go resize things
587  if (hr == NS_E_SDK_BUFFERTOOSMALL) {
588  data.SetLength(dataLength);
589  dataLength = data.Length();
590  nameLength = 0;
591  picData = (WM_PICTURE*)data.BeginWriting();
592  hr = aHeader->GetAttributeByIndexEx(0xFFFF,
593  indices.get()[offset],
594  NULL,
595  &nameLength,
596  &type,
597  NULL,
598  reinterpret_cast<BYTE*>(data.BeginWriting()),
599  &dataLength);
600  }
601  COM_ENSURE_SUCCESS(hr);
602 
603  if (type != WMT_TYPE_BINARY) {
604  LOG(("%s: index %hu got unknown type %i", __FUNCTION__, offset, type));
605  continue;
606  }
607 
608  // look at the picture to see if it's the right type
609  if (picData->bPictureType != aType) {
610  // the picture is of a different type, don't override
611  // NOTE: this only works because both Songbird and WMP use the type IDs
612  // from ID3v1
613  continue;
614  }
615 
616  // this is the right picture
617  targetIndex = indices.get()[offset];
618  break;
619  }
620  }
621 
622  if (aURL.IsEmpty()) {
623  // trying to remove the album art
624  if (targetIndex != static_cast<WORD>(-1)) {
625  hr = aHeader->DeleteAttribute(0xFFFF, targetIndex);
626  COM_ENSURE_SUCCESS(hr);
627 
628  aSuccess = PR_TRUE;
629  } else {
630  // it wasn't found anyway, so end up doing nothing
631  aSuccess = PR_FALSE;
632  }
633  return NS_OK;
634  }
635 
636  // we do want to set a picture.
637  nsCOMPtr<nsIURI> uri;
638  rv = NS_NewURI(getter_AddRefs(uri), aURL);
639  NS_ENSURE_SUCCESS(rv, rv);
640 
641  nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(uri, &rv);
642  NS_ENSURE_SUCCESS(rv, rv);
643 
644  nsCOMPtr<nsIFile> artFile;
645  rv = fileURL->GetFile(getter_AddRefs(artFile));
646  NS_ENSURE_SUCCESS(rv, rv);
647 
648  nsCString dataString;
649  rv = sbReadFile(artFile, dataString);
650  NS_ENSURE_SUCCESS(rv, rv);
651 
652  // detect the image type
653  nsCString contentType;
654  nsCOMPtr<nsIContentSniffer> contentSniffer =
655  do_ProxiedGetService("@mozilla.org/image/loader;1", &rv);
656  NS_ENSURE_SUCCESS(rv, rv);
657 
658  rv = contentSniffer->GetMIMETypeFromContent(NULL,
659  reinterpret_cast<const PRUint8*>(dataString.BeginReading()),
660  dataString.Length(),
661  contentType);
662  NS_ENSURE_SUCCESS(rv, rv);
663 
664  NS_ConvertASCIItoUTF16 contentTypeUnicode(contentType);
665 
666  nsString emptyString;
667  WM_PICTURE newPicData;
668  newPicData.pwszMIMEType = contentTypeUnicode.BeginWriting();
669  /* this only works because both songbird and WMA copy the types from id3v1 */
670  newPicData.bPictureType = aType;
671  newPicData.pwszDescription = emptyString.BeginWriting();
672  newPicData.pbData = reinterpret_cast<BYTE*>(dataString.BeginWriting());
673  newPicData.dwDataLen = dataString.Length();
674 
675  if (targetIndex == static_cast<WORD>(-1)) {
676  // no existing picture found
677  WORD index = 0;
678  hr = aHeader->AddAttribute(0,
679  g_wszWMPicture,
680  &index,
681  WMT_TYPE_BINARY,
682  0,
683  reinterpret_cast<const BYTE*>(&newPicData),
684  sizeof(WM_PICTURE));
685  COM_ENSURE_SUCCESS(hr);
686  } else {
687  // there's an existing picture of the right type
688  hr = aHeader->ModifyAttribute(0xFFFF,
689  targetIndex,
690  WMT_TYPE_BINARY,
691  NULL,
692  reinterpret_cast<const BYTE*>(&newPicData),
693  sizeof(WM_PICTURE));
694  COM_ENSURE_SUCCESS(hr);
695  }
696 
697  aSuccess = PR_TRUE;
698  return NS_OK;
699 }
700 
701 NS_IMETHODIMP
702 sbMetadataHandlerWMA::GetProps(sbIMutablePropertyArray **_retval)
703 {
704  NS_ENSURE_ARG_POINTER(_retval);
705  NS_ENSURE_STATE(m_PropertyArray);
706  NS_IF_ADDREF(*_retval = m_PropertyArray);
707  return NS_OK;
708 }
709 
710 NS_IMETHODIMP
711 sbMetadataHandlerWMA::SetProps(sbIMutablePropertyArray *props)
712 {
714  return NS_OK;
715 }
716 
717 NS_IMETHODIMP
718 sbMetadataHandlerWMA::GetRequiresMainThread(PRBool *_retval)
719 {
720  NS_ENSURE_ARG_POINTER(_retval);
721  // This handler does not use the channel implementation,
722  // and is threadsafe.
723  *_retval = PR_FALSE;
724  return NS_OK;
725 }
726 
727 nsString
728 sbMetadataHandlerWMA::ReadHeaderValue(IWMHeaderInfo3 *aHeaderInfo,
729  const nsAString &aKey)
730 {
731  TRACE(("%s[%p]: reading %s",
732  __FUNCTION__, this, NS_ConvertUTF16toUTF8(aKey).get()));
733  HRESULT hr;
734  nsString value;
735 
736  // Get the number of indices
737  WORD count = 0;
738  hr = aHeaderInfo->GetAttributeIndices(0xFFFF,
739  aKey.BeginReading(),
740  NULL,
741  NULL,
742  &count);
743  if (FAILED(hr) || !count) {
744  return SBVoidString();
745  }
746 
747  // Alloc the space for the indices
748  sbAutoNSTypePtr<WORD> indices = (WORD*)NS_Alloc(sizeof(WORD) * count);
749  if (!indices) {
750  NS_ERROR("NS_Alloc failed!");
751  return SBVoidString();
752  }
753 
754  // Ask for the indices
755  hr = aHeaderInfo->GetAttributeIndices(0xFFFF,
756  aKey.BeginReading(),
757  NULL,
758  indices.get(),
759  &count);
760  if (FAILED(hr)) {
761  return SBVoidString();
762  }
763 
764  // For now, get the first one?
765  WMT_ATTR_DATATYPE type;
766  WORD lang;
767  DWORD size;
769  WORD namesize;
770 
771  // Get the type and size
772  hr = aHeaderInfo->GetAttributeByIndexEx(0xFFFF,
773  *indices.get(),
774  NULL,
775  &namesize,
776  &type,
777  &lang,
778  NULL,
779  &size);
780  if (FAILED(hr)) {
781  NS_WARNING("GetAttributeByIndexEx failed");
782  return SBVoidString();
783  }
784 
785  // Alloc (documented as "suitably aligned for any kind of variable")
786  // in practice, it forwards to malloc()
787  data = (BYTE*) NS_Alloc(size);
788  if (!data) {
789  NS_ERROR("NS_Alloc failed!");
790  return SBVoidString();
791  }
792 
793  // Get the data
794  hr = aHeaderInfo->GetAttributeByIndexEx(0xFFFF,
795  *indices.get(),
796  NULL,
797  &namesize,
798  &type,
799  &lang,
800  data.get(),
801  &size);
802  if (FAILED(hr)) {
803  NS_WARNING("GetAttributeByIndexEx failed");
804  return SBVoidString();
805  }
806 
807  // Calculate the value
808  PRInt32 datatype = 0;
809 
810  switch(type) {
811  case WMT_TYPE_STRING:
812  value.Assign(reinterpret_cast<PRUnichar*>(data.get()));
813  break;
814 
815  case WMT_TYPE_BINARY:
816  break;
817 
818  case WMT_TYPE_QWORD: {
819  PRInt64 intVal = *(reinterpret_cast<QWORD*>(data.get()));
820  if (aKey.EqualsLiteral(WMP_LENGTH)) {
821  // "Duration" comes in 100-nanosecond chunks. Wow.
822  // Songbird wants it in microseconds.
823  intVal /= 10;
824  }
825 
826  // Convert the long to a string.
827  char buf[30];
828  PRUint32 len = PR_snprintf(buf, sizeof(buf), "%lld", intVal);
829 
830  value.Append(NS_ConvertASCIItoUTF16(buf, len));
831  datatype = 1;
832  } break;
833 
834  case WMT_TYPE_DWORD: {
835  PRUint32 intVal = *(reinterpret_cast<DWORD*>(data.get()));
836  if (aKey.EqualsLiteral(WMP_BITRATE)) {
837  // Songbird wants bit rate in kbps
838  intVal /= 1000;
839  }
840  value.AppendInt( intVal );
841  datatype = 1;
842  } break;
843 
844  case WMT_TYPE_WORD:
845  value.AppendInt( (PRInt32)*(reinterpret_cast<WORD*>(data.get())) );
846  datatype = 1;
847  break;
848 
849  case WMT_TYPE_BOOL:
850  value.AppendInt( (PRInt32)*(reinterpret_cast<BOOL*>(data.get())) );
851  datatype = 1;
852  break;
853 
854  case WMT_TYPE_GUID:
855  break;
856 
857  default:
858  NS_WARNING("Value given in an unsupported type");
859  break;
860  }
861 
862  TRACE(("%s[%p]: %s -> %s",
863  __FUNCTION__,
864  this,
865  NS_ConvertUTF16toUTF8(aKey).get(),
866  NS_ConvertUTF16toUTF8(value).get()));
867  return value;
868 }
869 
870 NS_METHOD
871 sbMetadataHandlerWMA::CreateWMPMediaItem(const nsAString& aFilePath,
872  IWMPMedia3** aMedia)
873 {
874  HRESULT hr;
875  NS_ENSURE_ARG_POINTER(aMedia);
876 
877  CComPtr<IWMPPlayer4> player;
878  hr = player.CoCreateInstance(__uuidof(WindowsMediaPlayer),
879  NULL,
880  CLSCTX_INPROC_SERVER);
881  COM_ENSURE_SUCCESS(hr);
882 
883  // Set basic settings
884  CComPtr<IWMPSettings> settings;
885  hr = player->get_settings(&settings);
886  COM_ENSURE_SUCCESS(hr);
887 
888  hr = settings->put_autoStart(PR_FALSE);
889  COM_ENSURE_SUCCESS(hr);
890 
891  CComBSTR uiMode(_T("invisible"));
892  hr = player->put_uiMode(uiMode);
893  COM_ENSURE_SUCCESS(hr);
894 
895  // Make our custom playlist
896  CComPtr<IWMPPlaylist> playlist;
897  CComBSTR playlistName(_T("SongbirdMetadataPlaylist"));
898  hr = player->newPlaylist(playlistName, NULL, &playlist);
899  COM_ENSURE_SUCCESS(hr);
900 
901  hr = player->put_currentPlaylist(playlist);
902  COM_ENSURE_SUCCESS(hr);
903 
904  CComBSTR uriString(aFilePath.BeginReading());
905 
906  CComPtr<IWMPMedia> newMedia;
907  hr = player->newMedia(uriString, &newMedia);
908  COM_ENSURE_SUCCESS(hr);
909 
910  CComPtr<IWMPMedia3> newMedia3;
911  hr = newMedia->QueryInterface(&newMedia3);
912  COM_ENSURE_SUCCESS(hr);
913 
914  // Now add our new item.
915  hr = playlist->appendItem(newMedia);
916  COM_ENSURE_SUCCESS(hr);
917 
918  // Set our new item as the current one
919  CComPtr<IWMPControls> controls;
920  hr = player->get_controls(&controls);
921  COM_ENSURE_SUCCESS(hr);
922 
923  hr = controls->put_currentItem(newMedia);
924  COM_ENSURE_SUCCESS(hr);
925 
926  *aMedia = newMedia3.Detach();
927 
928  return NS_OK;
929 }
930 
931 NS_METHOD
932 sbMetadataHandlerWMA::ReadMetadataWMFSDK(const nsAString& aFilePath,
933  PRInt32* _retval)
934 {
935  nsresult rv;
936 
937  CComPtr<IWMMetadataEditor> reader;
938  HRESULT hr = WMCreateEditor(&reader);
939  COM_ENSURE_SUCCESS(hr);
940 
941  nsAutoString filePath(aFilePath);
942 
943  // This will fail for all protected files, so silence the warning
944  hr = reader->Open(filePath.get());
945  if (FAILED(hr))
946  return NS_ERROR_FAILURE;
947 
948  CComPtr<IWMHeaderInfo3> headerInfo;
949  hr = reader->QueryInterface(&headerInfo);
950  COM_ENSURE_SUCCESS(hr);
951 
952  nsString value, wmpKey;
953 
954  for (PRUint32 index = 0; index < NS_ARRAY_LENGTH(kMetadataKeys); ++index) {
955  wmpKey.Assign(nsDependentString(kMetadataKeys[index].wmpName));
956 
957  value = ReadHeaderValue(headerInfo, wmpKey);
958 
959  // If there is a value, add it to the Songbird values.
960  if (!value.IsEmpty()) {
961  nsAutoString sbKey;
962  sbKey.Assign(nsDependentString(kMetadataKeys[index].songbirdName));
963  nsresult rv = m_PropertyArray->AppendProperty(sbKey, value);
964  if (NS_SUCCEEDED(rv)) {
965  *_retval += 1;
966  }
967  else {
968  NS_WARNING("AppendProperty failed!");
969  }
970  }
971  }
972 
973  // Figure out whether it's audio or video
974  wmpKey.AssignLiteral("HasVideo");
975  nsString hasVideo = ReadHeaderValue(headerInfo, wmpKey);
976 
977  wmpKey.AssignLiteral("HasAudio");
978  nsString hasAudio = ReadHeaderValue(headerInfo, wmpKey);
979 
980  value = EmptyString();
981 
982  if(hasVideo.EqualsLiteral("1")) {
983  value = NS_LITERAL_STRING("video");
984  }
985  else if(hasAudio.EqualsLiteral("1")) {
986  value = NS_LITERAL_STRING("audio");
987  }
988 
989  rv = m_PropertyArray->AppendProperty(NS_LITERAL_STRING(SB_PROPERTY_CONTENTTYPE),
990  value);
991 
992  if(NS_SUCCEEDED(rv)) {
993  *_retval += 1;
994  }
995  else {
996  NS_WARNING("AppendProperty Failed!");
997  }
998 
999  hr = reader->Close();
1000  COM_ENSURE_SUCCESS(hr);
1001 
1002  return NS_OK;
1003 }
1004 
1005 NS_METHOD
1006 sbMetadataHandlerWMA::ReadMetadataWMP(const nsAString& aFilePath,
1007  PRInt32* _retval)
1008 {
1009  nsresult rv;
1010  HRESULT hr;
1011 
1012  CComPtr<IWMPMedia3> newMedia;
1013  rv = CreateWMPMediaItem(aFilePath, &newMedia);
1014  NS_ENSURE_SUCCESS(rv, rv);
1015 
1016  for (PRUint32 index = 0; index < NS_ARRAY_LENGTH(kMetadataKeys); ++index) {
1017 
1018  CComBSTR key(kMetadataKeys[index].wmpName);
1019  nsAutoString metadataValue;
1020  PRUint32 metadataValueType = 0;
1021 
1022  // Special case for length... and others?
1023  if (key == WMP_LENGTH) {
1024  // Songbird needs length in microseconds
1025  double duration;
1026  hr = newMedia->get_duration(&duration);
1027  if (FAILED(hr)) {
1028  NS_WARNING("get_duration failed!");
1029  continue;
1030  }
1031  double result = duration * PR_USEC_PER_SEC;
1032 
1033  AppendInt(metadataValue, static_cast<PRUint64>(result));
1034  metadataValueType = 1;
1035  }
1036  else {
1037  CComBSTR value;
1038  hr = newMedia->getItemInfo(key, &value);
1039  if (FAILED(hr)) {
1040  NS_WARNING("getItemInfo failed!");
1041  continue;
1042  }
1043  if (key == WMP_BITRATE) {
1044  // WMP returns bitrate in bits/sec, Songbird wants kbps/sec
1045  metadataValue.Assign(value.m_str, value.Length() - 3);
1046  } else if (key == WMP_PROTECTED) {
1047  // Songbird wants (nothing) or "1"
1048  if (value.Length() > 0) {
1049  metadataValue.AssignLiteral("1");
1050  }
1051  } else {
1052  metadataValue.Assign(value.m_str);
1053  }
1054  }
1055 
1056  if (!metadataValue.IsEmpty()) {
1057  nsAutoString sbKey;
1058  sbKey.Assign(nsDependentString(kMetadataKeys[index].songbirdName));
1059  nsresult rv =
1060  m_PropertyArray->AppendProperty(sbKey, metadataValue);
1061  if (NS_SUCCEEDED(rv))
1062  *_retval += 1;
1063  else
1064  NS_WARNING("SetValue failed!");
1065  }
1066  }
1067 
1068  // Simply check the file extension to determine if this is a video file.
1069  nsString value(NS_LITERAL_STRING("audio")); // assume audio
1070 
1071  nsCOMPtr<nsILocalFile> localFile =
1072  do_CreateInstance("@mozilla.org/file/local;1", &rv);
1073  if (NS_SUCCEEDED(rv) && localFile) {
1074  rv = localFile->InitWithPath(aFilePath);
1075  if (NS_SUCCEEDED(rv)) {
1076  nsString leafName;
1077  rv = localFile->GetLeafName(leafName);
1078  NS_ENSURE_SUCCESS(rv, rv);
1079 
1080  PRInt32 index = leafName.RFindChar('.');
1081  if (index >= 0) {
1082  nsString extension(StringTail(leafName, leafName.Length() -1 - index));
1083 
1084  if (extension.EqualsLiteral("wmv") ||
1085  extension.EqualsLiteral("wm"))
1086  {
1087  value.AssignLiteral("video");
1088  }
1089  }
1090  }
1091  }
1092 
1093  rv = m_PropertyArray->AppendProperty(NS_LITERAL_STRING(SB_PROPERTY_CONTENTTYPE),
1094  value);
1095  NS_ENSURE_SUCCESS(rv, rv);
1096 
1097  return NS_OK;
1098 }
1099 
1100 NS_METHOD
1101 sbMetadataHandlerWMA::ReadAlbumArtWMFSDK(const nsAString &aFilePath,
1102  nsACString &aMimeType,
1103  PRUint32 *aDataLen,
1104  PRUint8 **aData)
1105 {
1106  CComPtr<IWMMetadataEditor> reader;
1107  HRESULT hr = WMCreateEditor(&reader);
1108  COM_ENSURE_SUCCESS(hr);
1109 
1110  nsAutoString filePath(aFilePath);
1111 
1112  // This will fail for all protected files, so silence the warning
1113  hr = reader->Open(filePath.get());
1114  if (FAILED(hr)) {
1115  TRACE(("%s: failed to open file %s, assuming protected",
1116  __FUNCTION__,
1117  NS_ConvertUTF16toUTF8(filePath).get()));
1118  return NS_ERROR_FAILURE;
1119  }
1120 
1121  CComPtr<IWMHeaderInfo3> headerInfo;
1122  hr = reader->QueryInterface(&headerInfo);
1123  COM_ENSURE_SUCCESS(hr);
1124 
1125  // Get the number of indices
1126  WORD count = 0;
1127  hr = headerInfo->GetAttributeIndices(0xFFFF,
1128  g_wszWMPicture,
1129  NULL,
1130  NULL,
1131  &count);
1132  COM_ENSURE_SUCCESS(hr);
1133  NS_ENSURE_TRUE(count, NS_ERROR_NO_CONTENT);
1134 
1135  // Alloc the space for the indices
1136  sbAutoNSTypePtr<WORD> indices = (WORD*) NS_Alloc(sizeof(WORD) * count);
1137  NS_ENSURE_TRUE(indices, NS_ERROR_OUT_OF_MEMORY);
1138 
1139  // Ask for the indices
1140  hr = headerInfo->GetAttributeIndices(0xFFFF,
1141  g_wszWMPicture,
1142  NULL,
1143  indices.get(),
1144  &count);
1145  COM_ENSURE_SUCCESS(hr);
1146 
1147  // For now, get the first one?
1148  WMT_ATTR_DATATYPE type;
1149  WORD lang;
1150  DWORD size;
1151  WORD namesize;
1152 
1153  // Get the type and size
1154  hr = headerInfo->GetAttributeByIndexEx(0xFFFF,
1155  *(indices.get()),
1156  NULL,
1157  &namesize,
1158  &type,
1159  &lang,
1160  NULL,
1161  &size);
1162  COM_ENSURE_SUCCESS(hr);
1163 
1164  // Alloc
1165  sbAutoNSTypePtr<BYTE> data = (BYTE*) NS_Alloc(size);
1166  NS_ENSURE_TRUE(data, NS_ERROR_OUT_OF_MEMORY);
1167 
1168  // Get the data
1169  hr = headerInfo->GetAttributeByIndexEx(0xFFFF,
1170  *(indices.get()),
1171  NULL,
1172  &namesize,
1173  &type,
1174  &lang,
1175  data.get(),
1176  &size);
1177  COM_ENSURE_SUCCESS(hr);
1178  NS_ENSURE_TRUE(type == WMT_TYPE_BINARY, NS_ERROR_UNEXPECTED);
1179 
1180  // get the picture data out (remembering to use a copy)
1181  WM_PICTURE *picData = (WM_PICTURE*)data.get();
1182  CopyUTF16toUTF8(nsDependentString(picData->pwszMIMEType), aMimeType);
1183  *aData = static_cast<PRUint8*>(SB_CloneMemory(picData->pbData, picData->dwDataLen));
1184  NS_ENSURE_TRUE(*aData, NS_ERROR_OUT_OF_MEMORY);
1185  *aDataLen = picData->dwDataLen;
1186 
1187  hr = reader->Close();
1188  return NS_OK;
1189 }
1190 
1191 
1192 NS_METHOD
1193 sbMetadataHandlerWMA::ReadAlbumArtWMP(const nsAString &aFilePath,
1194  nsACString &aMimeType,
1195  PRUint32 *aDataLen,
1196  PRUint8 **aData)
1197 {
1198  nsresult rv;
1199  HRESULT hr;
1200 
1201  CComPtr<IWMPMedia3> newMedia;
1202  rv = CreateWMPMediaItem(aFilePath, &newMedia);
1203  NS_ENSURE_SUCCESS(rv, rv);
1204 
1205  // read out the metadata
1206  long count = 0;
1207  CComBSTR key(g_wszWMPicture);
1208  hr = newMedia->getAttributeCountByType(key, NULL, &count);
1209  COM_ENSURE_SUCCESS(hr);
1210 
1211  for (long idx = 0; idx < count; ++idx) {
1212  CComVariant var;
1213  hr = newMedia->getItemInfoByType(key, NULL, idx, &var);
1214  COM_ENSURE_SUCCESS(hr);
1215 
1216  CComPtr<IWMPMetadataPicture> picture;
1217  switch(V_VT(&var)) {
1218  case VT_DISPATCH:
1219  hr = var.pdispVal->QueryInterface(&picture);
1220  break;
1221  case VT_DISPATCH | VT_BYREF:
1222  if (!var.ppdispVal) {
1223  nsresult __rv = NS_ERROR_INVALID_POINTER;
1224  NS_ENSURE_SUCCESS_BODY(hr, hr);
1225  continue;
1226  }
1227  hr = (*(var.ppdispVal))->QueryInterface(&picture);
1228  break;
1229  default:
1230  TRACE(("%s: don't know how to deal with WM/Picture variant type %i",
1231  __FUNCTION__, var.vt));
1232  continue;
1233  }
1234 
1235  if (FAILED(hr) || NS_UNLIKELY(!picture)) {
1236  nsresult __rv = NS_ERROR_NO_INTERFACE;
1237  NS_ENSURE_SUCCESS_BODY(hr, hr);
1238  continue;
1239  }
1240 
1241  /* get the picture data
1242  * IWMPMetadataPicture will only give us a URL (of the form
1243  * "vnd.ms.wmhtml://localhost/WMP<guid>.jpg"), and doesn't directly give us
1244  * any way to access the stream. Fortunately, they also get dumped into
1245  * Temporary Internet Files (with the URL intact).
1246  * So, we look up the URL in the IE cache and hope it's still there. It can
1247  * be resolved to a local file (in a hidden + system directory), which we
1248  * can then read normally.
1249  */
1250  CComBSTR url;
1251  hr = picture->get_URL(&url);
1252  COM_ENSURE_SUCCESS(hr);
1253 
1254  DWORD entrySize = 0;
1255  BOOL success = GetUrlCacheEntryInfo(url, NULL, &entrySize);
1256  NS_ENSURE_TRUE(!success && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1257  NS_ERROR_FAILURE);
1258  NS_ASSERTION(entrySize > 0, "Unexpected entry size");
1259 
1261  (INTERNET_CACHE_ENTRY_INFO*)NS_Alloc(entrySize);
1262  NS_ENSURE_TRUE(cacheInfo, NS_ERROR_OUT_OF_MEMORY);
1263 
1264  cacheInfo.get()->dwStructSize = sizeof(INTERNET_CACHE_ENTRY_INFO);
1265 
1266  success = GetUrlCacheEntryInfo(url, cacheInfo.get(), &entrySize);
1267  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
1268 
1269  // at this point, cacheInfo.get()->lpszLocalFileName is the local file path
1270  nsCOMPtr<nsILocalFile> file =
1271  do_CreateInstance("@mozilla.org/file/local;1", &rv);
1272  NS_ENSURE_SUCCESS(rv, rv);
1273 
1274  rv = file->InitWithPath(nsDependentString(cacheInfo.get()->lpszLocalFileName));
1275  NS_ENSURE_SUCCESS(rv, rv);
1276 
1277  PRInt64 fileSize;
1278  rv = file->GetFileSize(&fileSize);
1279  NS_ENSURE_SUCCESS(rv, rv);
1280 
1281  sbAutoNSTypePtr<PRUint8> fileData = (PRUint8*)NS_Alloc(static_cast<PRSize>(fileSize));
1282  NS_ENSURE_TRUE(fileData, NS_ERROR_OUT_OF_MEMORY);
1283 
1284  nsCOMPtr<nsIFileInputStream> fileStream =
1285  do_CreateInstance("@mozilla.org/network/file-input-stream;1", &rv);
1286  NS_ENSURE_SUCCESS(rv, rv);
1287 
1288  rv = fileStream->Init(file, PR_RDONLY, -1, nsIFileInputStream::CLOSE_ON_EOF);
1289  NS_ENSURE_SUCCESS(rv, rv);
1290 
1291  PRUint32 bytesRead;
1292  rv = fileStream->Read((char*)fileData.get(), (PRUint32)fileSize, &bytesRead);
1293  NS_ENSURE_SUCCESS(rv, rv);
1294 
1295  // the stream is actually already closed (CLOSE_ON_EOF), but no harm to be
1296  // explicit about it
1297  rv = fileStream->Close();
1298  NS_ENSURE_SUCCESS(rv, rv);
1299 
1300  // get the picture type
1301  CComBSTR mimeType;
1302  hr = picture->get_mimeType(&mimeType);
1303  COM_ENSURE_SUCCESS(hr);
1304  aMimeType.Assign(NS_ConvertUTF16toUTF8(nsDependentString(mimeType)));
1305 
1306  *aDataLen = bytesRead;
1307  *aData = fileData.forget();
1308 
1309  return NS_OK;
1310  }
1311 
1312  // if we get here, we ran through the pictures and found nothing useful
1313  return NS_ERROR_FAILURE;
1314 }
1315 
1316 /* PRBool isDRMProtected (in AString aPath); */
1317 NS_IMETHODIMP
1318 sbMetadataHandlerWMA::IsDRMProtected(const nsAString & aPath,
1319  PRBool *_retval)
1320 {
1321  NS_ENSURE_ARG_POINTER(_retval);
1322  BOOL isProtected; // needed for data type conversion
1323  HRESULT hr = WMIsContentProtected(aPath.BeginReading(), &isProtected);
1324  *_retval = isProtected;
1325  return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
1326 }
#define LOG(args)
void * SB_CloneMemory(const void *ptr, PRSize size)
Clone a block of contiguous memory.
nsCOMPtr< nsIChannel > m_Channel
return NS_OK
_updateCookies aPath
attribute sbIMutablePropertyArray props
An array of metadata properties.
TCHAR const *const wmpName
NS_METHOD ReadAlbumArtWMFSDK(const nsAString &aFilePath, nsACString &aMimeType, PRUint32 *aDataLen, PRUint8 **aData)
const PR_RDONLY
NS_METHOD SetImageDataInternal(PRInt32 aType, const nsAString &aURL, IWMHeaderInfo3 *aHeader, PRBool &aSuccess)
NS_IMPL_THREADSAFE_ISUPPORTS2(sbMetadataHandlerWMA, sbIMetadataHandler, sbIMetadataHandlerWMA) sbMetadataHandlerWMA
PRUnichar const *const songbirdName
nsresult sbReadFile(nsIFile *aFile, nsACString &aBuffer)
nsString ReadHeaderValue(IWMHeaderInfo3 *aHeaderInfo, const nsAString &aKey)
#define WMP_PROTECTED
#define SB_MUTABLEPROPERTYARRAY_CONTRACTID
var header
Definition: FeedWriter.js:953
const PRUint32 METADATA_IMAGE_TYPE_OTHER
Constant for the type of image in the metadata, these are pulled from the taglib/attachedpictureframe...
An interface to carry around arrays of nsIProperty instances Note that implementations of the interfa...
NS_METHOD ReadMetadataWMP(const nsAString &aFilePath, PRInt32 *_retval)
PRUint32 & offset
_hideDatepicker duration
var count
Definition: test_bug7406.js:32
const sbCreateProxiedComponent do_ProxiedGetService(const nsCID &aCID, nsresult *error=0)
#define SB_PROPERTY_CONTENTTYPE
#define TRACE(args)
const nsIChannel
_dialogDatepicker settings
An object capable of manipulating the metadata tags for a media file.
NS_METHOD ReadAlbumArtWMP(const nsAString &aFilePath, nsACString &aMimeType, PRUint32 *aDataLen, PRUint8 **aData)
static const metadataKeyMapEntry_t kMetadataKeys[]
WMA metadata handler.
T * get() const
#define COM_ENSURE_SUCCESS(_val)
NS_METHOD CreateWMPMediaItem(const nsAString &aFilePath, IWMPMedia3 **aMedia)
nsCOMPtr< sbIMetadataChannel > m_ChannelHandler
function url(spec)
var uri
Definition: FeedWriter.js:1135
countRef value
Definition: FeedWriter.js:1423
static void AppendInt(nsAString &str, PRInt64 val)
nsCOMPtr< sbIMutablePropertyArray > m_PropertyArray
#define SONGBIRD_METADATAHANDLERWMA_CONTRACTID
WMT_ATTR_DATATYPE type
#define KEY_MAP_ENTRY(_entry, _type)
observe data
Definition: FeedWriter.js:1329
#define WMP_LENGTH
NS_METHOD ReadMetadataWMFSDK(const nsAString &aFilePath, PRInt32 *_retval)
_getSelectedPageStyle s i
#define SB_PROPERTY_PRIMARYIMAGEURL
#define WMP_BITRATE
_updateTextAndScrollDataForFrame aData
var file