private static unsafe bool NumberBufferToDecimal(ref Number.NumberBuffer number, ref Decimal value) { Decimal d = new Decimal(); char *p = number.digits; int e = number.scale; if (*p == 0) { // To avoid risking an app-compat issue with pre 4.5 (where some app was illegally using Reflection to examine the internal scale bits), we'll only force // the scale to 0 if the scale was previously positive (previously, such cases were unparsable to a bug.) if (e > 0) { e = 0; } } else { if (e > DecimalPrecision) { return(false); } while (((e > 0) || ((*p != 0) && (e > -28))) && ((d.High < 0x19999999) || ((d.High == 0x19999999) && ((d.Mid < 0x99999999) || ((d.Mid == 0x99999999) && ((d.Low < 0x99999999) || ((d.Low == 0x99999999) && (*p <= '5')))))))) { Decimal.DecMul10(ref d); if (*p != 0) { Decimal.DecAddInt32(ref d, (uint)(*p++ - '0')); } e--; } if (*p++ >= '5') { bool round = true; if ((*(p - 1) == '5') && ((*(p - 2) % 2) == 0)) { // Check if previous digit is even, only if the when we are unsure whether hows to do // Banker's rounding. For digits > 5 we will be roundinp up anyway. int count = 20; // Look at the next 20 digits to check to round while ((*p == '0') && (count != 0)) { p++; count--; } if ((*p == '\0') || (count == 0)) { round = false;// Do nothing } } if (round) { Decimal.DecAddInt32(ref d, 1); if ((d.High | d.Mid | d.Low) == 0) { d.High = 0x19999999; d.Mid = 0x99999999; d.Low = 0x9999999A; e++; } } } } if (e > 0) { return(false); } if (e <= -DecimalPrecision) { // Parsing a large scale zero can give you more precision than fits in the decimal. // This should only happen for actual zeros or very small numbers that round to zero. d.High = 0; d.Low = 0; d.Mid = 0; d.Scale = DecimalPrecision - 1; } else { d.Scale = -e; } d.IsNegative = number.sign; value = d; return(true); }