sbNumberPropertyInfo.cpp
Go to the documentation of this file.
1 /*
2 //
3 // BEGIN SONGBIRD GPL
4 //
5 // This file is part of the Songbird web player.
6 //
7 // Copyright(c) 2005-2008 POTI, Inc.
8 // http://songbirdnest.com
9 //
10 // This file may be licensed under the terms of of the
11 // GNU General Public License Version 2 (the "GPL").
12 //
13 // Software distributed under the License is distributed
14 // on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
15 // express or implied. See the GPL for the specific language
16 // governing rights and limitations.
17 //
18 // You should have received a copy of the GPL along with this
19 // program. If not, go to http://www.gnu.org/licenses/gpl.html
20 // or write to the Free Software Foundation, Inc.,
21 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 // END SONGBIRD GPL
24 //
25 */
26 
27 #include "sbNumberPropertyInfo.h"
28 
29 #include <float.h>
30 #include <nsAutoPtr.h>
31 #include <prprf.h>
32 
33 #include <sbLockUtils.h>
35 
36 static inline
37 PRBool IsValidRadix(PRUint32 aRadix)
38 {
39  if(aRadix == 8 ||
40  aRadix == 10 ||
41  aRadix == 16 ||
42  aRadix == 0) {
43  return PR_TRUE;
44  }
45 
46  return PR_FALSE;
47 }
48 
49 /*static data for static inline function*/
50 static const char *gsFmtRadix8 = "%llo";
51 static const char *gsFmtRadix10 = "%lld";
52 static const char *gsFmtRadix16 = "%llX";
53 static const char *gsFmtFloat = "%lg";
54 
55 static inline
56 const char *GetFmtFromRadix(PRUint32 aRadix)
57 {
58  const char *fmt = nsnull;
59 
60  switch(aRadix) {
62  fmt = gsFmtRadix8;
63  break;
64 
66  fmt = gsFmtRadix10;
67  break;
68 
70  fmt = gsFmtRadix16;
71  break;
72 
74  fmt = gsFmtFloat;
75  break;
76  }
77 
78  return fmt;
79 }
80 
81 /*static data for static inline function*/
82 static const char *gsSortFmtRadix8 = "%022llo";
83 static const char *gsSortFmtRadix10 = "%+020lld";
84 static const char *gsSortFmtRadix16 = "%016llX";
85 static const char *gsSortFmtFloat = "%+046.16lf";
86 
87 static inline
88 const char *GetSortableFmtFromRadix(PRUint32 aRadix)
89 {
90  const char *fmt = nsnull;
91 
92  switch(aRadix) {
94  fmt = gsSortFmtRadix8;
95  break;
96 
98  fmt = gsSortFmtRadix10;
99  break;
100 
102  fmt = gsSortFmtRadix16;
103  break;
104 
106  fmt = gsSortFmtFloat;
107  break;
108  }
109 
110  return fmt;
111 }
112 
115 
116 NS_INTERFACE_TABLE_HEAD(sbNumberPropertyInfo)
117 NS_INTERFACE_TABLE_BEGIN
118 NS_INTERFACE_TABLE_ENTRY(sbNumberPropertyInfo, sbINumberPropertyInfo)
119 NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(sbNumberPropertyInfo, sbIPropertyInfo, sbINumberPropertyInfo)
120 NS_INTERFACE_TABLE_END
121 NS_INTERFACE_TABLE_TAIL_INHERITING(sbPropertyInfo)
122 
123 sbNumberPropertyInfo::sbNumberPropertyInfo()
124 : mMinMaxValueLock(nsnull)
125 , mMinValue(LL_MININT)
126 , mMaxValue(LL_MAXINT)
127 , mMinFloatValue(DBL_MIN)
128 , mMaxFloatValue(DBL_MAX)
129 , mHasSetMinValue(PR_FALSE)
130 , mHasSetMaxValue(PR_FALSE)
131 , mRadix(sbINumberPropertyInfo::RADIX_10)
132 {
133  mType = NS_LITERAL_STRING("number");
134 
135  mMinMaxValueLock = PR_NewLock();
136  NS_ASSERTION(mMinMaxValueLock,
137  "sbNumberPropertyInfo::mMinMaxValueLock failed to create lock!");
138 
139  mRadixLock = PR_NewLock();
140  NS_ASSERTION(mRadixLock,
141  "sbNumberPropertyInfo::mRadixLock failed to create lock!");
142 }
143 
145 {
146  if(mMinMaxValueLock) {
147  PR_DestroyLock(mMinMaxValueLock);
148  }
149  if(mRadixLock) {
150  PR_DestroyLock(mRadixLock);
151  }
152 }
153 
154 nsresult
156  nsresult rv;
157 
158  rv = sbPropertyInfo::Init();
159  NS_ENSURE_SUCCESS(rv, rv);
160 
161  rv = InitializeOperators();
162  NS_ENSURE_SUCCESS(rv, rv);
163 
164  return NS_OK;
165 }
166 
167 nsresult
169 {
170  nsresult rv;
171  nsAutoString op;
172  nsRefPtr<sbPropertyOperator> propOp;
173 
174  rv = sbPropertyInfo::GetOPERATOR_EQUALS(op);
175  NS_ENSURE_SUCCESS(rv, rv);
176  propOp = new sbPropertyOperator(op, NS_LITERAL_STRING("&smart.int.equal"));
177  NS_ENSURE_TRUE(propOp, NS_ERROR_OUT_OF_MEMORY);
178  rv = mOperators.AppendObject(propOp);
179  NS_ENSURE_SUCCESS(rv, rv);
180 
181  rv = sbPropertyInfo::GetOPERATOR_NOTEQUALS(op);
182  NS_ENSURE_SUCCESS(rv, rv);
183  propOp = new sbPropertyOperator(op, NS_LITERAL_STRING("&smart.int.notequal"));
184  NS_ENSURE_TRUE(propOp, NS_ERROR_OUT_OF_MEMORY);
185  rv = mOperators.AppendObject(propOp);
186  NS_ENSURE_SUCCESS(rv, rv);
187 
188  rv = sbPropertyInfo::GetOPERATOR_GREATER(op);
189  NS_ENSURE_SUCCESS(rv, rv);
190  propOp = new sbPropertyOperator(op, NS_LITERAL_STRING("&smart.int.greater"));
191  NS_ENSURE_TRUE(propOp, NS_ERROR_OUT_OF_MEMORY);
192  rv = mOperators.AppendObject(propOp);
193  NS_ENSURE_SUCCESS(rv, rv);
194 
195  rv = sbPropertyInfo::GetOPERATOR_GREATEREQUAL(op);
196  NS_ENSURE_SUCCESS(rv, rv);
197  propOp = new sbPropertyOperator(op, NS_LITERAL_STRING("&smart.int.greaterequal"));
198  NS_ENSURE_TRUE(propOp, NS_ERROR_OUT_OF_MEMORY);
199  rv = mOperators.AppendObject(propOp);
200  NS_ENSURE_SUCCESS(rv, rv);
201 
202  rv = sbPropertyInfo::GetOPERATOR_LESS(op);
203  NS_ENSURE_SUCCESS(rv, rv);
204  propOp = new sbPropertyOperator(op, NS_LITERAL_STRING("&smart.int.less"));
205  NS_ENSURE_TRUE(propOp, NS_ERROR_OUT_OF_MEMORY);
206  rv = mOperators.AppendObject(propOp);
207  NS_ENSURE_SUCCESS(rv, rv);
208 
209  rv = sbPropertyInfo::GetOPERATOR_LESSEQUAL(op);
210  NS_ENSURE_SUCCESS(rv, rv);
211  propOp = new sbPropertyOperator(op, NS_LITERAL_STRING("&smart.int.lessequal"));
212  NS_ENSURE_TRUE(propOp, NS_ERROR_OUT_OF_MEMORY);
213  rv = mOperators.AppendObject(propOp);
214  NS_ENSURE_SUCCESS(rv, rv);
215 
216  rv = sbPropertyInfo::GetOPERATOR_BETWEEN(op);
217  NS_ENSURE_SUCCESS(rv, rv);
218  propOp = new sbPropertyOperator(op, NS_LITERAL_STRING("&smart.int.between"));
219  NS_ENSURE_TRUE(propOp, NS_ERROR_OUT_OF_MEMORY);
220  rv = mOperators.AppendObject(propOp);
221  NS_ENSURE_SUCCESS(rv, rv);
222 
223  return NS_OK;
224 }
225 
226 NS_IMETHODIMP sbNumberPropertyInfo::Validate(const nsAString & aValue, PRBool *_retval)
227 {
228  NS_ENSURE_ARG_POINTER(_retval);
229 
230  *_retval = PR_TRUE;
231  if (aValue.IsVoid()) {
232  return NS_OK;
233  }
234 
235  PRInt64 value = 0;
236  PRFloat64 floatValue = 0;
237 
238  NS_ConvertUTF16toUTF8 narrow(aValue);
239 
240  sbSimpleAutoLock lockRadix(mRadixLock);
241  const char *fmt = GetFmtFromRadix(mRadix);
242 
243  // Add a string parsing specifier, to catch extra characters behind
244  // the number. Limit string parsing to 16 chars, we just want to check
245  // if something's there anyway, we don't want to do anything with the
246  // actual string
247  nsAutoString ext_fmt;
248  ext_fmt.AssignLiteral(fmt);
249  ext_fmt += NS_LITERAL_STRING("%16s");
250  const char remainder[17]="";
251  PRInt32 r = 0;
252  if(mRadix) {
253  r = PR_sscanf(narrow.get(),
254  NS_LossyConvertUTF16toASCII(ext_fmt).get(),
255  &value,
256  remainder);
257  }
258  else {
259  r = PR_sscanf(narrow.get(),
260  NS_LossyConvertUTF16toASCII(ext_fmt).get(),
261  &floatValue,
262  remainder);
263  }
264 
265  if (r < 1) {
266  // We got less than one parameter (the number) that parsed correctly,
267  // the value is not valid.
268  *_retval = PR_FALSE;
269  }
270 
271  // Otherwise, check whether we got something in the string. Can't rely on the
272  // return value from PR_sscanf here because a number by itself will still parse
273  // an empty trailing string successfully
274  if (*remainder != 0) {
275  // We got extra characters, the value is not valid.
276  *_retval = PR_FALSE;
277  }
278 
279  // This part is specific to integer values. Floats need to be checked against
280  // different min/max values.
282  if(mRadix) {
283  // Now check min & max constraints
284  if(value < mMinValue ||
285  value > mMaxValue) {
286  // Value is above or below limits, not valid.
287  *_retval = PR_FALSE;
288  }
289  }
290  else {
291  // Now check min & max constraints
292  if(floatValue < mMinFloatValue ||
293  floatValue > mMaxFloatValue) {
294  // Value is above or below limits, not valid.
295  *_retval = PR_FALSE;
296  }
297  }
298 
299  return NS_OK;
300 }
301 
302 NS_IMETHODIMP sbNumberPropertyInfo::Sanitize(const nsAString & aValue, nsAString & _retval)
303 {
304  return NS_ERROR_NOT_IMPLEMENTED;
305 }
306 
307 NS_IMETHODIMP sbNumberPropertyInfo::Format(const nsAString & aValue, nsAString & _retval)
308 {
309  PRInt64 value = 0;
310  PRFloat64 floatValue = 0;
311 
312  NS_ConvertUTF16toUTF8 narrow(aValue);
313 
314  _retval = aValue;
315  _retval.StripWhitespace();
316 
317  sbSimpleAutoLock lockRadix(mRadixLock);
318  const char *fmt = GetFmtFromRadix(mRadix);
319 
321  if(mRadix) {
322  if(PR_sscanf(narrow.get(), fmt, &value) != 1) {
323  _retval = EmptyString();
324  return NS_ERROR_INVALID_ARG;
325  }
326  }
327  else {
328  if(PR_sscanf(narrow.get(), fmt, &floatValue) != 1) {
329  _retval = EmptyString();
330  return NS_ERROR_INVALID_ARG;
331  }
332  }
333 
334  char out[64] = {0};
335  if(mRadix) {
336  PR_snprintf(out, 64, fmt, value);
337  }
338  else {
339  PR_snprintf(out, 64, fmt, floatValue);
340  }
341 
342  NS_ConvertUTF8toUTF16 wide(out);
343  _retval = EmptyString();
344 
345  if(fmt == gsFmtRadix16) {
346  _retval.AssignLiteral("0x");
347  }
348  else if(fmt == gsFmtRadix8) {
349  _retval.AssignLiteral("0");
350  }
351 
352  _retval.Append(wide);
353 
354  return NS_OK;
355 }
356 
357 NS_IMETHODIMP sbNumberPropertyInfo::MakeSearchable(const nsAString & aValue, nsAString & _retval)
358 {
359  nsresult rv;
360  _retval = aValue;
361  if (aValue.IsVoid()) {
362  return NS_OK;
363  }
364 
365  PRInt64 value = 0;
366  PRFloat64 floatValue = 0;
367 
368  NS_ConvertUTF16toUTF8 narrow(aValue);
369 
370  _retval.StripWhitespace();
371 
372  sbSimpleAutoLock lockRadix(mRadixLock);
373  const char *fmt = GetFmtFromRadix(mRadix);
374 
375  PRInt32 parsedCount = 0;
377  if(mRadix) {
378  parsedCount = PR_sscanf(narrow.get(), fmt, &value);
379  }
380  else {
381  parsedCount = PR_sscanf(narrow.get(), fmt, &floatValue);
382  }
383 
384  if(parsedCount != 1) {
385  _retval = EmptyString();
386  return NS_ERROR_INVALID_ARG;
387  }
388 
389 
390  PRUint32 outputLength = 0;
391  char out[64] = {0};
392  const char *sortableFmt = GetSortableFmtFromRadix(mRadix);
393 
394  if(mRadix) {
395  outputLength = PR_snprintf(out, 64, sortableFmt, value);
396  }
397  else {
398  outputLength = PR_snprintf(out, 64, sortableFmt, floatValue);
399  }
400 
401  if(outputLength == (PRUint32)-1) {
402  rv = NS_ERROR_FAILURE;
403  _retval = EmptyString();
404  }
405  else {
406  NS_ConvertUTF8toUTF16 wide(out);
407  rv = NS_OK;
408  _retval = wide;
409  }
410 
411  return rv;
412 }
413 
414 NS_IMETHODIMP sbNumberPropertyInfo::GetMinValue(PRInt64 *aMinValue)
415 {
416  NS_ENSURE_ARG_POINTER(aMinValue);
418  *aMinValue = mMinValue;
419  return NS_OK;
420 }
421 NS_IMETHODIMP sbNumberPropertyInfo::SetMinValue(PRInt64 aMinValue)
422 {
424 
425  if(!mHasSetMinValue) {
426  mMinValue = aMinValue;
427  mHasSetMinValue = PR_TRUE;
428  return NS_OK;
429  }
430 
431  return NS_ERROR_ALREADY_INITIALIZED;
432 }
433 
434 NS_IMETHODIMP sbNumberPropertyInfo::GetMaxValue(PRInt64 *aMaxValue)
435 {
436  NS_ENSURE_ARG_POINTER(aMaxValue);
438  *aMaxValue = mMaxValue;
439  return NS_OK;
440 }
441 NS_IMETHODIMP sbNumberPropertyInfo::SetMaxValue(PRInt64 aMaxValue)
442 {
444 
445  if(!mHasSetMaxValue) {
446  mMaxValue = aMaxValue;
447  mHasSetMaxValue = PR_TRUE;
448  return NS_OK;
449  }
450 
451  return NS_ERROR_ALREADY_INITIALIZED;
452 }
453 
454 NS_IMETHODIMP sbNumberPropertyInfo::GetMinFloatValue(PRFloat64 *aMinFloatValue)
455 {
456  NS_ENSURE_ARG_POINTER(aMinFloatValue);
458  *aMinFloatValue = mMinFloatValue;
459  return NS_OK;
460 }
461 NS_IMETHODIMP sbNumberPropertyInfo::SetMinFloatValue(PRFloat64 aMinFloatValue)
462 {
464 
465  if(!mHasSetMinValue) {
466  mMinFloatValue = aMinFloatValue;
467  mHasSetMinValue = PR_TRUE;
468  return NS_OK;
469  }
470 
471  return NS_ERROR_ALREADY_INITIALIZED;
472 }
473 
474 NS_IMETHODIMP sbNumberPropertyInfo::GetMaxFloatValue(PRFloat64 *aMaxFloatValue)
475 {
476  NS_ENSURE_ARG_POINTER(aMaxFloatValue);
478  *aMaxFloatValue = mMaxFloatValue;
479  return NS_OK;
480 }
481 NS_IMETHODIMP sbNumberPropertyInfo::SetMaxFloatValue(PRFloat64 aMaxFloatValue)
482 {
484 
485  if(!mHasSetMaxValue) {
486  mMaxFloatValue = aMaxFloatValue;
487  mHasSetMaxValue = PR_TRUE;
488  return NS_OK;
489  }
490 
491  return NS_ERROR_ALREADY_INITIALIZED;
492 }
493 
494 NS_IMETHODIMP sbNumberPropertyInfo::GetRadix(PRUint32 *aRadix)
495 {
496  NS_ENSURE_ARG_POINTER(aRadix);
497 
499  *aRadix = mRadix;
500  return NS_OK;
501 }
502 NS_IMETHODIMP sbNumberPropertyInfo::SetRadix(PRUint32 aRadix)
503 {
504  NS_ENSURE_TRUE(IsValidRadix(aRadix), NS_ERROR_INVALID_ARG);
506  mRadix = aRadix;
507  return NS_OK;
508 }
const unsigned long RADIX_10
Signed decimal representation (eg. 14 decimal)
static PRBool IsValidRadix(PRUint32 aRadix)
return NS_OK
static const char * gsFmtRadix16
onPageChanged aValue
Definition: FeedWriter.js:1395
NS_IMETHOD Sanitize(const nsAString &aValue, nsAString &_retval)
NS_IMETHOD Format(const nsAString &aValue, nsAString &_retval)
static const char * GetSortableFmtFromRadix(PRUint32 aRadix)
static const char * gsSortFmtFloat
The property information specific to numeric fields.
const unsigned long RADIX_8
Unsigned octal representation (eg. 16, or 14 decimal).
const unsigned long RADIX_16
Unsigned hex representation (eg. 0x0E, or 14 decimal)
NS_IMPL_RELEASE_INHERITED(sbNumberPropertyInfo, sbPropertyInfo)
NS_IMETHOD Validate(const nsAString &aValue, PRBool *_retval)
An interface used to describe a metadata property for use by the UI and other sbILibrary interfaces (...
static const char * gsSortFmtRadix10
static const char * gsFmtRadix10
static const char * gsSortFmtRadix8
countRef value
Definition: FeedWriter.js:1423
NS_IMPL_ADDREF_INHERITED(sbNumberPropertyInfo, sbPropertyInfo)
nsCOMArray< sbIPropertyOperator > mOperators
NS_IMETHOD MakeSearchable(const nsAString &aValue, nsAString &_retval)
static const char * gsFmtRadix8
const unsigned long FLOAT
Signed floating point representation (eg. 14.89)
static const char * gsSortFmtRadix16
static const char * GetFmtFromRadix(PRUint32 aRadix)
static const char * gsFmtFloat