dom/bindings/PrimitiveConversions.h

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
     2 /* vim: set ts=2 sw=2 et tw=79: */
     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/. */
     7 /**
     8  * Conversions from jsval to primitive values
     9  */
    11 #ifndef mozilla_dom_PrimitiveConversions_h
    12 #define mozilla_dom_PrimitiveConversions_h
    14 #include <limits>
    15 #include <math.h>
    16 #include <stdint.h>
    18 #include "jsapi.h"
    19 #include "mozilla/Assertions.h"
    20 #include "mozilla/ErrorResult.h"
    21 #include "mozilla/FloatingPoint.h"
    23 namespace mozilla {
    24 namespace dom {
    26 template<typename T>
    27 struct TypeName {
    28 };
    30 template<>
    31 struct TypeName<int8_t> {
    32   static const char* value() {
    33     return "byte";
    34   }
    35 };
    36 template<>
    37 struct TypeName<uint8_t> {
    38   static const char* value() {
    39     return "octet";
    40   }
    41 };
    42 template<>
    43 struct TypeName<int16_t> {
    44   static const char* value() {
    45     return "short";
    46   }
    47 };
    48 template<>
    49 struct TypeName<uint16_t> {
    50   static const char* value() {
    51     return "unsigned short";
    52   }
    53 };
    54 template<>
    55 struct TypeName<int32_t> {
    56   static const char* value() {
    57     return "long";
    58   }
    59 };
    60 template<>
    61 struct TypeName<uint32_t> {
    62   static const char* value() {
    63     return "unsigned long";
    64   }
    65 };
    66 template<>
    67 struct TypeName<int64_t> {
    68   static const char* value() {
    69     return "long long";
    70   }
    71 };
    72 template<>
    73 struct TypeName<uint64_t> {
    74   static const char* value() {
    75     return "unsigned long long";
    76   }
    77 };
    80 enum ConversionBehavior {
    81   eDefault,
    82   eEnforceRange,
    83   eClamp
    84 };
    86 template<typename T, ConversionBehavior B>
    87 struct PrimitiveConversionTraits {
    88 };
    90 template<typename T>
    91 struct DisallowedConversion {
    92   typedef int jstype;
    93   typedef int intermediateType;
    95 private:
    96   static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
    97                                jstype* retval) {
    98     MOZ_CRASH("This should never be instantiated!");
    99   }
   100 };
   102 struct PrimitiveConversionTraits_smallInt {
   103   // The output of JS::ToInt32 is determined as follows:
   104   //   1) The value is converted to a double
   105   //   2) Anything that's not a finite double returns 0
   106   //   3) The double is rounded towards zero to the nearest integer
   107   //   4) The resulting integer is reduced mod 2^32.  The output of this
   108   //      operation is an integer in the range [0, 2^32).
   109   //   5) If the resulting number is >= 2^31, 2^32 is subtracted from it.
   110   //
   111   // The result of all this is a number in the range [-2^31, 2^31)
   112   //
   113   // WebIDL conversions for the 8-bit, 16-bit, and 32-bit integer types
   114   // are defined in the same way, except that step 4 uses reduction mod
   115   // 2^8 and 2^16 for the 8-bit and 16-bit types respectively, and step 5
   116   // is only done for the signed types.
   117   //
   118   // C/C++ define integer conversion semantics to unsigned types as taking
   119   // your input integer mod (1 + largest value representable in the
   120   // unsigned type).  Since 2^32 is zero mod 2^8, 2^16, and 2^32,
   121   // converting to the unsigned int of the relevant width will correctly
   122   // perform step 4; in particular, the 2^32 possibly subtracted in step 5
   123   // will become 0.
   124   //
   125   // Once we have step 4 done, we're just going to assume 2s-complement
   126   // representation and cast directly to the type we really want.
   127   //
   128   // So we can cast directly for all unsigned types and for int32_t; for
   129   // the smaller-width signed types we need to cast through the
   130   // corresponding unsigned type.
   131   typedef int32_t jstype;
   132   typedef int32_t intermediateType;
   133   static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
   134                                jstype* retval) {
   135     return JS::ToInt32(cx, v, retval);
   136   }
   137 };
   138 template<>
   139 struct PrimitiveConversionTraits<int8_t, eDefault> : PrimitiveConversionTraits_smallInt {
   140   typedef uint8_t intermediateType;
   141 };
   142 template<>
   143 struct PrimitiveConversionTraits<uint8_t, eDefault> : PrimitiveConversionTraits_smallInt {
   144 };
   145 template<>
   146 struct PrimitiveConversionTraits<int16_t, eDefault> : PrimitiveConversionTraits_smallInt {
   147   typedef uint16_t intermediateType;
   148 };
   149 template<>
   150 struct PrimitiveConversionTraits<uint16_t, eDefault> : PrimitiveConversionTraits_smallInt {
   151 };
   152 template<>
   153 struct PrimitiveConversionTraits<int32_t, eDefault> : PrimitiveConversionTraits_smallInt {
   154 };
   155 template<>
   156 struct PrimitiveConversionTraits<uint32_t, eDefault> : PrimitiveConversionTraits_smallInt {
   157 };
   159 template<>
   160 struct PrimitiveConversionTraits<int64_t, eDefault> {
   161   typedef int64_t jstype;
   162   typedef int64_t intermediateType;
   163   static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
   164                                jstype* retval) {
   165     return JS::ToInt64(cx, v, retval);
   166   }
   167 };
   169 template<>
   170 struct PrimitiveConversionTraits<uint64_t, eDefault> {
   171   typedef uint64_t jstype;
   172   typedef uint64_t intermediateType;
   173   static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
   174                                jstype* retval) {
   175     return JS::ToUint64(cx, v, retval);
   176   }
   177 };
   179 template<typename T>
   180 struct PrimitiveConversionTraits_Limits {
   181   static inline T min() {
   182     return std::numeric_limits<T>::min();
   183   }
   184   static inline T max() {
   185     return std::numeric_limits<T>::max();
   186   }
   187 };
   189 template<>
   190 struct PrimitiveConversionTraits_Limits<int64_t> {
   191   static inline int64_t min() {
   192     return -(1LL << 53);
   193   }
   194   static inline int64_t max() {
   195     return (1LL << 53);
   196   }
   197 };
   199 template<>
   200 struct PrimitiveConversionTraits_Limits<uint64_t> {
   201   static inline uint64_t min() {
   202     return 0;
   203   }
   204   static inline uint64_t max() {
   205     return (1LL << 53);
   206   }
   207 };
   209 template<typename T, bool (*Enforce)(JSContext* cx, const double& d, T* retval)>
   210 struct PrimitiveConversionTraits_ToCheckedIntHelper {
   211   typedef T jstype;
   212   typedef T intermediateType;
   214   static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
   215                                jstype* retval) {
   216     double intermediate;
   217     if (!JS::ToNumber(cx, v, &intermediate)) {
   218       return false;
   219     }
   221     return Enforce(cx, intermediate, retval);
   222   }
   223 };
   225 template<typename T>
   226 inline bool
   227 PrimitiveConversionTraits_EnforceRange(JSContext* cx, const double& d, T* retval)
   228 {
   229   static_assert(std::numeric_limits<T>::is_integer,
   230                 "This can only be applied to integers!");
   232   if (!mozilla::IsFinite(d)) {
   233     return ThrowErrorMessage(cx, MSG_ENFORCE_RANGE_NON_FINITE, TypeName<T>::value());
   234   }
   236   bool neg = (d < 0);
   237   double rounded = floor(neg ? -d : d);
   238   rounded = neg ? -rounded : rounded;
   239   if (rounded < PrimitiveConversionTraits_Limits<T>::min() ||
   240       rounded > PrimitiveConversionTraits_Limits<T>::max()) {
   241     return ThrowErrorMessage(cx, MSG_ENFORCE_RANGE_OUT_OF_RANGE, TypeName<T>::value());
   242   }
   244   *retval = static_cast<T>(rounded);
   245   return true;
   246 }
   248 template<typename T>
   249 struct PrimitiveConversionTraits<T, eEnforceRange> :
   250   public PrimitiveConversionTraits_ToCheckedIntHelper<T, PrimitiveConversionTraits_EnforceRange<T> > {
   251 };
   253 template<typename T>
   254 inline bool
   255 PrimitiveConversionTraits_Clamp(JSContext* cx, const double& d, T* retval)
   256 {
   257   static_assert(std::numeric_limits<T>::is_integer,
   258                 "This can only be applied to integers!");
   260   if (mozilla::IsNaN(d)) {
   261     *retval = 0;
   262     return true;
   263   }
   264   if (d >= PrimitiveConversionTraits_Limits<T>::max()) {
   265     *retval = PrimitiveConversionTraits_Limits<T>::max();
   266     return true;
   267   }
   268   if (d <= PrimitiveConversionTraits_Limits<T>::min()) {
   269     *retval = PrimitiveConversionTraits_Limits<T>::min();
   270     return true;
   271   }
   273   MOZ_ASSERT(mozilla::IsFinite(d));
   275   // Banker's rounding (round ties towards even).
   276   // We move away from 0 by 0.5f and then truncate.  That gets us the right
   277   // answer for any starting value except plus or minus N.5.  With a starting
   278   // value of that form, we now have plus or minus N+1.  If N is odd, this is
   279   // the correct result.  If N is even, plus or minus N is the correct result.
   280   double toTruncate = (d < 0) ? d - 0.5 : d + 0.5;
   282   T truncated = static_cast<T>(toTruncate);
   284   if (truncated == toTruncate) {
   285     /*
   286      * It was a tie (since moving away from 0 by 0.5 gave us the exact integer
   287      * we want). Since we rounded away from 0, we either already have an even
   288      * number or we have an odd number but the number we want is one closer to
   289      * 0. So just unconditionally masking out the ones bit should do the trick
   290      * to get us the value we want.
   291      */
   292     truncated &= ~1;
   293   }
   295   *retval = truncated;
   296   return true;
   297 }
   299 template<typename T>
   300 struct PrimitiveConversionTraits<T, eClamp> :
   301   public PrimitiveConversionTraits_ToCheckedIntHelper<T, PrimitiveConversionTraits_Clamp<T> > {
   302 };
   305 template<ConversionBehavior B>
   306 struct PrimitiveConversionTraits<bool, B> : public DisallowedConversion<bool> {};
   308 template<>
   309 struct PrimitiveConversionTraits<bool, eDefault> {
   310   typedef bool jstype;
   311   typedef bool intermediateType;
   312   static inline bool converter(JSContext* /* unused */, JS::Handle<JS::Value> v,
   313                                jstype* retval) {
   314     *retval = JS::ToBoolean(v);
   315     return true;
   316   }
   317 };
   320 template<ConversionBehavior B>
   321 struct PrimitiveConversionTraits<float, B> : public DisallowedConversion<float> {};
   323 template<ConversionBehavior B>
   324 struct PrimitiveConversionTraits<double, B> : public DisallowedConversion<double> {};
   326 struct PrimitiveConversionTraits_float {
   327   typedef double jstype;
   328   typedef double intermediateType;
   329   static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
   330                                jstype* retval) {
   331     return JS::ToNumber(cx, v, retval);
   332   }
   333 };
   335 template<>
   336 struct PrimitiveConversionTraits<float, eDefault> : PrimitiveConversionTraits_float {
   337 };
   338 template<>
   339 struct PrimitiveConversionTraits<double, eDefault> : PrimitiveConversionTraits_float {
   340 };
   343 template<typename T, ConversionBehavior B>
   344 bool ValueToPrimitive(JSContext* cx, JS::Handle<JS::Value> v, T* retval)
   345 {
   346   typename PrimitiveConversionTraits<T, B>::jstype t;
   347   if (!PrimitiveConversionTraits<T, B>::converter(cx, v, &t))
   348     return false;
   350   *retval = static_cast<T>(
   351     static_cast<typename PrimitiveConversionTraits<T, B>::intermediateType>(t));
   352   return true;
   353 }
   355 } // namespace dom
   356 } // namespace mozilla
   358 #endif /* mozilla_dom_PrimitiveConversions_h */

mercurial