Advertisement
Guest User

chris

a guest
Oct 29th, 2009
272
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 72.88 KB | None | 0 0
  1. // ==++==
  2. //
  3. //  
  4. //    Copyright (c) 2006 Microsoft Corporation.  All rights reserved.
  5. //  
  6. //    The use and distribution terms for this software are contained in the file
  7. //    named license.txt, which can be found in the root of this distribution.
  8. //    By using this software in any fashion, you are agreeing to be bound by the
  9. //    terms of this license.
  10. //  
  11. //    You must not remove this notice, or any other, from this software.
  12. //  
  13. //
  14. // ==--==
  15. #include "common.h"
  16. #include "excep.h"
  17. #include "comnumber.h"
  18. #include "comstring.h"
  19. #include "comdecimal.h"
  20. #include <stdlib.h>
  21.  
  22. typedef wchar_t wchar;
  23.  
  24. #define INT32_PRECISION 10
  25. #define UINT32_PRECISION INT32_PRECISION
  26. #define INT64_PRECISION 19
  27. #define UINT64_PRECISION 20
  28. #define FLOAT_PRECISION 7
  29. #define DOUBLE_PRECISION 15
  30. #define LARGE_BUFFER_SIZE 600
  31. #define MIN_BUFFER_SIZE 105
  32.  
  33. #define SCALE_NAN 0x80000000
  34. #define SCALE_INF 0x7FFFFFFF
  35.  
  36. struct FPSINGLE {
  37. #if BIGENDIAN
  38.     unsigned int sign: 1;
  39.     unsigned int exp: 8;
  40.     unsigned int mant: 23;
  41. #else
  42.     unsigned int mant: 23;
  43.     unsigned int exp: 8;
  44.     unsigned int sign: 1;
  45. #endif
  46. };
  47.  
  48. struct FPDOUBLE {
  49. #if BIGENDIAN
  50.     unsigned int sign: 1;
  51.     unsigned int exp: 11;
  52.     unsigned int mantHi: 20;
  53.     unsigned int mantLo;
  54. #else
  55.     unsigned int mantLo;
  56.     unsigned int mantHi: 20;
  57.     unsigned int exp: 11;
  58.     unsigned int sign: 1;
  59. #endif
  60. };
  61.  
  62. static const char* const posCurrencyFormats[] = {
  63.     "$#", "#$", "$ #", "# $"};
  64.  
  65. static const char* const negCurrencyFormats[] = {
  66.         "($#)", "-$#", "$-#", "$#-",
  67.             "(#$)", "-#$", "#-$", "#$-",
  68.             "-# $", "-$ #", "# $-", "$ #-",
  69.             "$ -#", "#- $", "($ #)", "(# $)"};
  70.  
  71. static const char* const posPercentFormats[] = {
  72.             "# %", "#%", "%#", "% #"
  73.         };
  74.  
  75. static const char* const negPercentFormats[] = {
  76.     "-# %", "-#%", "-%#",
  77.         "%-#", "%#-",
  78.         "#-%", "#%-",
  79.         "-% #", "# %-", "% #-",
  80.         "% -#", "#- %"
  81.         };
  82.  
  83. static const char* const negNumberFormats[] = {
  84.             "(#)", "-#", "- #", "#-", "# -",
  85.         };
  86.  
  87. static const char posNumberFormat[] = "#";
  88.  
  89.  
  90.  
  91. void DoubleToNumber(double value, int precision, NUMBER* number)
  92. {
  93.     WRAPPER_CONTRACT
  94.     _ASSERTE(number != NULL);
  95.  
  96.     number->precision = precision;
  97.     if (((FPDOUBLE*)&value)->exp == 0x7FF) {
  98.         number->scale = (((FPDOUBLE*)&value)->mantLo || ((FPDOUBLE*)&value)->mantHi) ? SCALE_NAN: SCALE_INF;
  99.         number->sign = ((FPDOUBLE*)&value)->sign;
  100.         number->digits[0] = 0;
  101.     }
  102.     else {
  103.         char* src = _ecvt(value, precision, &number->scale, &number->sign);
  104.         wchar* dst = number->digits;
  105.         if (*src != '0') {
  106.             while (*src) *dst++ = *src++;
  107.         }
  108.         *dst = 0;
  109.     }
  110. }
  111.  
  112. /*===========================================================
  113.     Portable NumberToDouble implementation
  114.     --------------------------------------
  115.  
  116.     - does the conversion with the best possible precision.
  117.     - does not use any float arithmetic so it is not sensitive
  118.     to differences in precision of floating point calculations
  119.     across platforms.
  120.  
  121.     The internal integer representation of the float number is
  122.     UINT64 mantisa + INT exponent. The mantisa is kept normalized
  123.     ie with the most significant one being 63-th bit of UINT64.
  124. ===========================================================*/
  125.  
  126. //
  127. // get 32-bit integer from at most 9 digits
  128. //
  129. static unsigned DigitsToInt(__in_ecount(count) wchar* p, int count)
  130. {
  131.     LEAF_CONTRACT
  132.  
  133.     _ASSERTE(1 <= count && count <= 9);
  134.     wchar* end = p + count;
  135.     unsigned res = *p - '0';
  136.     for ( p = p + 1; p < end; p++) {
  137.         res = 10 * res + *p - '0';
  138.     }
  139.     return res;
  140. }
  141.  
  142. //
  143. // helper macro to multiply two 32-bit uints
  144. //
  145. #define Mul32x32To64(a, b) ((UINT64)((UINT32)(a)) * (UINT64)((UINT32)(b)))
  146.  
  147. //
  148. // multiply two numbers in the internal integer representation
  149. //
  150. static UINT64 Mul64Lossy(UINT64 a, UINT64 b, INT* pexp)
  151. {
  152.     LEAF_CONTRACT
  153.  
  154.     // it's ok to losse some precision here - Mul64 will be called
  155.     // at most twice during the conversion, so the error won't propagate
  156.     // to any of the 53 significant bits of the result
  157.     UINT64 val = Mul32x32To64(a >> 32, b >> 32) +
  158.         (Mul32x32To64(a >> 32, b) >> 32) +
  159.         (Mul32x32To64(a, b >> 32) >> 32);
  160.  
  161.     // normalize
  162.     if ((val & I64(0x8000000000000000)) == 0) { val <<= 1; *pexp -= 1; }
  163.  
  164.     return val;
  165. }
  166.  
  167. //
  168. // precomputed tables with powers of 10. These allows us to do at most
  169. // two Mul64 during the conversion. This is important not only
  170. // for speed, but also for precision because of Mul64 computes with 1 bit error.
  171. //
  172.  
  173. static const UINT64 rgval64Power10[] = {
  174. // powers of 10
  175. /*1*/ I64(0xa000000000000000),
  176. /*2*/ I64(0xc800000000000000),
  177. /*3*/ I64(0xfa00000000000000),
  178. /*4*/ I64(0x9c40000000000000),
  179. /*5*/ I64(0xc350000000000000),
  180. /*6*/ I64(0xf424000000000000),
  181. /*7*/ I64(0x9896800000000000),
  182. /*8*/ I64(0xbebc200000000000),
  183. /*9*/ I64(0xee6b280000000000),
  184. /*10*/ I64(0x9502f90000000000),
  185. /*11*/ I64(0xba43b74000000000),
  186. /*12*/ I64(0xe8d4a51000000000),
  187. /*13*/ I64(0x9184e72a00000000),
  188. /*14*/ I64(0xb5e620f480000000),
  189. /*15*/ I64(0xe35fa931a0000000),
  190.  
  191. // powers of 0.1
  192. /*1*/ I64(0xcccccccccccccccd),
  193. /*2*/ I64(0xa3d70a3d70a3d70b),
  194. /*3*/ I64(0x83126e978d4fdf3c),
  195. /*4*/ I64(0xd1b71758e219652e),
  196. /*5*/ I64(0xa7c5ac471b478425),
  197. /*6*/ I64(0x8637bd05af6c69b7),
  198. /*7*/ I64(0xd6bf94d5e57a42be),
  199. /*8*/ I64(0xabcc77118461ceff),
  200. /*9*/ I64(0x89705f4136b4a599),
  201. /*10*/ I64(0xdbe6fecebdedd5c2),
  202. /*11*/ I64(0xafebff0bcb24ab02),
  203. /*12*/ I64(0x8cbccc096f5088cf),
  204. /*13*/ I64(0xe12e13424bb40e18),
  205. /*14*/ I64(0xb424dc35095cd813),
  206. /*15*/ I64(0x901d7cf73ab0acdc),
  207. };
  208.  
  209. static const INT8 rgexp64Power10[] = {
  210. // exponents for both powers of 10 and 0.1
  211. /*1*/ 4,
  212. /*2*/ 7,
  213. /*3*/ 10,
  214. /*4*/ 14,
  215. /*5*/ 17,
  216. /*6*/ 20,
  217. /*7*/ 24,
  218. /*8*/ 27,
  219. /*9*/ 30,
  220. /*10*/ 34,
  221. /*11*/ 37,
  222. /*12*/ 40,
  223. /*13*/ 44,
  224. /*14*/ 47,
  225. /*15*/ 50,
  226. };
  227.  
  228. static const UINT64 rgval64Power10By16[] = {
  229. // powers of 10^16
  230. /*1*/ I64(0x8e1bc9bf04000000),
  231. /*2*/ I64(0x9dc5ada82b70b59e),
  232. /*3*/ I64(0xaf298d050e4395d6),
  233. /*4*/ I64(0xc2781f49ffcfa6d4),
  234. /*5*/ I64(0xd7e77a8f87daf7fa),
  235. /*6*/ I64(0xefb3ab16c59b14a0),
  236. /*7*/ I64(0x850fadc09923329c),
  237. /*8*/ I64(0x93ba47c980e98cde),
  238. /*9*/ I64(0xa402b9c5a8d3a6e6),
  239. /*10*/ I64(0xb616a12b7fe617a8),
  240. /*11*/ I64(0xca28a291859bbf90),
  241. /*12*/ I64(0xe070f78d39275566),
  242. /*13*/ I64(0xf92e0c3537826140),
  243. /*14*/ I64(0x8a5296ffe33cc92c),
  244. /*15*/ I64(0x9991a6f3d6bf1762),
  245. /*16*/ I64(0xaa7eebfb9df9de8a),
  246. /*17*/ I64(0xbd49d14aa79dbc7e),
  247. /*18*/ I64(0xd226fc195c6a2f88),
  248. /*19*/ I64(0xe950df20247c83f8),
  249. /*20*/ I64(0x81842f29f2cce373),
  250. /*21*/ I64(0x8fcac257558ee4e2),
  251.  
  252. // powers of 0.1^16
  253. /*1*/ I64(0xe69594bec44de160),
  254. /*2*/ I64(0xcfb11ead453994c3),
  255. /*3*/ I64(0xbb127c53b17ec165),
  256. /*4*/ I64(0xa87fea27a539e9b3),
  257. /*5*/ I64(0x97c560ba6b0919b5),
  258. /*6*/ I64(0x88b402f7fd7553ab),
  259. /*7*/ I64(0xf64335bcf065d3a0),
  260. /*8*/ I64(0xddd0467c64bce4c4),
  261. /*9*/ I64(0xc7caba6e7c5382ed),
  262. /*10*/ I64(0xb3f4e093db73a0b7),
  263. /*11*/ I64(0xa21727db38cb0053),
  264. /*12*/ I64(0x91ff83775423cc29),
  265. /*13*/ I64(0x8380dea93da4bc82),
  266. /*14*/ I64(0xece53cec4a314f00),
  267. /*15*/ I64(0xd5605fcdcf32e217),
  268. /*16*/ I64(0xc0314325637a1978),
  269. /*17*/ I64(0xad1c8eab5ee43ba2),
  270. /*18*/ I64(0x9becce62836ac5b0),
  271. /*19*/ I64(0x8c71dcd9ba0b495c),
  272. /*20*/ I64(0xfd00b89747823938),
  273. /*21*/ I64(0xe3e27a444d8d991a),
  274. };
  275.  
  276. static const INT16 rgexp64Power10By16[] = {
  277. // exponents for both powers of 10^16 and 0.1^16
  278. /*1*/ 54,
  279. /*2*/ 107,
  280. /*3*/ 160,
  281. /*4*/ 213,
  282. /*5*/ 266,
  283. /*6*/ 319,
  284. /*7*/ 373,
  285. /*8*/ 426,
  286. /*9*/ 479,
  287. /*10*/ 532,
  288. /*11*/ 585,
  289. /*12*/ 638,
  290. /*13*/ 691,
  291. /*14*/ 745,
  292. /*15*/ 798,
  293. /*16*/ 851,
  294. /*17*/ 904,
  295. /*18*/ 957,
  296. /*19*/ 1010,
  297. /*20*/ 1064,
  298. /*21*/ 1117,
  299. };
  300.  
  301. #ifdef _DEBUG
  302. //
  303. // slower high precision version of Mul64 for computation of the tables
  304. //
  305. static UINT64 Mul64Precise(UINT64 a, UINT64 b, INT* pexp)
  306. {
  307.     LEAF_CONTRACT
  308.  
  309.     UINT64 hilo =
  310.         ((Mul32x32To64(a >> 32, b) >> 1) +
  311.         (Mul32x32To64(a, b >> 32) >> 1) +
  312.         (Mul32x32To64(a, b) >> 33)) >> 30;
  313.  
  314.     UINT64 val = Mul32x32To64(a >> 32, b >> 32) + (hilo >> 1) + (hilo & 1);
  315.  
  316.     // normalize
  317.     if ((val & I64(0x8000000000000000)) == 0) { val <<= 1; *pexp -= 1; }
  318.  
  319.     return val;
  320. }
  321.  
  322. //
  323. // debug-only verification of the precomputed tables
  324. //
  325. static void CheckTable(UINT64 val, INT exp, LPCVOID table, int size, LPCSTR name, int tabletype)
  326. {
  327.     WRAPPER_CONTRACT
  328.  
  329.     UINT64 multval = val;
  330.     INT mulexp = exp;
  331.     bool fBad = false;
  332.     for (int i = 0; i < size; i++) {
  333.         switch (tabletype) {
  334.         case 1:
  335.             if (((UINT64*)table)[i] != val) {
  336.                 if (!fBad) {
  337.                     fprintf(stderr, "%s:\n", name);
  338.                     fBad = true;
  339.                 }
  340.                 fprintf(stderr, "/*%d*/ I64(0x%I64x),\n", i+1, val);
  341.             }
  342.             break;
  343.         case 2:
  344.             if (((INT8*)table)[i] != exp) {
  345.                 if (!fBad) {
  346.                     fprintf(stderr, "%s:\n", name);
  347.                     fBad = true;
  348.                 }
  349.                 fprintf(stderr, "/*%d*/ %d,\n", i+1, exp);
  350.             }
  351.             break;
  352.         case 3:
  353.             if (((INT16*)table)[i] != exp) {
  354.                 if (!fBad) {
  355.                     fprintf(stderr, "%s:\n", name);
  356.                     fBad = true;
  357.                 }
  358.                 fprintf(stderr, "/*%d*/ %d,\n", i+1, exp);
  359.             }
  360.             break;
  361.         default:
  362.             _ASSERTE(false);
  363.             break;
  364.         }
  365.  
  366.         exp += mulexp;
  367.         val = Mul64Precise(val, multval, &exp);
  368.     }
  369.     _ASSERTE(!fBad || !"NumberToDouble table not correct. Correct version dumped to stderr.");
  370. }
  371.  
  372. void CheckTables()
  373. {
  374.     WRAPPER_CONTRACT
  375.  
  376.     UINT64 val; INT exp;
  377.  
  378.     val = I64(0xa000000000000000); exp = 4; // 10
  379.     CheckTable(val, exp, rgval64Power10, 15, "rgval64Power10", 1);
  380.     CheckTable(val, exp, rgexp64Power10, 15, "rgexp64Power10", 2);
  381.  
  382.     val = I64(0x8e1bc9bf04000000); exp = 54; //10^16
  383.     CheckTable(val, exp, rgval64Power10By16, 21, "rgval64Power10By16", 1);
  384.     CheckTable(val, exp, rgexp64Power10By16, 21, "rgexp64Power10By16", 3);
  385.  
  386.     val = I64(0xCCCCCCCCCCCCCCCD); exp = -3; // 0.1
  387.     CheckTable(val, exp, rgval64Power10+15, 15, "rgval64Power10 - inv", 1);
  388.  
  389.     val = I64(0xe69594bec44de160); exp = -53; // 0.1^16
  390.     CheckTable(val, exp, rgval64Power10By16+21, 21, "rgval64Power10By16 - inv", 1);
  391. }
  392. #endif // _DEBUG
  393.  
  394. void NumberToDouble(NUMBER* number, double* value)
  395. {
  396.     WRAPPER_CONTRACT
  397.  
  398.     UINT64 val;
  399.     INT exp;
  400.     wchar* src = number->digits;
  401.     int remaining;
  402.     int total;
  403.     int count;
  404.     int scale;
  405.     int absscale;
  406.     int index;
  407.  
  408. #ifdef _DEBUG
  409.     static bool fCheckedTables = false;
  410.     if (!fCheckedTables) {
  411.         CheckTables();
  412.         fCheckedTables = true;
  413.     }
  414. #endif // _DEBUG
  415.  
  416.     total = (int)wcslen(src);
  417.     remaining = total;
  418.  
  419.     // skip the leading zeros
  420.     while (*src == '0') {
  421.         remaining--;
  422.         src++;
  423.     }
  424.  
  425.     if (remaining == 0) {
  426.         *value = 0;
  427.         goto done;
  428.     }
  429.  
  430.     count = min(remaining, 9);
  431.     remaining -= count;
  432.     val = DigitsToInt(src, count);
  433.  
  434.     if (remaining > 0) {
  435.         count = min(remaining, 9);
  436.         remaining -= count;
  437.  
  438.         // get the denormalized power of 10
  439.         UINT32 mult = (UINT32)(rgval64Power10[count-1] >> (64 - rgexp64Power10[count-1]));
  440.         val = Mul32x32To64(val, mult) + DigitsToInt(src+9, count);
  441.     }
  442.  
  443.     scale = number->scale - (total - remaining);
  444.     absscale = abs(scale);
  445.     if (absscale >= 22 * 16) {
  446.         // overflow / underflow
  447.         *(UINT64*)value = (scale > 0) ? I64(0x7FF0000000000000) : 0;
  448.         goto done;
  449.     }
  450.  
  451.     exp = 64;
  452.  
  453.     // normalize the mantisa
  454.     if ((val & I64(0xFFFFFFFF00000000)) == 0) { val <<= 32; exp -= 32; }
  455.     if ((val & I64(0xFFFF000000000000)) == 0) { val <<= 16; exp -= 16; }
  456.     if ((val & I64(0xFF00000000000000)) == 0) { val <<= 8; exp -= 8; }
  457.     if ((val & I64(0xF000000000000000)) == 0) { val <<= 4; exp -= 4; }
  458.     if ((val & I64(0xC000000000000000)) == 0) { val <<= 2; exp -= 2; }
  459.     if ((val & I64(0x8000000000000000)) == 0) { val <<= 1; exp -= 1; }
  460.  
  461.     index = absscale & 15;
  462.     if (index) {
  463.         INT multexp = rgexp64Power10[index-1];
  464.         // the exponents are shared between the inverted and regular table
  465.         exp += (scale < 0) ? (-multexp + 1) : multexp;
  466.  
  467.         UINT64 multval = rgval64Power10[index + ((scale < 0) ? 15 : 0) - 1];
  468.         val = Mul64Lossy(val, multval, &exp);
  469.     }
  470.  
  471.     index = absscale >> 4;
  472.     if (index) {
  473.         INT multexp = rgexp64Power10By16[index-1];
  474.         // the exponents are shared between the inverted and regular table
  475.         exp += (scale < 0) ? (-multexp + 1) : multexp;
  476.  
  477.         UINT64 multval = rgval64Power10By16[index + ((scale < 0) ? 21 : 0) - 1];
  478.         val = Mul64Lossy(val, multval, &exp);
  479.     }
  480.  
  481.     // round & scale down
  482.     if ((UINT32)val & (1 << 10))
  483.     {
  484.         // IEEE round to even
  485.         UINT64 tmp = val + ((1 << 10) - 1) + (((UINT32)val >> 11) & 1);
  486.         if (tmp < val) {
  487.             // overflow
  488.             tmp = (tmp >> 1) | I64(0x8000000000000000);
  489.             exp += 1;
  490.         }
  491.         val = tmp;
  492.     }
  493.     val >>= 11;
  494.  
  495.     exp += 0x3FE;
  496.  
  497.     if (exp <= 0) {
  498.         if (exp <= -52) {
  499.             // underflow
  500.             val = 0;
  501.         }
  502.         else {
  503.             // denormalized
  504.             val >>= (-exp+1);
  505.         }
  506.     }
  507.     else
  508.     if (exp >= 0x7FF) {
  509.         // overflow
  510.         val = I64(0x7FF0000000000000);
  511.     }
  512.     else {
  513.         val = ((UINT64)exp << 52) + (val & I64(0x000FFFFFFFFFFFFF));
  514.     }
  515.  
  516.     *(UINT64*)value = val;
  517.  
  518. done:
  519.     if (number->sign) *(UINT64*)value |= I64(0x8000000000000000);
  520. }
  521.  
  522. wchar_t* COMNumber::Int32ToDecChars(wchar_t* p, unsigned int value, int digits)
  523. {
  524.     LEAF_CONTRACT
  525.     _ASSERTE(p != NULL);
  526.  
  527.     while (--digits >= 0 || value != 0) {
  528.         *--p = value % 10 + '0';
  529.         value /= 10;
  530.     }
  531.     return p;
  532. }
  533.  
  534. unsigned int Int64DivMod1E9(unsigned __int64* value)
  535. {
  536.     LEAF_CONTRACT
  537.     _ASSERTE(value != NULL);
  538.  
  539.     unsigned int rem = (unsigned int)(*value % 1000000000);
  540.     *value /= 1000000000;
  541.     return rem;
  542. }
  543.  
  544.  
  545.  
  546.  
  547.  
  548. inline void AddStringRef(wchar** ppBuffer, STRINGREF strRef)
  549. {
  550.     WRAPPER_CONTRACT
  551.     _ASSERTE(ppBuffer != NULL && strRef != NULL);
  552.  
  553.     wchar* buffer = strRef->GetBuffer();
  554.     _ASSERTE(buffer != NULL);
  555.     DWORD length = strRef->GetStringLength();
  556.     for (wchar* str = buffer; str < buffer + length; (*ppBuffer)++, str++)
  557.     {
  558.         **ppBuffer = *str;
  559.     }
  560. }
  561.  
  562. LPCWSTR MatchChars(LPCWSTR p, LPCWSTR str)
  563. {
  564.     LEAF_CONTRACT
  565.     _ASSERTE(p != NULL && str != NULL);
  566.  
  567.     if (!*str) return 0;
  568.     for (; *str; p++, str++)
  569.     {
  570.         if (*p != *str) //We only hurt the failure case
  571.         {
  572.             if ((*str == 0xA0) && (*p == 0x20)) // This fix is for French or Kazakh cultures. Since a user cannot type 0xA0 as a
  573.                 // space character we use 0x20 space character instead to mean the same.
  574.                 continue;
  575.             return 0;
  576.         }
  577.     }
  578.     return p;
  579. }
  580.  
  581. wchar* Int32ToHexChars(wchar* p, unsigned int value, int hexBase, int digits)
  582. {
  583.     LEAF_CONTRACT
  584.     _ASSERTE(p != NULL);
  585.  
  586.     while (--digits >= 0 || value != 0) {
  587.         int digit = value & 0xF;
  588.         *--p = digit + (digit < 10? '0': hexBase);
  589.         value >>= 4;
  590.     }
  591.     return p;
  592. }
  593.  
  594. STRINGREF Int32ToDecStr(int value, int digits, STRINGREF sNegative)
  595. {
  596.     CONTRACTL {
  597.         THROWS;
  598.         INJECT_FAULT(COMPlusThrowOM());
  599.         GC_TRIGGERS;
  600.         MODE_COOPERATIVE;
  601.     } CONTRACTL_END;
  602.  
  603.     CQuickBytes buf;
  604.  
  605.     if (digits < 1) digits = 1;
  606.  
  607.     UINT maxDigitsLength = (digits > 15) ? digits : 15; // Since an int32 can have maximum of 10 chars as a String
  608.     UINT bufferLength = (maxDigitsLength > 100) ? maxDigitsLength : 100;
  609.     int negLength = 0;
  610.     wchar* src = NULL;
  611.  
  612.     if (value < 0) {
  613.         _ASSERTE(sNegative != NULL);
  614.         src = sNegative->GetBuffer();
  615.         _ASSERTE(src != NULL);
  616.         negLength = sNegative->GetStringLength();
  617.         if ((UINT) negLength > bufferLength - maxDigitsLength) {
  618.             bufferLength = (UINT) negLength + maxDigitsLength;
  619.         }
  620.     }
  621.  
  622.     wchar *buffer = (wchar*)buf.AllocThrows(bufferLength * sizeof(WCHAR));
  623.     wchar* p = COMNumber::Int32ToDecChars(buffer + bufferLength, value >= 0? value: -value, digits);
  624.     _ASSERTE(p != NULL);
  625.     if (value < 0) {
  626.         for (int i =negLength - 1; i >= 0; i--)
  627.         {
  628.             *(--p) = *(src+i);
  629.         }
  630.     }
  631.  
  632.     _ASSERTE(buffer + bufferLength - p >=0 && buffer <= p);
  633.     return COMString::NewString(p, (int)(buffer + bufferLength - p));
  634. }
  635.  
  636. STRINGREF UInt32ToDecStr(unsigned int value, int digits)
  637. {
  638.     WRAPPER_CONTRACT
  639.  
  640.     wchar buffer[100];
  641.     if (digits < 1) digits = 1;
  642.     wchar* p = COMNumber::Int32ToDecChars(buffer + 100, value, digits);
  643.     _ASSERTE(p != NULL && p >= buffer && p < (buffer + 100));
  644.     return COMString::NewString(p, (int) (buffer + 100 - p));
  645. }
  646.  
  647. STRINGREF Int32ToHexStr(unsigned int value, int hexBase, int digits)
  648. {
  649.     WRAPPER_CONTRACT
  650.  
  651.     wchar buffer[100];
  652.     if (digits < 1) digits = 1;
  653.     wchar* p = Int32ToHexChars(buffer + 100, value, hexBase, digits);
  654.     return COMString::NewString(p, (int) (buffer + 100 - p));
  655. }
  656.  
  657. void Int32ToNumber(int value, NUMBER* number)
  658. {
  659.     WRAPPER_CONTRACT
  660.     _ASSERTE(number != NULL);
  661.  
  662.     wchar buffer[INT32_PRECISION+1];
  663.     number->precision = INT32_PRECISION;
  664.     if (value >= 0) {
  665.         number->sign = 0;
  666.     }
  667.     else {
  668.         number->sign = 1;
  669.         value = -value;
  670.     }
  671.     wchar* p = COMNumber::Int32ToDecChars(buffer + INT32_PRECISION, value, 0);
  672.     _ASSERTE(p != NULL);
  673.     int i = (int) (buffer + INT32_PRECISION - p);
  674.     number->scale = i;
  675.     wchar* dst = number->digits;
  676.     _ASSERTE(dst != NULL);
  677.     while (--i >= 0) *dst++ = *p++;
  678.     *dst = 0;
  679. }
  680.  
  681. void UInt32ToNumber(unsigned int value, NUMBER* number)
  682. {
  683.     WRAPPER_CONTRACT
  684.     _ASSERTE(number != NULL);
  685.  
  686.     wchar buffer[UINT32_PRECISION+1];
  687.     number->precision = UINT32_PRECISION;
  688.     number->sign = 0;
  689.     wchar* p = COMNumber::Int32ToDecChars(buffer + UINT32_PRECISION, value, 0);
  690.     _ASSERT(p != NULL);
  691.     int i = (int) (buffer + UINT32_PRECISION - p);
  692.     number->scale = i;
  693.     wchar* dst = number->digits;
  694.     _ASSERT(dst != NULL);
  695.     while (--i >= 0) *dst++ = *p++;
  696.     *dst = 0;
  697. }
  698.  
  699.  
  700.  
  701.  
  702. #define LO32(x) ((unsigned int)(x))
  703. #define HI32(x) ((unsigned int)(((x) & UI64(0xFFFFFFFF00000000)) >> 32))
  704.  
  705. STRINGREF Int64ToDecStr(__int64 value, int digits, STRINGREF sNegative)
  706. {
  707.     CONTRACTL {
  708.         THROWS;
  709.         INJECT_FAULT(COMPlusThrowOM());
  710.         GC_TRIGGERS;
  711.         MODE_COOPERATIVE;
  712.     } CONTRACTL_END;
  713.  
  714.     CQuickBytes buf;
  715.  
  716.     if (digits < 1) digits = 1;
  717.     int sign = HI32(value);
  718.  
  719.     // digits as specified in the format string can be at most 99.
  720.     UINT maxDigitsLength = (digits > 20) ? digits : 20;
  721.     UINT bufferLength = (maxDigitsLength > 100) ? maxDigitsLength : 100;
  722.  
  723.     if (sign < 0) {
  724.         value = -value;
  725.         _ASSERTE(sNegative);
  726.         int negLength = sNegative->GetStringLength();
  727.         if ((UINT) negLength > bufferLength - maxDigitsLength) {
  728.             bufferLength = negLength + maxDigitsLength;
  729.         }
  730.     }
  731.  
  732.     wchar *buffer = (wchar*)buf.AllocThrows(bufferLength * sizeof(WCHAR));
  733.     wchar* p = buffer + bufferLength;
  734.     while (HI32(value)) {
  735.         p = COMNumber::Int32ToDecChars(p, Int64DivMod1E9((unsigned __int64*)&value), 9);
  736.         _ASSERTE(p != NULL);
  737.         digits -= 9;
  738.     }
  739.     p = COMNumber::Int32ToDecChars(p, LO32(value), digits);
  740.     _ASSERTE(p != NULL);
  741.     if (sign < 0) {
  742.         wchar* src = sNegative->GetBuffer();
  743.         _ASSERTE(src != NULL);
  744.         for (int i =sNegative->GetStringLength() - 1; i >= 0; i--)
  745.         {
  746.             *(--p) = *(src+i);
  747.         }
  748.     }
  749.     return COMString::NewString(p, (int) (buffer + bufferLength - p));
  750. }
  751.  
  752. STRINGREF UInt64ToDecStr(unsigned __int64 value, int digits)
  753. {
  754.     WRAPPER_CONTRACT
  755.  
  756.     wchar buffer[100];
  757.     if (digits < 1) digits = 1;
  758.     wchar* p = buffer + 100;
  759.     while (HI32(value)) {
  760.         p = COMNumber::Int32ToDecChars(p, Int64DivMod1E9(&value), 9);
  761.         _ASSERTE(p != NULL);
  762.         digits -= 9;
  763.     }
  764.     p = COMNumber::Int32ToDecChars(p, LO32(value), digits);
  765.     _ASSERTE(p != NULL && p >= buffer && p < (buffer + 100));
  766.     return COMString::NewString(p, (int) (buffer + 100 - p));
  767. }
  768.  
  769. STRINGREF Int64ToHexStr(unsigned __int64 value, int hexBase, int digits)
  770. {
  771.     WRAPPER_CONTRACT
  772.  
  773.     wchar buffer[100];
  774.     wchar* p;
  775.     if (HI32(value)) {
  776.         Int32ToHexChars(buffer + 100, LO32(value), hexBase, 8);
  777.         p = Int32ToHexChars(buffer + 100 - 8, HI32(value), hexBase, digits - 8);
  778.     }
  779.     else {
  780.         if (digits < 1) digits = 1;
  781.         p = Int32ToHexChars(buffer + 100, LO32(value), hexBase, digits);
  782.     }
  783.     _ASSERTE(p != NULL && p >= buffer && p < (buffer + 100));
  784.     return COMString::NewString(p, (int) (buffer + 100 - p));
  785. }
  786.  
  787. void Int64ToNumber(__int64 value, NUMBER* number)
  788. {
  789.     WRAPPER_CONTRACT
  790.  
  791.     wchar buffer[INT64_PRECISION+1];
  792.     number->precision = INT64_PRECISION;
  793.     if (value >= 0) {
  794.         number->sign = 0;
  795.     }
  796.     else {
  797.         number->sign = 1;
  798.         value = -value;
  799.     }
  800.     wchar* p = buffer + INT64_PRECISION;
  801.     while (HI32(value)) {
  802.         p = COMNumber::Int32ToDecChars(p, Int64DivMod1E9((unsigned __int64*)&value), 9);
  803.         _ASSERTE(p != NULL);
  804.     }
  805.     p = COMNumber::Int32ToDecChars(p, LO32(value), 0);
  806.     _ASSERTE(p != NULL);
  807.     int i = (int) (buffer + INT64_PRECISION - p);
  808.     number->scale = i;
  809.     wchar* dst = number->digits;
  810.     _ASSERTE(dst != NULL);
  811.     while (--i >= 0) *dst++ = *p++;
  812.     *dst = 0;
  813. }
  814.  
  815. void UInt64ToNumber(unsigned __int64 value, NUMBER* number)
  816. {
  817.     WRAPPER_CONTRACT
  818.  
  819.     wchar buffer[UINT64_PRECISION+1];
  820.     number->precision = UINT64_PRECISION;
  821.     number->sign = 0;
  822.     wchar* p = buffer + UINT64_PRECISION;
  823.     while (HI32(value)) {
  824.         p = COMNumber::Int32ToDecChars(p, Int64DivMod1E9(&value), 9);
  825.         _ASSERTE(p != NULL);
  826.     }
  827.     p = COMNumber::Int32ToDecChars(p, LO32(value), 0);
  828.     _ASSERTE(p != NULL);
  829.     int i = (int) (buffer + UINT64_PRECISION - p);
  830.     number->scale = i;
  831.     wchar* dst = number->digits;
  832.     _ASSERTE(dst != NULL);
  833.     while (--i >= 0) *dst++ = *p++;
  834.     *dst = 0;
  835. }
  836.  
  837.  
  838. void RoundNumber(NUMBER* number, int pos)
  839. {
  840.     LEAF_CONTRACT
  841.     _ASSERTE(number != NULL);
  842.  
  843.     int i = 0;
  844.     while (i < pos && number->digits[i] != 0) i++;
  845.     if (i == pos && number->digits[i] >= '5') {
  846.         while (i > 0 && number->digits[i - 1] == '9') i--;
  847.         if (i > 0) {
  848.             number->digits[i - 1]++;
  849.         }
  850.         else {
  851.             number->scale++;
  852.             number->digits[0] = '1';
  853.             i = 1;
  854.         }
  855.     }
  856.     else {
  857.         while (i > 0 && number->digits[i - 1] == '0') i--;
  858.     }
  859.     if (i == 0) {
  860.         number->scale = 0;
  861.         number->sign = 0;
  862.     }
  863.     number->digits[i] = 0;
  864. }
  865.  
  866. wchar ParseFormatSpecifier(STRINGREF str, int* digits)
  867. {
  868.     WRAPPER_CONTRACT
  869.     _ASSERTE(digits != NULL);
  870.  
  871.     if (str != 0) {
  872.         wchar* p = str->GetBuffer();
  873.         _ASSERTE(p != NULL);
  874.         wchar ch = *p;
  875.         if (ch != 0) {
  876.             if (ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z') {
  877.                 p++;
  878.                 int n = -1;
  879.                 if (*p >= '0' && *p <= '9') {
  880.                     n = *p++ - '0';
  881.                     while (*p >= '0' && *p <= '9') {
  882.                         n = n * 10 + *p++ - '0';
  883.                         if (n >= 10) break;
  884.                     }
  885.                 }
  886.                 if (*p == 0) {
  887.                     *digits = n;
  888.                     return ch;
  889.                 }
  890.             }
  891.             return 0;
  892.         }
  893.     }
  894.     *digits = -1;
  895.     return 'G';
  896. }
  897.  
  898. wchar* FormatExponent(wchar* buffer, int value, wchar expChar,
  899.     STRINGREF posSignStr, STRINGREF negSignStr, int minDigits)
  900. {
  901.     WRAPPER_CONTRACT
  902.     _ASSERTE(buffer != NULL);
  903.  
  904.     wchar digits[11];
  905.     *buffer++ = expChar;
  906.     if (value < 0) {
  907.         _ASSERTE(negSignStr != NULL);
  908.         AddStringRef(&buffer, negSignStr);
  909.         value = -value;
  910.     }
  911.     else {
  912.         if (posSignStr!= NULL) {
  913.             AddStringRef(&buffer, posSignStr);
  914.         }
  915.     }
  916.     wchar* p = COMNumber::Int32ToDecChars(digits + 10, value, minDigits);
  917.     _ASSERTE(p != NULL);
  918.     int i = (int) (digits + 10 - p);
  919.     while (--i >= 0) *buffer++ = *p++;
  920.     return buffer;
  921. }
  922.  
  923. wchar* FormatGeneral(wchar* buffer, NUMBER* number, int digits, wchar expChar,
  924.     NUMFMTREF numfmt, BOOL bSuppressScientific = FALSE)
  925. {
  926.         WRAPPER_CONTRACT
  927.         _ASSERTE(number != NULL);
  928.         _ASSERTE(buffer != NULL);
  929.         _ASSERTE(numfmt != NULL);
  930.  
  931.     int digPos = number->scale;
  932.     int scientific = 0;
  933.     if (!bSuppressScientific) { // Don't switch to scientific notation
  934.         if (digPos > digits || digPos < -3) {
  935.             digPos = 1;
  936.             scientific = 1;
  937.         }
  938.     }
  939.     wchar* dig = number->digits;
  940.     _ASSERT(dig != NULL);
  941.     if (digPos > 0) {
  942.         do {
  943.             *buffer++ = *dig != 0? *dig++: '0';
  944.         } while (--digPos > 0);
  945.     }
  946.     else {
  947.         *buffer++ = '0';
  948.     }
  949.     if (*dig != 0 || digPos < 0) {
  950.         AddStringRef(&buffer, numfmt->sNumberDecimal);
  951.         while (digPos < 0) {
  952.             *buffer++ = '0';
  953.             digPos++;
  954.         }
  955.         while (*dig != 0) {
  956.             *buffer++ = *dig++;
  957.         }
  958.     }
  959.     if (scientific) buffer = FormatExponent(buffer, number->scale - 1, expChar, numfmt->sPositive, numfmt->sNegative, 2);
  960.     return buffer;
  961. }
  962.  
  963. wchar* FormatScientific(wchar* buffer, NUMBER* number, int digits, wchar expChar,
  964.     NUMFMTREF numfmt)
  965. {
  966.         WRAPPER_CONTRACT
  967.         _ASSERTE(number != NULL);
  968.         _ASSERTE(buffer != NULL);
  969.         _ASSERTE(numfmt != NULL);
  970.  
  971.     wchar* dig = number->digits;
  972.     _ASSERTE(dig != NULL);
  973.     *buffer++ = *dig != 0? *dig++: '0';
  974.     if (digits != 1) // For E0 we would like to suppress the decimal point
  975.         AddStringRef(&buffer, numfmt->sNumberDecimal);
  976.     while (--digits > 0) *buffer++ = *dig != 0? *dig++: '0';
  977.     int e = number->digits[0] == 0? 0: number->scale - 1;
  978.     buffer = FormatExponent(buffer, e, expChar, numfmt->sPositive, numfmt->sNegative, 3);
  979.     _ASSERTE(buffer != NULL);
  980.     return buffer;
  981. }
  982.  
  983. wchar* FormatFixed(wchar* buffer, NUMBER* number, int digits,
  984.     I4ARRAYREF groupDigitsRef, STRINGREF sDecimal, STRINGREF sGroup)
  985. {
  986.     CONTRACTL {
  987.         THROWS;
  988.         INJECT_FAULT(COMPlusThrowOM());
  989.         GC_TRIGGERS;
  990.         MODE_COOPERATIVE;
  991.         PRECONDITION(CheckPointer(buffer));
  992.         PRECONDITION(CheckPointer(number));
  993.     } CONTRACTL_END;
  994.  
  995.     int digPos = number->scale;
  996.     wchar* dig = number->digits;
  997.     const I4* groupDigits = NULL;
  998.     if (groupDigitsRef != NULL) {
  999.         groupDigits = groupDigitsRef->GetDirectConstPointerToNonObjectElements();
  1000.     }
  1001.  
  1002.     if (digPos > 0) {
  1003.         if (groupDigits != NULL) {
  1004.  
  1005.             int groupSizeIndex = 0;     // index into the groupDigits array.
  1006.             int groupSizeCount = groupDigits[groupSizeIndex];   // the current total of group size.
  1007.             int groupSizeLen   = groupDigitsRef->GetNumComponents();    // the length of groupDigits array.
  1008.             int bufferSize     = digPos;                        // the length of the result buffer string.
  1009.             int groupSeparatorLen = sGroup->GetStringLength();  // the length of the group separator string.
  1010.             int groupSize = 0;                                      // the current group size.
  1011.  
  1012.             //
  1013.             // Find out the size of the string buffer for the result.
  1014.             //
  1015.             if (groupSizeLen != 0) // You can pass in 0 length arrays
  1016.             {
  1017.                 while (digPos > groupSizeCount) {
  1018.                     groupSize = groupDigits[groupSizeIndex];
  1019.                     if (groupSize == 0) {
  1020.                         break;
  1021.                     }
  1022.  
  1023.                     bufferSize += groupSeparatorLen;
  1024.                     if (groupSizeIndex < groupSizeLen - 1) {
  1025.                         groupSizeIndex++;
  1026.                     }
  1027.                     groupSizeCount += groupDigits[groupSizeIndex];
  1028.                     if (groupSizeCount < 0 || bufferSize < 0) {
  1029.                         COMPlusThrow(kArgumentOutOfRangeException); // if we overflow
  1030.                     }
  1031.                 }
  1032.                 if (groupSizeCount == 0) // If you passed in an array with one entry as 0, groupSizeCount == 0
  1033.                     groupSize = 0;
  1034.                 else
  1035.                     groupSize = groupDigits[0];
  1036.             }
  1037.  
  1038.             groupSizeIndex = 0;
  1039.             int digitCount = 0;
  1040.             int digStart;
  1041.             int digLength = (int)wcslen(dig);
  1042.             digStart = (digPos<digLength)?digPos:digLength;
  1043.             wchar* p = buffer + bufferSize - 1;
  1044.             for (int i = digPos - 1; i >=0; i--) {
  1045.                 *(p--) = (i<digStart)?dig[i]:'0';
  1046.  
  1047.                 if (groupSize > 0) {
  1048.                     digitCount++;
  1049.                     if (digitCount == groupSize && i != 0) {
  1050.                         for (int j = groupSeparatorLen - 1; j >=0; j--) {
  1051.                             *(p--) = sGroup->GetBuffer()[j];
  1052.                         }
  1053.  
  1054.                         if (groupSizeIndex < groupSizeLen - 1) {
  1055.                             groupSizeIndex++;
  1056.                             groupSize = groupDigits[groupSizeIndex];
  1057.                         }
  1058.                         digitCount = 0;
  1059.                     }
  1060.                 }
  1061.             }
  1062.             if (p < buffer - 1) {
  1063.                 // This indicates a buffer underflow since we write in backwards.
  1064.                 DoJITFailFast();
  1065.             }
  1066.             buffer += bufferSize;
  1067.             dig += digStart;
  1068.         } else {
  1069.             do {
  1070.                 *buffer++ = *dig != 0? *dig++: '0';
  1071.             } while (--digPos > 0);
  1072.         }
  1073.     }
  1074.     else {
  1075.         *buffer++ = '0';
  1076.     }
  1077.     if (digits > 0) {
  1078.         AddStringRef(&buffer, sDecimal);
  1079.         while (digPos < 0 && digits > 0) {
  1080.             *buffer++ = '0';
  1081.             digPos++;
  1082.             digits--;
  1083.         }
  1084.         while (digits > 0) {
  1085.             *buffer++ = *dig != 0? *dig++: '0';
  1086.             digits--;
  1087.         }
  1088.     }
  1089.     return buffer;
  1090. }
  1091.  
  1092. wchar* FormatNumber(wchar* buffer, NUMBER* number, int digits, NUMFMTREF numfmt)
  1093. {
  1094.     CONTRACTL {
  1095.         MODE_COOPERATIVE;
  1096.         THROWS;
  1097.         GC_TRIGGERS;
  1098.         PRECONDITION(CheckPointer(buffer));
  1099.         PRECONDITION(CheckPointer(number));
  1100.     } CONTRACTL_END;
  1101.  
  1102.     char ch;
  1103.     const char* fmt;
  1104.     fmt = number->sign?
  1105.         negNumberFormats[numfmt->cNegativeNumberFormat]:
  1106.     posNumberFormat;
  1107.  
  1108.     while ((ch = *fmt++) != 0) {
  1109.         switch (ch) {
  1110.         case '#':
  1111.             buffer = FormatFixed(buffer, number, digits,
  1112.                 numfmt->cNumberGroup,
  1113.                 numfmt->sNumberDecimal, numfmt->sNumberGroup);
  1114.             break;
  1115.         case '-':
  1116.             AddStringRef(&buffer, numfmt->sNegative);
  1117.             break;
  1118.         default:
  1119.             *buffer++ = ch;
  1120.         }
  1121.     }
  1122.     return buffer;
  1123.  
  1124. }
  1125.  
  1126. wchar* FormatCurrency(wchar* buffer, NUMBER* number, int digits, NUMFMTREF numfmt)
  1127. {
  1128.     CONTRACTL {
  1129.         MODE_COOPERATIVE;
  1130.         THROWS;
  1131.         GC_TRIGGERS;
  1132.         PRECONDITION(CheckPointer(buffer));
  1133.         PRECONDITION(CheckPointer(number));
  1134.     } CONTRACTL_END;
  1135.  
  1136.     char ch;
  1137.     const char* fmt;
  1138.     fmt = number->sign?
  1139.         negCurrencyFormats[numfmt->cNegCurrencyFormat]:
  1140.     posCurrencyFormats[numfmt->cPosCurrencyFormat];
  1141.  
  1142.     while ((ch = *fmt++) != 0) {
  1143.         switch (ch) {
  1144.         case '#':
  1145.             buffer = FormatFixed(buffer, number, digits,
  1146.                 numfmt->cCurrencyGroup,
  1147.                 numfmt->sCurrencyDecimal, numfmt->sCurrencyGroup);
  1148.             break;
  1149.         case '-':
  1150.             AddStringRef(&buffer, numfmt->sNegative);
  1151.             break;
  1152.         case '$':
  1153.             AddStringRef(&buffer, numfmt->sCurrency);
  1154.             break;
  1155.         default:
  1156.             *buffer++ = ch;
  1157.         }
  1158.     }
  1159.     return buffer;
  1160. }
  1161.  
  1162. wchar* FormatPercent(wchar* buffer, NUMBER* number, int digits, NUMFMTREF numfmt)
  1163. {
  1164.     CONTRACTL {
  1165.         MODE_COOPERATIVE;
  1166.         THROWS;
  1167.         GC_TRIGGERS;
  1168.         PRECONDITION(CheckPointer(buffer));
  1169.         PRECONDITION(CheckPointer(number));
  1170.     } CONTRACTL_END;
  1171.  
  1172.     char ch;
  1173.     const char* fmt;
  1174.     fmt = number->sign?
  1175.         negPercentFormats[numfmt->cNegativePercentFormat]:
  1176.     posPercentFormats[numfmt->cPositivePercentFormat];
  1177.  
  1178.     while ((ch = *fmt++) != 0) {
  1179.         switch (ch) {
  1180.         case '#':
  1181.             buffer = FormatFixed(buffer, number, digits,
  1182.                 numfmt->cPercentGroup,
  1183.                 numfmt->sPercentDecimal, numfmt->sPercentGroup);
  1184.             break;
  1185.         case '-':
  1186.             AddStringRef(&buffer, numfmt->sNegative);
  1187.             break;
  1188.         case '%':
  1189.             AddStringRef(&buffer, numfmt->sPercent);
  1190.             break;
  1191.         default:
  1192.             *buffer++ = ch;
  1193.         }
  1194.     }
  1195.     return buffer;
  1196. }
  1197.  
  1198. STRINGREF NumberToString(NUMBER* number, wchar format, int digits, NUMFMTREF numfmt, BOOL bDecimal = FALSE )
  1199. {
  1200.         CONTRACTL {
  1201.         THROWS;
  1202.         INJECT_FAULT(COMPlusThrowOM());
  1203.         GC_TRIGGERS;
  1204.         MODE_COOPERATIVE;
  1205.         PRECONDITION(CheckPointer(number));
  1206.     } CONTRACTL_END;
  1207.  
  1208.  
  1209.     // Do the worst case calculation
  1210.     /* US English - for Double.MinValue.ToString("C99"); we require 514 characters
  1211.     ----------
  1212.     2 paranthesis
  1213.     1 currency character
  1214.     308 characters
  1215.     103 group seperators
  1216.     1 decimal separator
  1217.     99 0's
  1218.  
  1219.         digPos + 99 + 6(slack) => digPos + 105
  1220.         C
  1221.         sNegative
  1222.         sCurrencyGroup
  1223.         sCurrencyDecimal
  1224.         sCurrency
  1225.         F
  1226.         sNegative
  1227.         sNumberDecimal
  1228.         N
  1229.         sNegative
  1230.         sNumberDecimal
  1231.         sNumberGroup
  1232.         E
  1233.         sNegative
  1234.         sPositive
  1235.         sNegative (for exponent)
  1236.         sPositive
  1237.         sNumberDecimal
  1238.         G
  1239.         sNegative
  1240.         sPositive
  1241.         sNegative (for exponent)
  1242.         sPositive
  1243.         sNumberDecimal
  1244.         P (+2 for some spaces)
  1245.         sNegative
  1246.         sPercentGroup
  1247.         sPercentDecimal
  1248.         sPercent
  1249.     */
  1250.  
  1251.     _ASSERTE(numfmt != NULL);
  1252.     INT64 newBufferLen = MIN_BUFFER_SIZE;
  1253.  
  1254.     CQuickBytesSpecifySize<LARGE_BUFFER_SIZE * sizeof(WCHAR)> buf;
  1255.  
  1256.     wchar *buffer = NULL;
  1257.     wchar* dst = NULL;
  1258.     wchar ftype = format & 0xFFDF;
  1259.     int digCount = 0;
  1260.  
  1261.     switch (ftype) {
  1262.     case 'C':
  1263.         if (digits < 0) digits = numfmt->cCurrencyDecimals;
  1264.         if (number->scale < 0)
  1265.             digCount = 0;
  1266.         else
  1267.             digCount = number->scale + digits;
  1268.  
  1269.         newBufferLen += digCount;
  1270.         newBufferLen += numfmt->sNegative->GetStringLength(); // For number and exponent
  1271.         newBufferLen += ((INT64)numfmt->sCurrencyGroup->GetStringLength() * digCount); // For all the grouping sizes
  1272.         newBufferLen += numfmt->sCurrencyDecimal->GetStringLength();
  1273.         newBufferLen += numfmt->sCurrency->GetStringLength();
  1274.  
  1275.         _ASSERTE(newBufferLen >= MIN_BUFFER_SIZE);
  1276.         if (newBufferLen > INT32_MAX) {
  1277.             COMPlusThrowOM();
  1278.         }
  1279.         newBufferLen = newBufferLen * sizeof(WCHAR);
  1280.         dst = buffer = (WCHAR*)buf.AllocThrows(newBufferLen);
  1281.  
  1282.         RoundNumber(number, number->scale + digits); // Don't change this line to use digPos since digCount could have its sign changed.
  1283.         dst = FormatCurrency(dst, number, digits, numfmt);
  1284.         break;
  1285.     case 'F':
  1286.         if (digits < 0) digits = numfmt->cNumberDecimals;
  1287.  
  1288.         if (number->scale < 0)
  1289.             digCount = 0;
  1290.         else
  1291.             digCount = number->scale + digits;
  1292.  
  1293.  
  1294.         newBufferLen += digCount;
  1295.         newBufferLen += numfmt->sNegative->GetStringLength(); // For number and exponent
  1296.         newBufferLen += numfmt->sNumberDecimal->GetStringLength();
  1297.  
  1298.         _ASSERTE(newBufferLen >= MIN_BUFFER_SIZE);
  1299.         if (newBufferLen > INT32_MAX) {
  1300.             COMPlusThrowOM();
  1301.         }
  1302.         newBufferLen = newBufferLen * sizeof(WCHAR);
  1303.         dst = buffer = (WCHAR*)buf.AllocThrows(newBufferLen);
  1304.  
  1305.         RoundNumber(number, number->scale + digits);
  1306.         if (number->sign) {
  1307.             AddStringRef(&dst, numfmt->sNegative);
  1308.         }
  1309.         dst = FormatFixed(dst, number, digits,
  1310.             NULL,
  1311.             numfmt->sNumberDecimal, NULL);
  1312.         break;
  1313.     case 'N':
  1314.         if (digits < 0) digits = numfmt->cNumberDecimals; // Since we are using digits in our calculation
  1315.  
  1316.         if (number->scale < 0)
  1317.             digCount = 0;
  1318.         else
  1319.             digCount = number->scale + digits;
  1320.  
  1321.  
  1322.         newBufferLen += digCount;
  1323.         newBufferLen += numfmt->sNegative->GetStringLength(); // For number and exponent
  1324.         newBufferLen += ((INT64)numfmt->sNumberGroup->GetStringLength()) * digCount; // For all the grouping sizes
  1325.         newBufferLen += numfmt->sNumberDecimal->GetStringLength();
  1326.  
  1327.         _ASSERTE(newBufferLen >= MIN_BUFFER_SIZE);
  1328.         if (newBufferLen > INT32_MAX) {
  1329.             COMPlusThrowOM();
  1330.         }
  1331.         newBufferLen = newBufferLen * sizeof(WCHAR);
  1332.         dst = buffer = (WCHAR*)buf.AllocThrows(newBufferLen);
  1333.  
  1334.         RoundNumber(number, number->scale + digits);
  1335.         dst = FormatNumber(dst, number, digits, numfmt);
  1336.         break;
  1337.     case 'E':
  1338.         if (digits < 0) digits = 6;
  1339.         digits++;
  1340.  
  1341.         newBufferLen += digits;
  1342.         newBufferLen += (((INT64)numfmt->sNegative->GetStringLength() + numfmt->sPositive->GetStringLength()) *2); // For number and exponent
  1343.         newBufferLen += numfmt->sNumberDecimal->GetStringLength();
  1344.  
  1345.         _ASSERTE(newBufferLen >= MIN_BUFFER_SIZE);
  1346.         if (newBufferLen > INT32_MAX) {
  1347.             COMPlusThrowOM();
  1348.         }
  1349.         newBufferLen = newBufferLen * sizeof(WCHAR);
  1350.         dst = buffer = (WCHAR*)buf.AllocThrows(newBufferLen);
  1351.  
  1352.         RoundNumber(number, digits);
  1353.         if (number->sign) {
  1354.             AddStringRef(&dst, numfmt->sNegative);
  1355.         }
  1356.         dst = FormatScientific(dst, number, digits, format, numfmt);
  1357.         break;
  1358.     case 'G':
  1359.         {
  1360.             bool enableRounding = true;
  1361.             if (digits < 1) {
  1362.                 if (bDecimal && (digits == -1)) { // Default to 29 digits precision only for G formatting without a precision specifier
  1363.                     digits = DECIMAL_PRECISION;
  1364.                     enableRounding = false;  // Turn off rounding for ECMA compliance to output trailing 0's after decimal as significant
  1365.                 }
  1366.                 else {
  1367.                     digits = number->precision;
  1368.                 }
  1369.             }
  1370.  
  1371.         newBufferLen += digits;
  1372.         newBufferLen += ((numfmt->sNegative->GetStringLength() + numfmt->sPositive->GetStringLength()) *2); // For number and exponent
  1373.         newBufferLen += numfmt->sNumberDecimal->GetStringLength();
  1374.  
  1375.         _ASSERTE(newBufferLen >= MIN_BUFFER_SIZE);
  1376.         if (newBufferLen > INT32_MAX) {
  1377.             COMPlusThrowOM();
  1378.         }
  1379.         newBufferLen = newBufferLen * sizeof(WCHAR);
  1380.         dst = buffer = (WCHAR*)buf.AllocThrows(newBufferLen);
  1381.  
  1382.             if (enableRounding) // Don't round for G formatting without precision
  1383.                 RoundNumber(number, digits); // This also fixes up the minus zero case
  1384.             else {
  1385.                 if (bDecimal && (number->digits[0] == 0)) { // Minus zero should be formatted as 0
  1386.                     number->sign = 0;
  1387.                 }
  1388.             }
  1389.         if (number->sign) {
  1390.             AddStringRef(&dst, numfmt->sNegative);
  1391.         }
  1392.             dst = FormatGeneral(dst, number, digits, format - ('G' - 'E'), numfmt, !enableRounding);
  1393.         }
  1394.         break;
  1395.     case 'P':
  1396.         if (digits < 0) digits = numfmt->cPercentDecimals;
  1397.         number->scale += 2;
  1398.  
  1399.         if (number->scale < 0)
  1400.             digCount = 0;
  1401.         else
  1402.             digCount = number->scale + digits;
  1403.  
  1404.  
  1405.         newBufferLen += digCount;
  1406.         newBufferLen += numfmt->sNegative->GetStringLength(); // For number and exponent
  1407.         newBufferLen += ((INT64)numfmt->sPercentGroup->GetStringLength()) * digCount; // For all the grouping sizes
  1408.         newBufferLen += numfmt->sPercentDecimal->GetStringLength();
  1409.         newBufferLen += numfmt->sPercent->GetStringLength();
  1410.  
  1411.         _ASSERTE(newBufferLen >= MIN_BUFFER_SIZE);
  1412.         if (newBufferLen > INT32_MAX) {
  1413.             COMPlusThrowOM();
  1414.         }
  1415.         newBufferLen = newBufferLen * sizeof(WCHAR);
  1416.         dst = buffer = (WCHAR*)buf.AllocThrows(newBufferLen);
  1417.  
  1418.         RoundNumber(number, number->scale + digits);
  1419.         dst = FormatPercent(dst, number, digits, numfmt);
  1420.         break;
  1421.     default:
  1422.         COMPlusThrow(kFormatException, L"Format_BadFormatSpecifier");
  1423.     }
  1424.     if (!((dst - buffer >= 0) && (dst - buffer) <= newBufferLen)) {
  1425.         DoJITFailFast();
  1426.     }
  1427.     return COMString::NewString(buffer, (int) (dst - buffer));
  1428. }
  1429.  
  1430. LPCWSTR FindSection(LPCWSTR format, int section)
  1431. {
  1432.     LEAF_CONTRACT
  1433.     _ASSERTE(format != NULL);
  1434.  
  1435.     LPCWSTR src;
  1436.     wchar ch;
  1437.     if (section == 0) return format;
  1438.     src = format;
  1439.     for (;;) {
  1440.         switch (ch = *src++) {
  1441.         case '\'':
  1442.         case '"':
  1443.             while (*src != 0 && *src++ != ch);
  1444.             break;
  1445.         case '\\':
  1446.             if (*src != 0) src++;
  1447.             break;
  1448.         case ';':
  1449.             if (--section != 0) break;
  1450.             if (*src != 0 && *src != ';') return src;
  1451.         case 0:
  1452.             return format;
  1453.         }
  1454.     }
  1455. }
  1456.  
  1457. STRINGREF NumberToStringFormat(NUMBER* number, STRINGREF str, NUMFMTREF numfmt)
  1458. {
  1459.     CONTRACTL {
  1460.         THROWS;
  1461.         INJECT_FAULT(COMPlusThrowOM());
  1462.         GC_TRIGGERS;
  1463.         MODE_COOPERATIVE;
  1464.     } CONTRACTL_END;
  1465.  
  1466.     int digitCount;
  1467.     int decimalPos;
  1468.     int firstDigit;
  1469.     int lastDigit;
  1470.     int digPos;
  1471.     int scientific;
  1472.     int percent;
  1473.     int permille;
  1474.     int thousandPos;
  1475.     int thousandCount = 0;
  1476.     int thousandSeps;
  1477.     int scaleAdjust;
  1478.     int adjust;
  1479.     wchar* format=NULL;
  1480.     LPCWSTR section=NULL;
  1481.     LPCWSTR src=NULL;
  1482.     wchar* dst=NULL;
  1483.     wchar* dig=NULL;
  1484.     wchar ch;
  1485.     wchar* buffer=NULL;
  1486.     CQuickBytes buf;
  1487.  
  1488.     _ASSERTE(str != NULL);
  1489.     _ASSERTE(numfmt != NULL);
  1490.  
  1491.     format = str->GetBuffer();
  1492.  
  1493.     section = FindSection(format, number->digits[0] == 0? 2: number->sign? 1: 0);
  1494.  
  1495. ParseSection:
  1496.     digitCount = 0;
  1497.     decimalPos = -1;
  1498.     firstDigit = 0x7FFFFFFF;
  1499.     lastDigit = 0;
  1500.     scientific = 0;
  1501.     percent = 0;
  1502.     permille = 0;
  1503.     thousandPos = -1;
  1504.     thousandSeps = 0;
  1505.     scaleAdjust = 0;
  1506.     src = section;
  1507.     _ASSERTE(src != NULL);
  1508.     while ((ch = *src++) != 0 && ch != ';') {
  1509.         switch (ch) {
  1510.         case '#':
  1511.             digitCount++;
  1512.             break;
  1513.         case '0':
  1514.             if (firstDigit == 0x7FFFFFFF) firstDigit = digitCount;
  1515.             digitCount++;
  1516.             lastDigit = digitCount;
  1517.             break;
  1518.         case '.':
  1519.             if (decimalPos < 0) {
  1520.                 decimalPos = digitCount;
  1521.             }
  1522.             break;
  1523.         case ',':
  1524.             if (digitCount > 0 && decimalPos < 0) {
  1525.                 if (thousandPos >= 0) {
  1526.                     if (thousandPos == digitCount) {
  1527.                         thousandCount++;
  1528.                         break;
  1529.                     }
  1530.                     thousandSeps = 1;
  1531.                 }
  1532.                 thousandPos = digitCount;
  1533.                 thousandCount = 1;
  1534.             }
  1535.             break;
  1536.         case '%':
  1537.             percent++;
  1538.             scaleAdjust += 2;
  1539.             break;
  1540.         case 0x2030:
  1541.             permille++;
  1542.             scaleAdjust += 3;
  1543.             break;
  1544.         case '\'':
  1545.         case '"':
  1546.             while (*src != 0 && *src++ != ch);
  1547.             break;
  1548.         case '\\':
  1549.             if (*src != 0) src++;
  1550.             break;
  1551.         case 'E':
  1552.         case 'e':
  1553.             if (*src=='0' || ((*src == '+' || *src == '-') && src[1] == '0')) {
  1554.                 while (*++src == '0');
  1555.                 scientific = 1;
  1556.             }
  1557.             break;
  1558.         }
  1559.     }
  1560.  
  1561.     if (decimalPos < 0) decimalPos = digitCount;
  1562.     if (thousandPos >= 0) {
  1563.         if (thousandPos == decimalPos) {
  1564.             scaleAdjust -= thousandCount * 3;
  1565.         }
  1566.         else {
  1567.             thousandSeps = 1;
  1568.         }
  1569.     }
  1570.     if (number->digits[0] != 0) {
  1571.         number->scale += scaleAdjust;
  1572.         int pos = scientific? digitCount: number->scale + digitCount - decimalPos;
  1573.         RoundNumber(number, pos);
  1574.         if (number->digits[0] == 0) {
  1575.             src = FindSection(format, 2);
  1576.             if (src != section) {
  1577.                 section = src;
  1578.                 goto ParseSection;
  1579.             }
  1580.         }
  1581.     } else {
  1582.         number->sign = 0; // We need to format -0 without the sign set.
  1583.         number->scale = 0; // Decimals with scale ('0.00') should be rounded.
  1584.     }
  1585.  
  1586.     firstDigit = firstDigit < decimalPos? decimalPos - firstDigit: 0;
  1587.     lastDigit = lastDigit > decimalPos? decimalPos - lastDigit: 0;
  1588.     if (scientific) {
  1589.         digPos = decimalPos;
  1590.         adjust = 0;
  1591.     }
  1592.     else {
  1593.         digPos = number->scale > decimalPos? number->scale: decimalPos;
  1594.         adjust = number->scale - decimalPos;
  1595.     }
  1596.     src = section;
  1597.     dig = number->digits;
  1598.  
  1599.     // Find maximum number of characters that the destination string can grow by
  1600.     // in the following while loop.  Use this to avoid buffer overflows.
  1601.     // Longest strings are potentially +/- signs with 10 digit exponents,
  1602.     // or decimal numbers, or the while loops copying from a quote or a \ onwards.
  1603.     // Check for positive and negative
  1604.     UINT64 maxStrIncLen = 0; // We need this to be UINT64 since the percent computation could go beyond a UINT.
  1605.     if (number->sign) {
  1606.         maxStrIncLen = numfmt->sNegative->GetStringLength();
  1607.     }
  1608.     else {
  1609.         maxStrIncLen = numfmt->sPositive->GetStringLength();
  1610.     }
  1611.  
  1612.     // Add for any big decimal seperator
  1613.     maxStrIncLen += numfmt->sNumberDecimal->GetStringLength();
  1614.  
  1615.     // Add for scientific
  1616.     if (scientific) {
  1617.         int inc1 = numfmt->sPositive->GetStringLength();
  1618.         int inc2 = numfmt->sNegative->GetStringLength();
  1619.         maxStrIncLen +=(inc1>inc2)?inc1:inc2;
  1620.     }
  1621.  
  1622.     // Add for percent separator
  1623.     if (percent) {
  1624.         maxStrIncLen += ((INT64)numfmt->sPercent->GetStringLength()) * percent;
  1625.     }
  1626.  
  1627.     // Add for permilli separator
  1628.     if (permille) {
  1629.         maxStrIncLen += ((INT64)numfmt->sPerMille->GetStringLength()) * permille;
  1630.     }
  1631.  
  1632.     //adjust can be negative, so we make this an int instead of an unsigned int.
  1633.     // adjust represents the number of characters over the formatting eg. format string is "0000" and you are trying to
  1634.     // format 100000 (6 digits). Means adjust will be 2. On the other hand if you are trying to format 10 adjust will be
  1635.     // -2 and we'll need to fixup these digits with 0 padding if we have 0 formatting as in this example.
  1636.     INT64 adjustLen=(adjust>0)?adjust:0; // We need to add space for these extra characters anyway.
  1637.     CQuickBytes thousands;
  1638.     INT32 bufferLen2 = 125;
  1639.     INT32 *thousandsSepPos = NULL;
  1640.     INT32 thousandsSepCtr = -1;
  1641.  
  1642.     if (thousandSeps) { // Fixup possible buffer overrun problems
  1643.         // We need to precompute this outside the number formatting loop
  1644.         if(numfmt->cNumberGroup->GetNumComponents() == 0) {
  1645.             thousandSeps = 0; // Nothing to add
  1646.         }
  1647.         else {
  1648.             thousandsSepPos = (INT32 *)thousands.AllocThrows(bufferLen2 * sizeof(INT32));
  1649.         //                        - We need this array to figure out where to insert the thousands seperator. We would have to traverse the string
  1650.             // backwords. PIC formatting always traverses forwards. These indices are precomputed to tell us where to insert
  1651.             // the thousands seperator so we can get away with traversing forwards. Note we only have to compute upto digPos.
  1652.             // The max is not bound since you can have formatting strings of the form "000,000..", and this
  1653.             // should handle that case too.
  1654.  
  1655.             const I4* groupDigits = numfmt->cNumberGroup->GetDirectConstPointerToNonObjectElements();
  1656.             _ASSERTE(groupDigits != NULL);
  1657.  
  1658.             int groupSizeIndex = 0;     // index into the groupDigits array.
  1659.             INT64 groupTotalSizeCount = 0;
  1660.             int groupSizeLen   = numfmt->cNumberGroup->GetNumComponents();    // the length of groupDigits array.
  1661.             if (groupSizeLen != 0)
  1662.                 groupTotalSizeCount = groupDigits[groupSizeIndex];   // the current running total of group size.
  1663.             int groupSize = groupTotalSizeCount;
  1664.  
  1665.             int totalDigits = digPos + ((adjust < 0)?adjust:0); // actual number of digits in o/p
  1666.             int numDigits = (firstDigit > totalDigits) ? firstDigit : totalDigits;
  1667.             while (numDigits > groupTotalSizeCount) {
  1668.                 if (groupSize == 0)
  1669.                     break;
  1670.                 thousandsSepPos[++thousandsSepCtr] = groupTotalSizeCount;
  1671.                 if (groupSizeIndex < groupSizeLen - 1) {
  1672.                     groupSizeIndex++;
  1673.                     groupSize = groupDigits[groupSizeIndex];
  1674.                 }
  1675.                 groupTotalSizeCount += groupSize;
  1676.                 if (bufferLen2 - thousandsSepCtr < 10) { // Slack of 10
  1677.                     bufferLen2 *= 2;
  1678.                     thousands.ReSizeThrows(bufferLen2*sizeof(INT32)); // memcopied by CQuickBytes automatically
  1679.                     thousandsSepPos = (INT32 *)thousands.Ptr();
  1680.                 }
  1681.             }
  1682.  
  1683.             // We already have computed the number of separators above. Simply add space for them.
  1684.             adjustLen += ( (thousandsSepCtr + 1) * ((INT64)numfmt->sNumberGroup->GetStringLength()));
  1685.         }
  1686.     }
  1687.  
  1688.     maxStrIncLen += adjustLen;
  1689.  
  1690.     // Allocate temp buffer - gotta deal with Schertz' 500 MB strings.
  1691.     // Some computations like when you specify Int32.MaxValue-2 %'s and each percent is setup to be Int32.MaxValue in length
  1692.     // will generate a result that will be larget than an unsigned int can hold. This is to protect against overflow.
  1693.     UINT64 tempLen = str->GetStringLength() + maxStrIncLen + 10;  // Include a healthy amount of temp space.
  1694.     if (tempLen > 0x7FFFFFFF)
  1695.         COMPlusThrowOM(); // if we overflow
  1696.  
  1697.     unsigned int bufferLen = (UINT)tempLen;
  1698.     if (bufferLen < 250) // Stay under 512 bytes
  1699.         bufferLen = 250; // This is to prevent unneccessary calls to resize
  1700.     buffer = (wchar *) buf.AllocThrows(bufferLen* sizeof(WCHAR));
  1701.     dst = buffer;
  1702.  
  1703.  
  1704.     if (number->sign && section == format) {
  1705.         AddStringRef(&dst, numfmt->sNegative);
  1706.     }
  1707.  
  1708.     BOOL decimalWritten = FALSE;
  1709.  
  1710.     while ((ch = *src++) != 0 && ch != ';') {
  1711.         // Make sure temp buffer is big enough, else resize it.
  1712.         if (bufferLen - (unsigned int)(dst-buffer) < 10) {
  1713.             int offset = dst - buffer;
  1714.             bufferLen *= 2;
  1715.             buf.ReSizeThrows(bufferLen*sizeof(WCHAR));
  1716.             buffer = (wchar*)buf.Ptr(); // memcopied by QuickBytes automatically
  1717.             dst = buffer + offset;
  1718.         }
  1719.  
  1720.         if (adjust > 0) {
  1721.             switch (ch) {
  1722.             case '#':
  1723.             case '0':
  1724.             case '.':
  1725.                 while (adjust > 0) { // digPos will be one greater than thousandsSepPos[thousandsSepCtr] since we are at
  1726.                     // the character after which the groupSeparator needs to be appended.
  1727.                     *dst++ = *dig != 0? *dig++: '0';
  1728.                     if (thousandSeps && digPos > 1 && thousandsSepCtr>=0) {
  1729.                         if (digPos == thousandsSepPos[thousandsSepCtr] + 1)  {
  1730.                             AddStringRef(&dst, numfmt->sNumberGroup);
  1731.                             thousandsSepCtr--;
  1732.                         }
  1733.                     }
  1734.                     digPos--;
  1735.                     adjust--;
  1736.                 }
  1737.             }
  1738.         }
  1739.  
  1740.         switch (ch) {
  1741.         case '#':
  1742.         case '0':
  1743.             {
  1744.                 if (adjust < 0) {
  1745.                     adjust++;
  1746.                     ch = digPos <= firstDigit? '0': 0;
  1747.                 }
  1748.                 else {
  1749.                     ch = *dig != 0? *dig++: digPos > lastDigit? '0': 0;
  1750.                 }
  1751.                 if (ch != 0) {
  1752.                     *dst++ = ch;
  1753.                     if (thousandSeps && digPos > 1 && thousandsSepCtr>=0) {
  1754.                         if (digPos == thousandsSepPos[thousandsSepCtr] + 1) {
  1755.                             AddStringRef(&dst, numfmt->sNumberGroup);
  1756.                             thousandsSepCtr--;
  1757.                         }
  1758.                     }
  1759.                 }
  1760.  
  1761.                 digPos--;
  1762.                 break;
  1763.             }
  1764.         case '.':
  1765.             {
  1766.                 if (digPos != 0 || decimalWritten) {
  1767.                     // For compatability, don't echo repeated decimals
  1768.                     break;
  1769.                 }
  1770.                 // If the format has trailing zeros or the format has a decimal and digits remain
  1771.                 if (lastDigit < 0
  1772.                     || (decimalPos < digitCount && *dig != 0)) {
  1773.                     AddStringRef(&dst, numfmt->sNumberDecimal);
  1774.                     decimalWritten = TRUE;
  1775.                 }
  1776.                 break;
  1777.             }
  1778.         case 0x2030:
  1779.             AddStringRef(&dst, numfmt->sPerMille);
  1780.             break;
  1781.         case '%':
  1782.             AddStringRef(&dst, numfmt->sPercent);
  1783.             break;
  1784.         case ',':
  1785.             break;
  1786.         case '\'':
  1787.         case '"':
  1788.             // Buffer overflow possibility
  1789.             while (*src != 0 && *src != ch) {
  1790.                 *dst++ = *src++;
  1791.                 if ((unsigned int)(dst-buffer) == bufferLen-1) {
  1792.                     if (bufferLen - (unsigned int)(dst-buffer) < maxStrIncLen) {
  1793.                         int offset = dst - buffer;
  1794.                         bufferLen *= 2;
  1795.                         buf.ReSizeThrows(bufferLen*sizeof(WCHAR)); // memcopied by CQuickBytes automatically
  1796.                         buffer = (wchar *)buf.Ptr();
  1797.                         dst = buffer + offset;
  1798.                     }
  1799.                 }
  1800.             }
  1801.             if (*src != 0) src++;
  1802.             break;
  1803.         case '\\':
  1804.             if (*src != 0) *dst++ = *src++;
  1805.             break;
  1806.         case 'E':
  1807.         case 'e':
  1808.             {
  1809.                 STRINGREF sign = NULL;
  1810.                 int i = 0;
  1811.                 if (scientific) {
  1812.                     if (*src=='0') {
  1813.                         //Handles E0, which should format the same as E-0
  1814.                         i++;
  1815.                     } else if (*src == '+' && src[1] == '0') {
  1816.                         //Handles E+0
  1817.                         sign = numfmt->sPositive;
  1818.                     } else if (*src == '-' && src[1] == '0') {
  1819.                         //Handles E-0
  1820.                         //Do nothing, this is just a place holder s.t. we don't break out of the loop.
  1821.                     } else {
  1822.                         *dst++ = ch;
  1823.                         break;
  1824.                     }
  1825.                     while (*++src == '0') i++;
  1826.                     if (i > 10) i = 10;
  1827.                     int exp = number->digits[0] == 0? 0: number->scale - decimalPos;
  1828.                     dst = FormatExponent(dst, exp, ch, sign, numfmt->sNegative, i);
  1829.                     scientific = 0;
  1830.                 }
  1831.                 else
  1832.                 {
  1833.                     *dst++ = ch; // Copy E or e to output
  1834.                     if (*src== '+' || *src == '-') {
  1835.                         *dst++ = *src++;
  1836.                     }
  1837.                     while (*src == '0') {
  1838.                         *dst++ = *src++;
  1839.                     }
  1840.                 }
  1841.                 break;
  1842.             }
  1843.         default:
  1844.             *dst++ = ch;
  1845.         }
  1846.     }
  1847.     if (!((dst - buffer >= 0) && (dst - buffer <= (int)bufferLen))) {
  1848.         DoJITFailFast();
  1849.     }
  1850.     STRINGREF newStr = COMString::NewString(buffer, (int)(dst - buffer));
  1851.     return newStr;
  1852. }
  1853.  
  1854. FCIMPL3_VII(Object*, COMNumber::FormatDecimal, DECIMAL value, StringObject* formatUNSAFE, NumberFormatInfo* numfmtUNSAFE)
  1855. {
  1856.     CONTRACTL
  1857.     {
  1858.         MODE_COOPERATIVE;
  1859.         DISABLED(GC_TRIGGERS);  // can't use this in an FCALL because we're in forbid gc mode until we setup a H_M_F.
  1860.         THROWS;
  1861.         SO_TOLERANT;       
  1862.     }
  1863.     CONTRACTL_END;
  1864.  
  1865.     NUMBER number;
  1866.  
  1867.     wchar fmt;
  1868.     int digits;
  1869.  
  1870.     STRINGREF  refRetVal = NULL;
  1871.     HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_1(Frame::FRAME_ATTR_RETURNOBJ, refRetVal);
  1872.  
  1873.     struct _gc
  1874.     {
  1875.         STRINGREF   format;
  1876.         NUMFMTREF   numfmt;
  1877.     } gc;
  1878.  
  1879.     gc.format = (STRINGREF) formatUNSAFE;
  1880.     gc.numfmt = (NUMFMTREF) numfmtUNSAFE;
  1881.  
  1882.     if (gc.numfmt == 0)
  1883.         COMPlusThrowArgumentNull(L"NumberFormatInfo");
  1884.  
  1885.     COMDecimal::DecimalToNumber(&value, &number);
  1886.  
  1887.     fmt = ParseFormatSpecifier(gc.format, &digits);
  1888.     if (fmt != 0) {
  1889.         refRetVal = NumberToString(&number, fmt, digits, gc.numfmt, TRUE);
  1890.     } else {
  1891.         refRetVal = NumberToStringFormat(&number, gc.format, gc.numfmt);
  1892.     }
  1893.  
  1894.     HELPER_METHOD_FRAME_END();
  1895.  
  1896.     return OBJECTREFToObject(refRetVal);
  1897. }
  1898. FCIMPLEND
  1899.  
  1900. FCIMPL3_VII(Object*, COMNumber::FormatDouble, double value, StringObject* formatUNSAFE, NumberFormatInfo* numfmtUNSAFE)
  1901. {
  1902.     CONTRACTL
  1903.     {
  1904.         MODE_COOPERATIVE;
  1905.         DISABLED(GC_TRIGGERS);  // can't use this in an FCALL because we're in forbid gc mode until we setup a H_M_F.
  1906.         THROWS;
  1907.         SO_TOLERANT;
  1908.     }
  1909.     CONTRACTL_END;
  1910.  
  1911.     NUMBER number;
  1912.     int digits;
  1913.     double dTest;
  1914.  
  1915.     struct _gc
  1916.     {
  1917.         STRINGREF   format;
  1918.         NUMFMTREF   numfmt;
  1919.         STRINGREF   refRetVal;
  1920.     } gc;
  1921.  
  1922.     gc.format = (STRINGREF) formatUNSAFE;
  1923.     gc.numfmt = (NUMFMTREF) numfmtUNSAFE;
  1924.     gc.refRetVal = NULL;
  1925.  
  1926.     HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_PROTECT(Frame::FRAME_ATTR_RETURNOBJ, gc);
  1927.  
  1928.     if (gc.numfmt == 0) COMPlusThrowArgumentNull(L"NumberFormatInfo");
  1929.     wchar fmt = ParseFormatSpecifier(gc.format, &digits);
  1930.     wchar val = (fmt & 0xFFDF);
  1931.     int precision = DOUBLE_PRECISION;
  1932.     switch (val) {
  1933.     case 'R':
  1934.         //In order to give numbers that are both friendly to display and round-trippable,
  1935.         //we parse the number using 15 digits and then determine if it round trips to the same
  1936.         //value.  If it does, we convert that NUMBER to a string, otherwise we reparse using 17 digits
  1937.         //and display that.
  1938.  
  1939.         DoubleToNumber(value, DOUBLE_PRECISION, &number);
  1940.  
  1941.         if (number.scale == (int) SCALE_NAN) {
  1942.             gc.refRetVal = gc.numfmt->sNaN;
  1943.             goto lExit;
  1944.         }
  1945.  
  1946.         if (number.scale == SCALE_INF) {
  1947.             gc.refRetVal = (number.sign? gc.numfmt->sNegativeInfinity: gc.numfmt->sPositiveInfinity);
  1948.             goto lExit;
  1949.         }
  1950.  
  1951.         NumberToDouble(&number, &dTest);
  1952.  
  1953.         if (dTest == value) {
  1954.             gc.refRetVal = NumberToString(&number, 'G', DOUBLE_PRECISION, gc.numfmt);
  1955.             goto lExit;
  1956.         }
  1957.  
  1958.         DoubleToNumber(value, 17, &number);
  1959.         gc.refRetVal = NumberToString(&number, 'G', 17, gc.numfmt);
  1960.         goto lExit;
  1961.         break;
  1962.  
  1963.     case 'E':
  1964.         // Here we round values less than E14 to 15 digits
  1965.         if (digits > 14) {
  1966.             precision = 17;
  1967.         }
  1968.         break;
  1969.  
  1970.     case 'G':
  1971.         // Here we round values less than G15 to 15 digits, G16 and G17 will not be touched
  1972.         if (digits > 15) {
  1973.             precision = 17;
  1974.         }
  1975.         break;
  1976.  
  1977.     }
  1978.  
  1979.     DoubleToNumber(value, precision, &number);
  1980.  
  1981.     if (number.scale == (int) SCALE_NAN) {
  1982.         gc.refRetVal = gc.numfmt->sNaN;
  1983.         goto lExit;
  1984.     }
  1985.  
  1986.     if (number.scale == SCALE_INF) {
  1987.         gc.refRetVal = (number.sign? gc.numfmt->sNegativeInfinity: gc.numfmt->sPositiveInfinity);
  1988.         goto lExit;
  1989.     }
  1990.  
  1991.     if (fmt != 0) {
  1992.         gc.refRetVal = NumberToString( &number, fmt, digits, gc.numfmt);
  1993.     }
  1994.     else {
  1995.         gc.refRetVal = NumberToStringFormat( &number, gc.format, gc.numfmt);
  1996.     }
  1997.  
  1998. lExit: ;
  1999.     HELPER_METHOD_FRAME_END();
  2000.  
  2001.     return OBJECTREFToObject(gc.refRetVal);
  2002. }
  2003. FCIMPLEND
  2004.  
  2005. //This function and the function pointer which we use to access are a really
  2006. //nasty hack to prevent VC7 from optimizing away our cast from double to float.
  2007. //We need this narrowing operation to verify whether or not we successfully round-tripped
  2008. //the single value.                                                                        
  2009.  
  2010. static void CvtToFloat(double val, volatile float* fltPtr)
  2011. {
  2012.     LEAF_CONTRACT;
  2013.     STATIC_CONTRACT_SO_TOLERANT;   
  2014.  
  2015.     *fltPtr = (float)val;
  2016. }
  2017.  
  2018. void (*CvtToFloatPtr)(double val, volatile float* fltPtr) = CvtToFloat;
  2019.  
  2020. FCIMPL3_VII(Object*, COMNumber::FormatSingle, float value, StringObject* formatUNSAFE, NumberFormatInfo* numfmtUNSAFE)
  2021. {
  2022.     CONTRACTL
  2023.     {
  2024.         MODE_COOPERATIVE;
  2025.         DISABLED(GC_TRIGGERS);  // can't use this in an FCALL because we're in forbid gc mode until we setup a H_M_F.
  2026.         THROWS;
  2027.         SO_TOLERANT;       
  2028.     }
  2029.     CONTRACTL_END;
  2030.  
  2031.     NUMBER number;
  2032.     int digits;
  2033.     double dTest;
  2034.     double argsValue = value;
  2035.  
  2036.     struct _gc
  2037.     {
  2038.         STRINGREF   format;
  2039.         NUMFMTREF   numfmt;
  2040.         STRINGREF   refRetVal;
  2041.     } gc;
  2042.  
  2043.     gc.format = (STRINGREF) formatUNSAFE;
  2044.     gc.numfmt = (NUMFMTREF) numfmtUNSAFE;
  2045.     gc.refRetVal = NULL;
  2046.  
  2047.     HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_PROTECT(Frame::FRAME_ATTR_RETURNOBJ, gc);
  2048.  
  2049.     if (gc.numfmt == 0) COMPlusThrowArgumentNull(L"NumberFormatInfo");
  2050.     wchar fmt = ParseFormatSpecifier(gc.format, &digits);
  2051.     wchar val = fmt & 0xFFDF;
  2052.     int precision = FLOAT_PRECISION;
  2053.     switch (val) {
  2054.     case 'R':
  2055.         //In order to give numbers that are both friendly to display and round-trippable,
  2056.         //we parse the number using 7 digits and then determine if it round trips to the same
  2057.         //value.  If it does, we convert that NUMBER to a string, otherwise we reparse using 9 digits
  2058.         //and display that.
  2059.  
  2060.         DoubleToNumber(argsValue, FLOAT_PRECISION, &number);
  2061.  
  2062.             if (number.scale == (int) SCALE_NAN) {
  2063.                 gc.refRetVal = gc.numfmt->sNaN;
  2064.                 goto lExit;
  2065.         }
  2066.         if (number.scale == SCALE_INF) {
  2067.                 gc.refRetVal = (number.sign? gc.numfmt->sNegativeInfinity: gc.numfmt->sPositiveInfinity);
  2068.                 goto lExit;
  2069.         }
  2070.  
  2071.         NumberToDouble(&number, &dTest);
  2072.  
  2073.         volatile float fTest;
  2074.  
  2075.         (*CvtToFloatPtr)(dTest, &fTest);
  2076.  
  2077.             if (fTest == value) {
  2078.                 gc.refRetVal = NumberToString(&number, 'G', FLOAT_PRECISION, gc.numfmt);
  2079.                 goto lExit;
  2080.         }
  2081.  
  2082.         DoubleToNumber(argsValue, 9, &number);
  2083.             gc.refRetVal = NumberToString(&number, 'G', 9, gc.numfmt);
  2084.             goto lExit;
  2085.         break;
  2086.     case 'E':
  2087.         // Here we round values less than E14 to 15 digits
  2088.         if (digits > 6) {
  2089.             precision = 9;
  2090.         }
  2091.         break;
  2092.  
  2093.  
  2094.     case 'G':
  2095.         // Here we round values less than G15 to 15 digits, G16 and G17 will not be touched
  2096.         if (digits > 7) {
  2097.             precision = 9;
  2098.         }
  2099.         break;
  2100.  
  2101.     }
  2102.  
  2103.     DoubleToNumber(value, precision, &number);
  2104.  
  2105.     if (number.scale == (int) SCALE_NAN) {
  2106.         gc.refRetVal = gc.numfmt->sNaN;
  2107.         goto lExit;
  2108.     }
  2109.  
  2110.     if (number.scale == SCALE_INF) {
  2111.         gc.refRetVal = (number.sign? gc.numfmt->sNegativeInfinity: gc.numfmt->sPositiveInfinity);
  2112.         goto lExit;
  2113.     }
  2114.  
  2115.     if (fmt != 0) {
  2116.         gc.refRetVal = NumberToString( &number, fmt, digits, gc.numfmt);
  2117.     }
  2118.     else {
  2119.         gc.refRetVal = NumberToStringFormat( &number, gc.format, gc.numfmt);
  2120.     }
  2121.  
  2122. lExit: ;
  2123.     HELPER_METHOD_FRAME_END();
  2124.  
  2125.     return OBJECTREFToObject(gc.refRetVal);
  2126. }
  2127. FCIMPLEND
  2128.  
  2129. FCIMPL3(Object*, COMNumber::FormatInt32, INT32 value, StringObject* formatUNSAFE, NumberFormatInfo* numfmtUNSAFE)
  2130. {
  2131.     CONTRACTL
  2132.     {
  2133.         MODE_COOPERATIVE;
  2134.         DISABLED(GC_TRIGGERS);  // can't use this in an FCALL because we're in forbid gc mode until we setup a H_M_F.
  2135.         THROWS;
  2136.         SO_TOLERANT;
  2137.     }
  2138.     CONTRACTL_END;
  2139.  
  2140.     wchar fmt;
  2141.     int digits;
  2142.  
  2143.     struct _gc
  2144.     {
  2145.         STRINGREF   refFormat;
  2146.         NUMFMTREF   refNumFmt;
  2147.         STRINGREF   refRetString;
  2148.     } gc;
  2149.  
  2150.     gc.refFormat    = (STRINGREF)formatUNSAFE;
  2151.     gc.refNumFmt    = (NUMFMTREF)numfmtUNSAFE;
  2152.     gc.refRetString = NULL;
  2153.  
  2154.     HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_PROTECT(Frame::FRAME_ATTR_RETURNOBJ, gc);
  2155.  
  2156.  
  2157.     if (gc.refNumFmt == 0) COMPlusThrowArgumentNull(L"NumberFormatInfo");
  2158.     fmt = ParseFormatSpecifier(gc.refFormat, &digits);
  2159.  
  2160.     //ANDing fmt with FFDF has the effect of uppercasing the character because
  2161.     //we've removed the bit that marks lower-case.
  2162.     switch (fmt & 0xFFDF) {
  2163.     case 'G':
  2164.         if (digits > 0)
  2165.         {
  2166.             NUMBER number;
  2167.             Int32ToNumber(value, &number);
  2168.             if (fmt != 0) {
  2169.                 gc.refRetString = NumberToString(&number, fmt, digits, gc.refNumFmt);
  2170.                 break;
  2171.             }
  2172.             gc.refRetString = NumberToStringFormat(&number, gc.refFormat, gc.refNumFmt);
  2173.             break;
  2174.         }
  2175.         // fall through
  2176.     case 'D':
  2177.         gc.refRetString = Int32ToDecStr(value, digits, gc.refNumFmt->sNegative);
  2178.         break;
  2179.     case 'X':
  2180.         gc.refRetString = Int32ToHexStr(value, fmt - ('X' - 'A' + 10), digits);
  2181.         break;
  2182.     default:
  2183.     NUMBER number;
  2184.     Int32ToNumber(value, &number);
  2185.     if (fmt != 0) {
  2186.       gc.refRetString = NumberToString(&number, fmt, digits, gc.refNumFmt);
  2187.       break;
  2188.     }
  2189.     gc.refRetString = NumberToStringFormat(&number, gc.refFormat, gc.refNumFmt);
  2190.     break;
  2191.  
  2192.     }
  2193.  
  2194.     HELPER_METHOD_FRAME_END();
  2195.  
  2196.     return OBJECTREFToObject(gc.refRetString);
  2197. }
  2198. FCIMPLEND
  2199.  
  2200. FCIMPL3(Object*, COMNumber::FormatUInt32, UINT32 value, StringObject* formatUNSAFE, NumberFormatInfo* numfmtUNSAFE)
  2201. {
  2202.     CONTRACTL
  2203.     {
  2204.         MODE_COOPERATIVE;
  2205.         DISABLED(GC_TRIGGERS);  // can't use this in an FCALL because we're in forbid gc mode until we setup a H_M_F.
  2206.         THROWS;
  2207.         SO_TOLERANT;       
  2208.     }
  2209.     CONTRACTL_END;
  2210.  
  2211.     wchar fmt;
  2212.     int digits;
  2213.  
  2214.     struct _gc
  2215.     {
  2216.         STRINGREF   refFormat;
  2217.         NUMFMTREF   refNumFmt;
  2218.         STRINGREF   refRetString;
  2219.     } gc;
  2220.  
  2221.     gc.refFormat    = (STRINGREF)formatUNSAFE;
  2222.     gc.refNumFmt    = (NUMFMTREF)numfmtUNSAFE;
  2223.     gc.refRetString = NULL;
  2224.  
  2225.     HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_PROTECT(Frame::FRAME_ATTR_RETURNOBJ, gc);
  2226.  
  2227.  
  2228.     if (gc.refNumFmt == 0) COMPlusThrowArgumentNull(L"NumberFormatInfo");
  2229.     fmt = ParseFormatSpecifier(gc.refFormat, &digits);
  2230.     switch (fmt & 0xFFDF)
  2231.     {
  2232.     case 'G':
  2233.         if (digits > 0)
  2234.         {
  2235.             NUMBER number;
  2236.             UInt32ToNumber(value, &number);
  2237.             if (fmt != 0) {
  2238.                 gc.refRetString = NumberToString(&number, fmt, digits, gc.refNumFmt);
  2239.                 break;
  2240.             }
  2241.             gc.refRetString = NumberToStringFormat(&number, gc.refFormat, gc.refNumFmt);
  2242.             break;
  2243.         }
  2244.         // fall through
  2245.     case 'D':
  2246.         gc.refRetString = UInt32ToDecStr(value, digits);
  2247.         break;
  2248.     case 'X':
  2249.         gc.refRetString = Int32ToHexStr(value, fmt - ('X' - 'A' + 10), digits);
  2250.         break;
  2251.     default:
  2252.         NUMBER number;
  2253.         UInt32ToNumber(value, &number);
  2254.         if (fmt != 0) {
  2255.           gc.refRetString = NumberToString(&number, fmt, digits, gc.refNumFmt);
  2256.           break;
  2257.         }
  2258.         gc.refRetString = NumberToStringFormat(&number, gc.refFormat, gc.refNumFmt);
  2259.         break;
  2260.     }
  2261.  
  2262.     HELPER_METHOD_FRAME_END();
  2263.  
  2264.     return OBJECTREFToObject(gc.refRetString);
  2265. }
  2266. FCIMPLEND
  2267.  
  2268. FCIMPL3_VII(Object*, COMNumber::FormatInt64, INT64 value, StringObject* formatUNSAFE, NumberFormatInfo* numfmtUNSAFE)
  2269. {
  2270.     CONTRACTL
  2271.     {
  2272.         MODE_COOPERATIVE;
  2273.         DISABLED(GC_TRIGGERS);  // can't use this in an FCALL because we're in forbid gc mode until we setup a H_M_F.
  2274.         THROWS;
  2275.         SO_TOLERANT;       
  2276.     }
  2277.     CONTRACTL_END;
  2278.  
  2279.     wchar fmt;
  2280.     int digits;
  2281.  
  2282.     struct _gc
  2283.     {
  2284.         STRINGREF   refFormat;
  2285.         NUMFMTREF   refNumFmt;
  2286.         STRINGREF   refRetString;
  2287.     } gc;
  2288.  
  2289.     gc.refFormat    = ObjectToSTRINGREF(formatUNSAFE);
  2290.     gc.refNumFmt    = (NUMFMTREF)numfmtUNSAFE;
  2291.     gc.refRetString = NULL;
  2292.  
  2293.     HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_PROTECT(Frame::FRAME_ATTR_RETURNOBJ, gc);
  2294.  
  2295.  
  2296.     if (gc.refNumFmt == 0) COMPlusThrowArgumentNull(L"NumberFormatInfo");
  2297.     fmt = ParseFormatSpecifier(gc.refFormat, &digits);
  2298.     switch (fmt & 0xFFDF)
  2299.     {
  2300.         case 'G':
  2301.             if (digits > 0)
  2302.             {
  2303.                 NUMBER number;
  2304.                 Int64ToNumber(value, &number);
  2305.                 if (fmt != 0) {
  2306.                     gc.refRetString = NumberToString(&number, fmt, digits, gc.refNumFmt);
  2307.                     break;
  2308.                 }
  2309.                 gc.refRetString = NumberToStringFormat(&number, gc.refFormat, gc.refNumFmt);
  2310.                 break;
  2311.             }
  2312.             // fall through
  2313.         case 'D':
  2314.             gc.refRetString = Int64ToDecStr(value, digits, gc.refNumFmt->sNegative);
  2315.             break;
  2316.         case 'X':
  2317.             gc.refRetString = Int64ToHexStr(value, fmt - ('X' - 'A' + 10), digits);
  2318.             break;
  2319.         default:
  2320.             NUMBER number;
  2321.             Int64ToNumber(value, &number);
  2322.             if (fmt != 0) {
  2323.                 gc.refRetString = NumberToString(&number, fmt, digits, gc.refNumFmt);
  2324.                 break;
  2325.             }
  2326.             gc.refRetString = NumberToStringFormat(&number, gc.refFormat, gc.refNumFmt);
  2327.             break;
  2328.     }
  2329.     HELPER_METHOD_FRAME_END();
  2330.  
  2331.     return OBJECTREFToObject(gc.refRetString);
  2332. }
  2333. FCIMPLEND
  2334.  
  2335. FCIMPL3_VII(Object*, COMNumber::FormatUInt64, UINT64 value, StringObject* formatUNSAFE, NumberFormatInfo* numfmtUNSAFE)
  2336. {
  2337.     CONTRACTL
  2338.     {
  2339.         MODE_COOPERATIVE;
  2340.         DISABLED(GC_TRIGGERS);  // can't use this in an FCALL because we're in forbid gc mode until we setup a H_M_F.
  2341.         THROWS;
  2342.         SO_TOLERANT;       
  2343.     }
  2344.     CONTRACTL_END;
  2345.  
  2346.     wchar fmt;
  2347.     int digits;
  2348.  
  2349.     struct _gc
  2350.     {
  2351.         STRINGREF   refFormat;
  2352.         NUMFMTREF   refNumFmt;
  2353.         STRINGREF   refRetString;
  2354.     } gc;
  2355.  
  2356.     gc.refFormat    = ObjectToSTRINGREF(formatUNSAFE);
  2357.     gc.refNumFmt    = (NUMFMTREF)numfmtUNSAFE;
  2358.     gc.refRetString = NULL;
  2359.  
  2360.     HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_PROTECT(Frame::FRAME_ATTR_RETURNOBJ, gc);
  2361.  
  2362.     if (gc.refNumFmt == 0) COMPlusThrowArgumentNull(L"NumberFormatInfo");
  2363.     fmt = ParseFormatSpecifier(gc.refFormat, &digits);
  2364.     switch (fmt & 0xFFDF) {
  2365.         case 'G':
  2366.             if (digits > 0)
  2367.             {
  2368.                 NUMBER number;
  2369.                 UInt64ToNumber(value, &number);
  2370.                 if (fmt != 0) {
  2371.                     gc.refRetString = NumberToString(&number, fmt, digits, gc.refNumFmt);
  2372.                     break;
  2373.                 }
  2374.                 gc.refRetString = NumberToStringFormat(&number, gc.refFormat, gc.refNumFmt);
  2375.                 break;
  2376.             }
  2377.             // fall through
  2378.         case 'D':
  2379.             gc.refRetString = UInt64ToDecStr(value, digits);
  2380.             break;
  2381.         case 'X':
  2382.             gc.refRetString = Int64ToHexStr(value, fmt - ('X' - 'A' + 10), digits);
  2383.             break;
  2384.         default:
  2385.             NUMBER number;
  2386.             UInt64ToNumber(value, &number);
  2387.             if (fmt != 0) {
  2388.                 gc.refRetString = NumberToString(&number, fmt, digits, gc.refNumFmt);
  2389.                 break;
  2390.             }
  2391.             gc.refRetString = NumberToStringFormat(&number, gc.refFormat, gc.refNumFmt);
  2392.             break;
  2393.     }
  2394.  
  2395.     HELPER_METHOD_FRAME_END();
  2396.  
  2397.     return OBJECTREFToObject(gc.refRetString);
  2398. }
  2399. FCIMPLEND
  2400.  
  2401. FCIMPL2(FC_BOOL_RET, COMNumber::NumberBufferToDecimal, BYTE* number, DECIMAL* value)
  2402. {
  2403.     WRAPPER_CONTRACT;
  2404.     STATIC_CONTRACT_SO_TOLERANT;   
  2405.  
  2406.     FC_RETURN_BOOL(COMDecimal::NumberToDecimal((NUMBER *) number, value) != 0);
  2407. }
  2408. FCIMPLEND
  2409.  
  2410. FCIMPL2(FC_BOOL_RET, COMNumber::NumberBufferToDouble, BYTE* number, double* value)
  2411. {
  2412.     WRAPPER_CONTRACT;
  2413.     STATIC_CONTRACT_SO_TOLERANT;
  2414.  
  2415.     double d = 0;
  2416.     NumberToDouble((NUMBER*) number, &d);
  2417.     unsigned int e = ((FPDOUBLE*)&d)->exp;
  2418.     unsigned int fmntLow = ((FPDOUBLE*)&d)->mantLo;
  2419.     unsigned int fmntHigh = ((FPDOUBLE*)&d)->mantHi;
  2420.     if (e == 0x7FF) {
  2421.         FC_RETURN_BOOL(false);
  2422.     }
  2423.     if (e == 0 && fmntLow ==0 && fmntHigh == 0)  {
  2424.         d = 0;
  2425.     }
  2426.     *value = d;
  2427.     FC_RETURN_BOOL(true);
  2428. }
  2429. FCIMPLEND
  2430.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement