sbIdentityService.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-2011 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 #include "sbIdentityService.h"
31 
32 #include "nsCOMPtr.h"
33 #include "nsComponentManagerUtils.h"
34 #include "nsServiceManagerUtils.h"
35 #include <nsICategoryManager.h>
36 
37 #include <nsStringAPI.h>
38 #include <sbStringUtils.h>
39 #include <sbStandardProperties.h>
40 #include <nsICryptoHash.h>
41 
42 #include <sbIPropertyManager.h>
43 #include <sbIPropertyInfo.h>
44 #include <sbILocalDatabaseResourcePropertyBag.h>
45 #include <sbILocalDatabaseMediaItem.h>
46 #include <sbDebugUtils.h>
47 
50 
51  /* The following consts are used to retrieve metadata properties
52  * and concatenate them into a string that will be hashed to form the
53  * metadata_hash_identity for each mediaitem.
54  *
55  * Any changes to any of these consts, including the order in the arrays,
56  * will require a migration to ensure stored identities of existing mediaitems
57  * are coherent with new identity calculations.
58  *
59  * The initial migration to this effect is
60  * sbMigrate19to110pre0.addMetadataHashIdentity.js
61  */
62 
63 // the separator that will be used between parts of the metadata hash identity
64 static const char SEPARATOR[] = "|";
65 
66 /* the properties that will be used as part of the metadata hash identity
67  * for audio files */
68 static const char* const sAudioPropsToHash[] = {
74 };
75 
76 // jhawk for now the properties used for Video and Audio are the same, but that
77 // will change in the near future.
78 /* the properties that will be used as part of the metadata hash identity
79  * for video files */
80 static const char* const sVideoPropsToHash[] = {
86 };
87 
88 //-----------------------------------------------------------------------------
90 {
92 }
93 
94 //-----------------------------------------------------------------------------
95 /* virtual */ sbIdentityService::~sbIdentityService()
96 {
97 }
98 
99 //-----------------------------------------------------------------------------
100 /* sbIdentityService.idl, hashString */
101 NS_IMETHODIMP
102 sbIdentityService::HashString(const nsAString &aString,
103  nsAString &_retval)
104 {
105  NS_ENSURE_TRUE(!aString.IsEmpty(), NS_ERROR_INVALID_ARG);
106 
107  TRACE_FUNCTION("Hashing the string \'%s\'",
108  NS_ConvertUTF16toUTF8(aString).get());
109 
110  nsresult rv;
111 
112  // Create and initialize a hash object.
113  nsCOMPtr<nsICryptoHash>
114  cryptoHash = do_CreateInstance("@mozilla.org/security/hash;1", &rv);
115  NS_ENSURE_SUCCESS(rv, rv);
116 
117  /* hash with md5 algorithm for very low chance of hash collision between
118  * differing strings */
119  rv = cryptoHash->Init(nsICryptoHash::MD5);
120  NS_ENSURE_SUCCESS(rv, rv);
121 
122  // handle the input string as a bytestring that cryptoHash can handle
123  nsCString toHash;
124  toHash = NS_ConvertUTF16toUTF8(aString);
125 
126  // generate the hash
127  rv = cryptoHash->Update
128  (reinterpret_cast<PRUint8 const *>(toHash.BeginReading()),
129  toHash.Length());
130  NS_ENSURE_SUCCESS(rv, rv);
131 
132  nsCString hashValue;
133  rv = cryptoHash->Finish(PR_TRUE, hashValue);
134  NS_ENSURE_SUCCESS(rv, rv);
135 
136  _retval.AssignLiteral(hashValue.get());
137 
138  return NS_OK;
139 }
140 
141 //-----------------------------------------------------------------------------
142 nsresult
143 sbIdentityService::GetPropertyStringFor
145  const char * const * aPropsToHash,
146  PRUint32 aPropsToHashLength,
147  nsAString &_retval)
148 {
149  NS_ENSURE_ARG_POINTER(aPropertyBag);
150  NS_ENSURE_ARG_POINTER(aPropsToHash);
151  nsresult rv;
152 
153  // Tracks whether we got a property value or not
154  bool propertyFound = false;
155  nsAutoString propString;
156  for (PRUint32 i = 0; i < aPropsToHashLength; i++) {
157 
158  // sAudioPropsToHash contains ids for the properties we are interested in
159  nsString propVal;
160  rv = aPropertyBag->GetProperty(NS_ConvertUTF8toUTF16(aPropsToHash[i]),
161  propVal);
162 
163  if (NS_FAILED(rv) || propVal.IsEmpty()) {
164  propVal.Truncate();
165  }
166  // Content type doesn't count for determining if a property is found
167  else if (strcmp(aPropsToHash[i], SB_PROPERTY_CONTENTTYPE) != 0) {
168 
169  propertyFound = true;
170  }
171  // append this property to the concatenated string
172  if (i == 0) {
173  propString.Assign(propVal);
174  }
175  else {
176  propString.AppendLiteral(SEPARATOR);
177  propString.Append(propVal);
178  }
179  }
180 
181  // If we found property values return the concatenated string else return void
182  if (propertyFound) {
183  _retval.Assign(propString);
184  }
185  else {
186  _retval.SetIsVoid(PR_TRUE);
187  }
188  return NS_OK;
189 }
190 
191 //-----------------------------------------------------------------------------
192 nsresult
193 sbIdentityService::GetPropertyStringForAudio
195  nsAString &_retval)
196 {
197  NS_ENSURE_ARG_POINTER(aPropertyBag);
198 
199  return GetPropertyStringFor(aPropertyBag,
201  NS_ARRAY_LENGTH(sAudioPropsToHash),
202  _retval);
203 }
204 
205 //-----------------------------------------------------------------------------
206 nsresult
207 sbIdentityService::GetPropertyStringForVideo
209  nsAString &_retval)
210 {
211  NS_ENSURE_ARG_POINTER(aPropertyBag);
212 
213  return GetPropertyStringFor(aPropertyBag,
215  NS_ARRAY_LENGTH(sVideoPropsToHash),
216  _retval);
217 }
218 
219 //-----------------------------------------------------------------------------
220 /* sbIdentityService.idl, calculateIdentityForMediaItem */
221 NS_IMETHODIMP
222 sbIdentityService::CalculateIdentityForMediaItem
223  (sbIMediaItem *aMediaItem,
224  nsAString &_retval)
225 {
226  NS_ENSURE_ARG_POINTER(aMediaItem);
227  nsresult rv;
228 
229  nsCOMPtr<sbILocalDatabaseMediaItem> localItem =
230  do_QueryInterface(aMediaItem, &rv);
231  if (NS_FAILED(rv)) {
232  // we were passed a mediaitem that we won't be able to get a propertybag for
233  return NS_OK;
234  }
235 
236  // get the propertybag underlying aMediaItem and make an identity from that
237  nsCOMPtr<sbILocalDatabaseResourcePropertyBag> propertyBag;
238  rv = localItem->GetPropertyBag(getter_AddRefs(propertyBag));
239  NS_ENSURE_SUCCESS(rv, rv);
240 
241  rv = CalculateIdentityForBag(propertyBag, _retval);
242  return rv;
243 }
244 
245 //-----------------------------------------------------------------------------
246 /* sbIdentityService.idl, calculateIdentityForBag */
247 NS_IMETHODIMP
248 sbIdentityService::CalculateIdentityForBag
250  nsAString &_retval)
251 {
252  NS_ENSURE_ARG_POINTER(aPropertyBag);
253  nsresult rv;
254 
255  #ifdef DEBUG
256  nsString trackName;
257  rv = aPropertyBag->GetProperty(NS_LITERAL_STRING(SB_PROPERTY_TRACKNAME),
258  trackName);
259  if (NS_FAILED(rv) || trackName.IsEmpty()) {
260  trackName.AssignLiteral("No Track Name");
261  }
262  TRACE_FUNCTION("Generating an identity for \'%s\' ",
263  NS_ConvertUTF16toUTF8(trackName).get());
264  #endif
265 
266  // concatenate the properties that we are interested in together
267  nsString contentType;
268  rv = aPropertyBag->GetProperty(NS_LITERAL_STRING(SB_PROPERTY_CONTENTTYPE),
269  contentType);
270  NS_ENSURE_SUCCESS(rv, rv);
271 
272  /* we use different properties in the identity calculations for video and
273  * audio, so detect the type and get a string of the relevant property values
274  * concatenated together
275  * If the content property is not set then we don't need the hash, throw
276  * NS_ERROR_NOT_AVAILABLE.
277  */
278  nsString propString;
279  if (contentType.EqualsLiteral("video")) {
280  rv = GetPropertyStringForVideo(aPropertyBag, propString);
281  NS_ENSURE_SUCCESS(rv, rv);
282  }
283  else if (contentType.EqualsLiteral("audio")) {
284  rv = GetPropertyStringForAudio(aPropertyBag, propString);
285  NS_ENSURE_SUCCESS(rv, rv);
286  }
287 
288  // If we didn't recognize the content type or the hash properties
289  // were not found return a void string.
290  if (propString.IsEmpty()) {
291  _retval.SetIsVoid(PR_TRUE);
292  }
293  else {
294  // hash the concatenated string and return it
295  rv = HashString(propString, _retval);
296  NS_ENSURE_SUCCESS(rv, rv);
297  }
298  return NS_OK;
299 }
300 
301 //-----------------------------------------------------------------------------
302 /* sbIdentityService.idl, saveIdentityForMediaItem */
303 NS_IMETHODIMP
304 sbIdentityService::SaveIdentityToMediaItem
305  (sbIMediaItem *aMediaItem,
306  const nsAString &aIdentity)
307 {
308  NS_ENSURE_ARG_POINTER(aMediaItem);
309  nsresult rv;
310 
311  #ifdef DEBUG
312  nsString trackName;
313  rv = aMediaItem->GetProperty(NS_LITERAL_STRING(SB_PROPERTY_TRACKNAME),
314  trackName);
315  if (NS_FAILED(rv) || trackName.IsEmpty()) {
316  trackName.AssignLiteral("No Track Name");
317  }
318 
319  // present the debug string to NSPR log and console
320  TRACE_FUNCTION("Saving an identity of \'%s\' for track \'%s\'",
321  NS_ConvertUTF16toUTF8(aIdentity).get(),
322  NS_ConvertUTF16toUTF8(trackName).get());
323  #endif
324 
325  // save aIdentity to the propertybag for the param aMediaitem
326  rv = aMediaItem->SetProperty
327  (NS_LITERAL_STRING(SB_PROPERTY_METADATA_HASH_IDENTITY),
328  aIdentity);
329  NS_ENSURE_SUCCESS(rv, rv);
330 
331  return NS_OK;
332 }
333 
334 //-----------------------------------------------------------------------------
335 /* sbIdentityService.idl, saveIdentityForBag */
336 NS_IMETHODIMP
337 sbIdentityService::SaveIdentityToBag
339  const nsAString &aIdentity)
340 {
341  NS_ENSURE_ARG_POINTER(aPropertyBag);
342  nsresult rv;
343 
344  #ifdef DEBUG
345  nsString trackName;
346  rv = aPropertyBag->GetProperty(NS_LITERAL_STRING(SB_PROPERTY_TRACKNAME),
347  trackName);
348  if (NS_FAILED(rv) || trackName.IsEmpty()) {
349  trackName.AssignLiteral("No Track Name");
350  }
351 
352  // present the debug string to NSPR log and console
353  TRACE_FUNCTION("Saving an identity of \'%s\' for track \'%s\'",
354  NS_ConvertUTF16toUTF8(aIdentity).get(),
355  NS_ConvertUTF16toUTF8(trackName).get());
356  #endif
357 
358  // save the identity in the propertybag
359  rv = aPropertyBag->SetProperty
360  (NS_LITERAL_STRING(SB_PROPERTY_METADATA_HASH_IDENTITY),
361  aIdentity);
362  NS_ENSURE_SUCCESS(rv, rv);
363 
364  return NS_OK;
365 }
#define SB_PRLOG_SETUP(x)
Definition: sbDebugUtils.h:115
return NS_OK
static const char *const sAudioPropsToHash[]
const SEPARATOR
#define SB_PROPERTY_METADATA_HASH_IDENTITY
A service to provide identifiers for mediaitems.
#define SB_PROPERTY_GENRE
#define SB_PROPERTY_CONTENTTYPE
#define TRACE_FUNCTION(...)
Definition: sbDebugUtils.h:118
#define SB_PROPERTY_ARTISTNAME
[USER CODE SHOULD NOT REFERENCE THIS CLASS]
#define SB_PROPERTY_ALBUMNAME
NS_IMPL_THREADSAFE_ISUPPORTS1(sbIdentityService, sbIIdentityService) static const char SEPARATOR[]
Interface that defines a single item of media in the system.
#define SB_PROPERTY_TRACKNAME
static const char *const sVideoPropsToHash[]
_getSelectedPageStyle s i