[System.Net] Add support for .pac proxy config scripts on mac
[mono.git] / mcs / class / corlib / System / NumberFormatter.cs
1 //
2 // System.NumberFormatter.cs
3 //
4 // Author:
5 //   Kazuki Oikawa (kazuki@panicode.com)
6 //   Eyal Alaluf (eyala@mainsoft.com)
7 //
8 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
9 // Copyright (C) 2008 Mainsoft Co. (http://www.mainsoft.com)
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 // NumberFormatter is shared with Grasshopper and hence the #if TARGET_JVM for
32 // marking the use of unsafe code that is not supported in Grasshopper.
33 #if !TARGET_JVM
34 #define UNSAFE_TABLES
35 #endif
36
37 using System.Globalization;
38 using System.Text;
39 using System.Threading;
40 using System.Runtime.CompilerServices;
41
42 namespace System
43 {
44         internal sealed partial class NumberFormatter
45         {
46                 #region Static Fields
47
48                 const int DefaultExpPrecision = 6;
49                 const int HundredMillion = 100000000;
50                 const long SeventeenDigitsThreshold = 10000000000000000;
51                 const ulong ULongDivHundredMillion = UInt64.MaxValue / HundredMillion;
52                 const ulong ULongModHundredMillion = 1 + UInt64.MaxValue % HundredMillion;
53
54                 const int DoubleBitsExponentShift = 52;
55                 const int DoubleBitsExponentMask = 0x7ff;
56                 const long DoubleBitsMantissaMask = 0xfffffffffffff;
57                 const int DecimalBitsScaleMask = 0x1f0000;
58
59                 const int SingleDefPrecision = 7;
60                 const int DoubleDefPrecision = 15;
61                 const int Int8DefPrecision = 3;
62                 const int UInt8DefPrecision = 3;
63                 const int Int16DefPrecision = 5;
64                 const int UInt16DefPrecision = 5;
65                 const int Int32DefPrecision = 10;
66                 const int UInt32DefPrecision = 10;
67                 const int Int64DefPrecision = 19;
68                 const int UInt64DefPrecision = 20;
69                 const int DecimalDefPrecision = 100;
70                 const int TenPowersListLength = 19;
71
72                 const double MinRoundtripVal = -1.79769313486231E+308;
73                 const double MaxRoundtripVal = 1.79769313486231E+308;
74
75 #if UNSAFE_TABLES
76                 // The below arrays are taken from mono/metatdata/number-formatter.h
77
78                 private static readonly unsafe ulong* MantissaBitsTable;
79                 private static readonly unsafe int* TensExponentTable;
80                 private static readonly unsafe char* DigitLowerTable;
81                 private static readonly unsafe char* DigitUpperTable;
82                 private static readonly unsafe long* TenPowersList;
83
84                 // DecHexDigits s a translation table from a decimal number to its
85                 // digits hexadecimal representation (e.g. DecHexDigits [34] = 0x34).
86                 private static readonly unsafe int* DecHexDigits;
87
88                 [MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.InternalCall)]
89                 private unsafe static extern void GetFormatterTables (out ulong* MantissaBitsTable, out int* TensExponentTable,
90                                 out char* DigitLowerTable, out char* DigitUpperTable,
91                                 out long* TenPowersList, out int* DecHexDigits);
92
93                 unsafe static NumberFormatter()
94                 {
95                         GetFormatterTables (out MantissaBitsTable, out TensExponentTable,
96                                 out DigitLowerTable, out DigitUpperTable, out TenPowersList, out DecHexDigits);
97                 }
98
99                 unsafe
100 #endif
101                 static long GetTenPowerOf(int i)
102                 {
103                         return TenPowersList [i];
104                 }
105                 #endregion Static Fields
106
107                 #region Fields
108
109                 private NumberFormatInfo _nfi;
110
111                 //part of the private stringbuffer
112                 private char[] _cbuf;
113
114                 private bool _NaN;
115                 private bool _infinity;
116                 private bool _isCustomFormat;
117                 private bool _specifierIsUpper;
118                 private bool _positive;
119                 private char _specifier;
120                 private int _precision;
121                 private int _defPrecision;
122
123                 private int _digitsLen;
124                 private int _offset; // Represent the first digit offset.
125                 private int _decPointPos;
126
127                 // The following fields are a hexadeimal representation of the digits.
128                 // For instance _val = 0x234 represents the digits '2', '3', '4'.
129                 private uint _val1; // Digits 0 - 7.
130                 private uint _val2; // Digits 8 - 15.
131                 private uint _val3; // Digits 16 - 23.
132                 private uint _val4; // Digits 23 - 31. Only needed for decimals.
133
134                 #endregion Fields
135
136                 #region Constructor Helpers
137
138                 // Translate an unsigned int to hexadecimal digits.
139                 // i.e. 123456789 is represented by _val1 = 0x23456789 and _val2 = 0x1
140                 private void InitDecHexDigits (uint value)
141                 {
142                         if (value >= HundredMillion) {
143                                 int div1 = (int)(value / HundredMillion);
144                                 value -= HundredMillion * (uint)div1;
145                                 _val2 = FastToDecHex (div1);
146                         }
147                         _val1 = ToDecHex ((int)value);
148                 }
149
150                 // Translate an unsigned long to hexadecimal digits.
151                 private void InitDecHexDigits (ulong value)
152                 {
153                         if (value >= HundredMillion) {
154                                 long div1 = (long)(value / HundredMillion);
155                                 value -= HundredMillion * (ulong)div1;
156                                 if (div1 >= HundredMillion) {
157                                         int div2 = (int)(div1 / HundredMillion);
158                                         div1 = div1 - div2 * (long)HundredMillion;
159                                         _val3 = ToDecHex (div2);
160                                 }
161                                 if (div1 != 0)
162                                         _val2 = ToDecHex ((int)(div1));
163                         }
164                         if (value != 0)
165                                 _val1 = ToDecHex ((int)value);
166                 }
167
168                 // Translate a decimal integer to hexadecimal digits.
169                 // The decimal integer is 96 digits and its value is hi * 2^64 + lo.
170                 // is the lower 64 bits.
171                 private void InitDecHexDigits (uint hi, ulong lo)
172                 {
173                         if (hi == 0) {
174                                 InitDecHexDigits (lo); // Only the lower 64 bits matter.
175                                 return;
176                         }
177
178                         // Compute (hi, lo) = (hi , lo) / HundredMillion.
179                         uint divhi = hi / HundredMillion;
180                         ulong remhi = hi - divhi * HundredMillion;
181                         ulong divlo = lo / HundredMillion;
182                         ulong remlo = lo - divlo * HundredMillion + remhi * ULongModHundredMillion;
183                         hi = divhi;
184                         lo = divlo + remhi * ULongDivHundredMillion;
185                         divlo = remlo / HundredMillion;
186                         remlo -= divlo * HundredMillion;
187                         lo += divlo;
188                         _val1 = ToDecHex ((int)remlo);
189
190                         // Divide hi * 2 ^ 64 + lo by HundredMillion using the fact that
191                         // hi < HundredMillion.
192                         divlo = lo / HundredMillion;
193                         remlo = lo - divlo * HundredMillion;
194                         lo = divlo;
195                         if (hi != 0) {
196                                 lo += hi * ULongDivHundredMillion;
197                                 remlo += hi * ULongModHundredMillion;
198                                 divlo = remlo / HundredMillion;
199                                 lo += divlo;
200                                 remlo -= divlo * HundredMillion;
201                         }
202                         _val2 = ToDecHex ((int)remlo);
203
204                         // Now we are left with 64 bits store in lo.
205                         if (lo >= HundredMillion) {
206                                 divlo = lo / HundredMillion;
207                                 lo -= divlo * HundredMillion;
208                                 _val4 = ToDecHex ((int)divlo);
209                         }
210                         _val3 = ToDecHex ((int)lo);
211                 }
212
213                 // Helper to translate an int in the range 0 .. 9999 to its
214                 // Hexadecimal digits representation.
215 #if UNSAFE_TABLES
216                 unsafe
217 #endif
218                 private static uint FastToDecHex (int val)
219                 {
220                         if (val < 100)
221                                 return (uint)DecHexDigits [val];
222
223                         // Uses 2^19 (524288) to compute val / 100 for val < 10000.
224                         int v = (val * 5243) >> 19;
225                         return (uint)((DecHexDigits [v] << 8) | DecHexDigits [val - v * 100]);
226                 }
227
228                 // Helper to translate an int in the range 0 .. 99999999 to its
229                 // Hexadecimal digits representation.
230                 private static uint ToDecHex (int val)
231                 {
232                         uint res = 0;
233                         if (val >= 10000) {
234                                 int v = val / 10000;
235                                 val -= v * 10000;
236                                 res = FastToDecHex (v) << 16;
237                         }
238                         return res | FastToDecHex (val);
239                 }
240
241                 // Helper to count number of hexadecimal digits in a number.
242                 private static int FastDecHexLen (int val)
243                 {
244                         if (val < 0x100)
245                                 if (val < 0x10)
246                                         return 1;
247                                 else
248                                         return 2;
249                         else if (val < 0x1000)
250                                 return 3;
251                         else
252                                 return 4;
253                 }
254
255                 private static int DecHexLen (uint val)
256                 {
257                         if (val < 0x10000)
258                                 return FastDecHexLen ((int)val);
259                         return 4 + FastDecHexLen ((int)(val >> 16));
260                 }
261
262                 // Count number of hexadecimal digits stored in _val1 .. _val4.
263                 private int DecHexLen ()
264                 {
265                         if (_val4 != 0)
266                                 return DecHexLen (_val4) + 24;
267                         else if (_val3 != 0)
268                                 return DecHexLen (_val3) + 16;
269                         else if (_val2 != 0)
270                                 return DecHexLen (_val2) + 8;
271                         else if (_val1 != 0)
272                                 return DecHexLen (_val1);
273                         else
274                                 return 0;
275                 }
276
277                 // Helper to count the 10th scale (number of digits) in a number
278                 private static int ScaleOrder (long hi)
279                 {
280                         for (int i = TenPowersListLength - 1; i >= 0; i--)
281                                 if (hi >= GetTenPowerOf (i))
282                                         return i + 1;
283                         return 1;
284                 }
285
286                 // Compute the initial precision for rounding a floating number
287                 // according to the used format.
288                 int InitialFloatingPrecision ()
289                 {
290                         if (_specifier == 'R')
291                                 return _defPrecision + 2;
292                         if (_precision < _defPrecision)
293                                 return _defPrecision;
294                         if (_specifier == 'G')
295                                 return Math.Min (_defPrecision + 2, _precision);
296                         if (_specifier == 'E')
297                                 return Math.Min (_defPrecision + 2, _precision + 1);
298                         return _defPrecision;
299                 }
300
301                 // Parse the given format and extract the precision in it.
302                 // Returns -1 for empty formats and -2 to indicate that the format
303                 // is a custom format.
304                 private static int ParsePrecision (string format)
305                 {
306                         int precision = 0;
307                         for (int i = 1; i < format.Length; i++) {
308                                 int val = format [i] - '0';
309                                 precision = precision * 10 + val;
310                                 if (val < 0 || val > 9 || precision > 99)
311                                         return -2;
312                         }
313                         return precision;
314                 }
315
316                 #endregion Constructor Helpers
317
318                 #region Constructors
319
320                 // Parse the given format and initialize the following fields:
321                 //   _isCustomFormat, _specifierIsUpper, _specifier & _precision.
322                 public NumberFormatter (Thread current)
323                 {
324                         _cbuf = EmptyArray<char>.Value;
325                         if (current == null)
326                                 return;
327                         CurrentCulture = current.CurrentCulture;
328                 }
329
330                 private void Init (string format)
331                 {
332                         _val1 = _val2 = _val3 = _val4 = 0;
333                         _offset = 0;
334                         _NaN = _infinity = false;
335                         _isCustomFormat = false;
336                         _specifierIsUpper = true;
337                         _precision = -1;
338
339                         if (format == null || format.Length == 0) {
340                                 _specifier = 'G';
341                                 return;
342                         }
343
344                         char specifier = format [0];
345                         if (specifier >= 'a' && specifier <= 'z') {
346                                 specifier = (char)(specifier - 'a' + 'A');
347                                 _specifierIsUpper = false;
348                         }
349                         else if (specifier < 'A' || specifier > 'Z') {
350                                 _isCustomFormat = true;
351                                 _specifier = '0';
352                                 return;
353                         }
354                         _specifier = specifier;
355                         if (format.Length > 1) {
356                                 _precision = ParsePrecision (format);
357                                 if (_precision == -2) { // Is it a custom format?
358                                         _isCustomFormat = true;
359                                         _specifier = '0';
360                                         _precision = -1;
361                                 }
362                         }
363                 }
364
365                 private void InitHex (ulong value)
366                 {
367                         switch (_defPrecision) {
368                                 case Int8DefPrecision:  value = (byte) value;    break;
369                                 case Int16DefPrecision: value = (ushort) value;  break;
370                                 case Int32DefPrecision: value = (uint) value;    break;
371                         }
372                         _val1 = (uint)value;
373                         _val2 = (uint)(value >> 32);
374                         _decPointPos = _digitsLen = DecHexLen ();
375                         if (value == 0)
376                                 _decPointPos = 1;
377                 }
378
379                 private void Init (string format, int value, int defPrecision)
380                 {
381                         Init (format);
382                         _defPrecision = defPrecision;
383                         _positive = value >= 0;
384
385                         if (value == 0 || _specifier == 'X') {
386                                 InitHex ((ulong)value);
387                                 return;
388                         }
389
390                         if (value < 0)
391                                 value = -value;
392                         InitDecHexDigits ((uint)value);
393                         _decPointPos = _digitsLen = DecHexLen ();
394                 }
395
396                 private void Init (string format, uint value, int defPrecision)
397                 {
398                         Init (format);
399                         _defPrecision = defPrecision;
400                         _positive = true;
401
402                         if (value == 0 || _specifier == 'X') {
403                                 InitHex (value);
404                                 return;
405                         }
406
407                         InitDecHexDigits (value);
408                         _decPointPos = _digitsLen = DecHexLen ();
409                 }
410
411                 private void Init (string format, long value)
412                 {
413                         Init (format);
414                         _defPrecision = Int64DefPrecision;
415                         _positive = value >= 0;
416
417                         if (value == 0 || _specifier == 'X') {
418                                 InitHex ((ulong)value);
419                                 return;
420                         }
421
422                         if (value < 0)
423                                 value = -value;
424                         InitDecHexDigits ((ulong)value);
425                         _decPointPos = _digitsLen = DecHexLen ();
426                 }
427
428                 private void Init (string format, ulong value)
429                 {
430                         Init (format);
431                         _defPrecision = UInt64DefPrecision;
432                         _positive = true;
433
434                         if (value == 0 || _specifier == 'X') {
435                                 InitHex ((ulong)value);
436                                 return;
437                         }
438
439                         InitDecHexDigits (value);
440                         _decPointPos = _digitsLen = DecHexLen ();
441                 }
442
443 #if UNSAFE_TABLES // No unsafe code under TARGET_JVM
444                 unsafe
445 #endif
446                 private void Init (string format, double value, int defPrecision)
447                 {
448                         Init (format);
449
450                         _defPrecision = defPrecision;
451                         long bits = BitConverter.DoubleToInt64Bits (value);
452                         _positive = bits >= 0;
453                         bits &= Int64.MaxValue;
454                         if (bits == 0) {
455                                 _decPointPos = 1;
456                                 _digitsLen = 0;
457                                 _positive = true;
458                                 return;
459                         }
460
461                         int e = (int)(bits >> DoubleBitsExponentShift);
462                         long m = bits & DoubleBitsMantissaMask;
463                         if (e == DoubleBitsExponentMask) {
464                                 _NaN = m != 0;
465                                 _infinity = m == 0;
466                                 return;
467                         }
468
469                         int expAdjust = 0;
470                         if (e == 0) {
471                                 // We need 'm' to be large enough so we won't lose precision.
472                                 e = 1;
473                                 int scale = ScaleOrder (m);
474                                 if (scale < DoubleDefPrecision) {
475                                         expAdjust = scale - DoubleDefPrecision;
476                                         m *= GetTenPowerOf (-expAdjust);
477                                 }
478                         }
479                         else {
480                                 m = (m + DoubleBitsMantissaMask + 1) * 10;
481                                 expAdjust = -1;
482                         }
483
484                         // multiply the mantissa by 10 ^ N
485                         ulong lo = (uint)m;
486                         ulong hi = (ulong)m >> 32;
487                         ulong lo2 = MantissaBitsTable [e];
488                         ulong hi2 = lo2 >> 32;
489                         lo2 = (uint)lo2;
490                         ulong mm = hi * lo2 + lo * hi2 + ((lo * lo2) >> 32);
491                         long res = (long)(hi * hi2 + (mm >> 32));
492                         while (res < SeventeenDigitsThreshold) {
493                                 mm = (mm & UInt32.MaxValue) * 10;
494                                 res = res * 10 + (long)(mm >> 32);
495                                 expAdjust--;
496                         }
497                         if ((mm & 0x80000000) != 0)
498                                 res++;
499
500                         int order = DoubleDefPrecision + 2;
501                         _decPointPos = TensExponentTable [e] + expAdjust + order;
502
503                         // Rescale 'res' to the initial precision (15-17 for doubles).
504                         int initialPrecision = InitialFloatingPrecision ();
505                         if (order > initialPrecision) {
506                                 long val = GetTenPowerOf (order - initialPrecision);
507                                 res = (res + (val >> 1)) / val;
508                                 order = initialPrecision;
509                         }
510                         if (res >= GetTenPowerOf (order)) {
511                                 order++;
512                                 _decPointPos++;
513                         }
514
515                         InitDecHexDigits ((ulong)res);
516                         _offset = CountTrailingZeros ();
517                         _digitsLen = order - _offset;
518                 }
519
520                 private void Init (string format, decimal value)
521                 {
522                         Init (format);
523                         _defPrecision = DecimalDefPrecision;
524
525                         int[] bits = decimal.GetBits (value);
526                         int scale = (bits [3] & DecimalBitsScaleMask) >> 16;
527                         _positive = bits [3] >= 0;
528                         if (bits [0] == 0 && bits [1] == 0 && bits [2] == 0) {
529                                 _decPointPos = -scale;
530                                 _positive = true;
531                                 _digitsLen = 0;
532                                 return;
533                         }
534
535                         InitDecHexDigits ((uint)bits [2], ((ulong)bits [1] << 32) | (uint)bits [0]);
536                         _digitsLen = DecHexLen ();
537                         _decPointPos = _digitsLen - scale;
538                         if (_precision != -1 || _specifier != 'G') {
539                                 _offset = CountTrailingZeros ();
540                                 _digitsLen -= _offset;
541                         }
542                 }
543
544                 #endregion Constructors
545
546                 #region Inner String Buffer
547
548                 //_cbuf moved to before other fields to improve layout
549                 private int _ind;
550
551                 private void ResetCharBuf (int size)
552                 {
553                         _ind = 0;
554                         if (_cbuf.Length < size)
555                                 _cbuf = new char [size];
556                 }
557
558                 private void Resize (int len)
559                 {
560                         Array.Resize (ref _cbuf, len);
561                 }
562
563                 private void Append (char c)
564                 {
565                         if (_ind == _cbuf.Length)
566                                 Resize (_ind + 10);
567                         _cbuf [_ind++] = c;
568                 }
569
570                 private void Append (char c, int cnt)
571                 {
572                         if (_ind + cnt > _cbuf.Length)
573                                 Resize (_ind + cnt + 10);
574                         while (cnt-- > 0)
575                                 _cbuf [_ind++] = c;
576                 }
577
578                 private void Append (string s)
579                 {
580                         int slen = s.Length;
581                         if (_ind + slen > _cbuf.Length)
582                                 Resize (_ind + slen + 10);
583                         for (int i = 0; i < slen; i++)
584                                 _cbuf [_ind++] = s [i];
585                 }
586
587                 #endregion Inner String Buffer
588
589                 #region Helper properties
590
591                 private NumberFormatInfo GetNumberFormatInstance (IFormatProvider fp)
592                 {
593                         if (_nfi != null && fp == null)
594                                 return _nfi;
595                         return NumberFormatInfo.GetInstance (fp);
596                 }
597
598                 public CultureInfo CurrentCulture {
599                         set {
600                                 if (value != null && value.IsReadOnly)
601                                         _nfi = value.NumberFormat;
602                                 else
603                                         _nfi = null;
604                         }
605                 }
606
607                 private int IntegerDigits {
608                         get { return _decPointPos > 0 ? _decPointPos : 1; }
609                 }
610
611                 private int DecimalDigits {
612                         get { return _digitsLen > _decPointPos ? _digitsLen - _decPointPos : 0; }
613                 }
614
615                 private bool IsFloatingSource {
616                         get { return _defPrecision == DoubleDefPrecision || _defPrecision == SingleDefPrecision; }
617                 }
618
619                 private bool IsZero {
620                         get { return _digitsLen == 0; }
621                 }
622
623                 private bool IsZeroInteger {
624                         get { return _digitsLen == 0 || _decPointPos <= 0; }
625                 }
626
627                 #endregion Helper properties
628
629                 #region Round
630
631                 private void RoundPos (int pos)
632                 {
633                         RoundBits (_digitsLen - pos);
634                 }
635
636                 private bool RoundDecimal (int decimals)
637                 {
638                         return RoundBits (_digitsLen - _decPointPos - decimals);
639                 }
640
641                 private bool RoundBits (int shift)
642                 {
643                         if (shift <= 0)
644                                 return false;
645
646                         if (shift > _digitsLen) {
647                                 _digitsLen = 0;
648                                 _decPointPos = 1;
649                                 _val1 = _val2 = _val3 = _val4 = 0;
650                                 _positive = true;
651                                 return false;
652                         }
653                         shift += _offset;
654                         _digitsLen += _offset;
655                         while (shift > 8) {
656                                 _val1 = _val2;
657                                 _val2 = _val3;
658                                 _val3 = _val4;
659                                 _val4 = 0;
660                                 _digitsLen -= 8;
661                                 shift -= 8;
662                         }
663                         shift = (shift - 1) << 2;
664                         uint v = _val1 >> shift;
665                         uint rem16 = v & 0xf;
666                         _val1 = (v ^ rem16) << shift;
667                         bool res = false;
668                         if (rem16 >= 0x5) {
669                                 _val1 |= 0x99999999 >> (28 - shift);
670                                 AddOneToDecHex ();
671                                 int newlen = DecHexLen ();
672                                 res = newlen != _digitsLen;
673                                 _decPointPos = _decPointPos + newlen - _digitsLen;
674                                 _digitsLen = newlen;
675                         }
676                         RemoveTrailingZeros ();
677                         return res;
678                 }
679
680                 private void RemoveTrailingZeros ()
681                 {
682                         _offset = CountTrailingZeros ();
683                         _digitsLen -= _offset;
684                         if (_digitsLen == 0) {
685                                 _offset = 0;
686                                 _decPointPos = 1;
687                                 _positive = true;
688                         }
689                 }
690
691                 private void AddOneToDecHex ()
692                 {
693                         if (_val1 == 0x99999999) {
694                                 _val1 = 0;
695                                 if (_val2 == 0x99999999) {
696                                         _val2 = 0;
697                                         if (_val3 == 0x99999999) {
698                                                 _val3 = 0;
699                                                 _val4 = AddOneToDecHex (_val4);
700                                         }
701                                         else
702                                                 _val3 = AddOneToDecHex (_val3);
703                                 }
704                                 else
705                                         _val2 = AddOneToDecHex (_val2);
706                         }
707                         else
708                                 _val1 = AddOneToDecHex (_val1);
709                 }
710
711                 // Assume val != 0x99999999
712                 private static uint AddOneToDecHex (uint val)
713                 {
714                         if ((val & 0xffff) == 0x9999)
715                                 if ((val & 0xffffff) == 0x999999)
716                                         if ((val & 0xfffffff) == 0x9999999)
717                                                 return val + 0x06666667;
718                                         else
719                                                 return val + 0x00666667;
720                                 else if ((val & 0xfffff) == 0x99999)
721                                         return val + 0x00066667;
722                                 else
723                                         return val + 0x00006667;
724                         else if ((val & 0xff) == 0x99)
725                                 if ((val & 0xfff) == 0x999)
726                                         return val + 0x00000667;
727                                 else
728                                         return val + 0x00000067;
729                         else if ((val & 0xf) == 0x9)
730                                 return val + 0x00000007;
731                         else
732                                 return val + 1;
733                 }
734
735                 private int CountTrailingZeros ()
736                 {
737                         if (_val1 != 0)
738                                 return CountTrailingZeros (_val1);
739                         if (_val2 != 0)
740                                 return CountTrailingZeros (_val2) + 8;
741                         if (_val3 != 0)
742                                 return CountTrailingZeros (_val3) + 16;
743                         if (_val4 != 0)
744                                 return CountTrailingZeros (_val4) + 24;
745                         return _digitsLen;
746                 }
747
748                 private static int CountTrailingZeros (uint val)
749                 {
750                         if ((val & 0xffff) == 0)
751                                 if ((val & 0xffffff) == 0)
752                                         if ((val & 0xfffffff) == 0)
753                                                 return 7;
754                                         else
755                                                 return 6;
756                                 else if ((val & 0xfffff) == 0)
757                                         return 5;
758                                 else
759                                         return 4;
760                         else if ((val & 0xff) == 0)
761                                 if ((val & 0xfff) == 0)
762                                         return 3;
763                                 else
764                                         return 2;
765                         else if ((val & 0xf) == 0)
766                                 return 1;
767                         else
768                                 return 0;
769                 }
770
771                 #endregion Round
772
773                 #region public number formatting methods
774
775                 [ThreadStatic]
776                 static NumberFormatter threadNumberFormatter;
777
778                 [ThreadStatic]
779                 static NumberFormatter userFormatProvider;
780
781                 private static NumberFormatter GetInstance (IFormatProvider fp)
782                 {
783                         if (fp != null) {
784                                 if (userFormatProvider == null) {
785                                         Interlocked.CompareExchange (ref userFormatProvider, new NumberFormatter (null), null);
786                                 }
787
788                                 return userFormatProvider;
789                         }
790
791                         NumberFormatter res = threadNumberFormatter;
792                         threadNumberFormatter = null;
793                         if (res == null)
794                                 return new NumberFormatter (Thread.CurrentThread);
795                         res.CurrentCulture = Thread.CurrentThread.CurrentCulture;
796                         return res;
797                 }
798
799                 private void Release()
800                 {
801                         if (this != userFormatProvider)
802                                 threadNumberFormatter = this;
803                 }
804
805                 public static string NumberToString (string format, sbyte value, IFormatProvider fp)
806                 {
807                         NumberFormatter inst = GetInstance (fp);
808                         inst.Init (format, value, Int8DefPrecision);
809                         string res = inst.IntegerToString (format, fp);
810                         inst.Release();
811                         return res;
812                 }
813
814                 public static string NumberToString (string format, byte value, IFormatProvider fp)
815                 {
816                         NumberFormatter inst = GetInstance (fp);
817                         inst.Init (format, value, UInt8DefPrecision);
818                         string res = inst.IntegerToString (format, fp);
819                         inst.Release();
820                         return res;
821                 }
822
823                 public static string NumberToString (string format, ushort value, IFormatProvider fp)
824                 {
825                         NumberFormatter inst = GetInstance (fp);
826                         inst.Init (format, value, Int16DefPrecision);
827                         string res = inst.IntegerToString (format, fp);
828                         inst.Release();
829                         return res;
830                 }
831
832                 public static string NumberToString (string format, short value, IFormatProvider fp)
833                 {
834                         NumberFormatter inst = GetInstance (fp);
835                         inst.Init (format, value, UInt16DefPrecision);
836                         string res = inst.IntegerToString (format, fp);
837                         inst.Release();
838                         return res;
839                 }
840
841                 public static string NumberToString (string format, uint value, IFormatProvider fp)
842                 {
843                         NumberFormatter inst = GetInstance (fp);
844                         inst.Init (format, value, Int32DefPrecision);
845                         string res = inst.IntegerToString (format, fp);
846                         inst.Release();
847                         return res;
848                 }
849
850                 public static string NumberToString (string format, int value, IFormatProvider fp)
851                 {
852                         NumberFormatter inst = GetInstance (fp);
853                         inst.Init (format, value, UInt32DefPrecision);
854                         string res = inst.IntegerToString (format, fp);
855                         inst.Release();
856                         return res;
857                 }
858
859                 public static string NumberToString (string format, ulong value, IFormatProvider fp)
860                 {
861                         NumberFormatter inst = GetInstance (fp);
862                         inst.Init (format, value);
863                         string res = inst.IntegerToString (format, fp);
864                         inst.Release();
865                         return res;
866                 }
867
868                 public static string NumberToString (string format, long value, IFormatProvider fp)
869                 {
870                         NumberFormatter inst = GetInstance (fp);
871                         inst.Init (format, value);
872                         string res = inst.IntegerToString (format, fp);
873                         inst.Release();
874                         return res;
875                 }
876
877                 public static string NumberToString (string format, float value, IFormatProvider fp)
878                 {
879                         NumberFormatter inst = GetInstance (fp);
880                         inst.Init (format, value, SingleDefPrecision);
881                         NumberFormatInfo nfi = inst.GetNumberFormatInstance (fp);
882                         string res;
883                         if (inst._NaN)
884                                 res = nfi.NaNSymbol;
885                         else if (inst._infinity)
886                                 if (inst._positive)
887                                         res = nfi.PositiveInfinitySymbol;
888                                 else
889                                         res = nfi.NegativeInfinitySymbol;
890                         else if (inst._specifier == 'R')
891                                 res = inst.FormatRoundtrip (value, nfi);
892                         else
893                                 res = inst.NumberToString (format, nfi);
894                         inst.Release();
895                         return res;
896                 }
897
898                 public static string NumberToString (string format, double value, IFormatProvider fp)
899                 {
900                         NumberFormatter inst = GetInstance (fp);
901                         inst.Init (format, value, DoubleDefPrecision);
902                         NumberFormatInfo nfi = inst.GetNumberFormatInstance (fp);
903                         string res;
904                         if (inst._NaN)
905                                 res = nfi.NaNSymbol;
906                         else if (inst._infinity)
907                                 if (inst._positive)
908                                         res = nfi.PositiveInfinitySymbol;
909                                 else
910                                         res = nfi.NegativeInfinitySymbol;
911                         else if (inst._specifier == 'R')
912                                 res = inst.FormatRoundtrip (value, nfi);
913                         else
914                                 res = inst.NumberToString (format, nfi);
915                         inst.Release();
916                         return res;
917                 }
918
919                 public static string NumberToString (string format, decimal value, IFormatProvider fp)
920                 {
921                         NumberFormatter inst = GetInstance (fp);
922                         inst.Init (format, value);
923                         string res = inst.NumberToString (format, inst.GetNumberFormatInstance (fp));
924                         inst.Release();
925                         return res;
926                 }
927
928                 public static string NumberToString (uint value, IFormatProvider fp)
929                 {
930                         if (value >= HundredMillion)
931                                 return NumberToString (null, value, fp);
932
933                         NumberFormatter inst = GetInstance (fp);
934                         string res = inst.FastIntegerToString ((int)value, fp);
935                         inst.Release();
936                         return res;
937                 }
938
939                 public static string NumberToString (int value, IFormatProvider fp)
940                 {
941                         if (value >= HundredMillion || value <= -HundredMillion)
942                                 return NumberToString (null, value, fp);
943
944                         NumberFormatter inst = GetInstance (fp);
945                         string res = inst.FastIntegerToString (value, fp);
946                         inst.Release();
947                         return res;
948                 }
949
950                 public static string NumberToString (ulong value, IFormatProvider fp)
951                 {
952                         if (value >= HundredMillion)
953                                 return NumberToString (null, value, fp);
954
955                         NumberFormatter inst = GetInstance (fp);
956                         string res = inst.FastIntegerToString ((int)value, fp);
957                         inst.Release();
958                         return res;
959                 }
960
961                 public static string NumberToString (long value, IFormatProvider fp)
962                 {
963                         if (value >= HundredMillion || value <= -HundredMillion)
964                                 return NumberToString (null, value, fp);
965
966                         NumberFormatter inst = GetInstance (fp);
967                         string res = inst.FastIntegerToString ((int)value, fp);
968                         inst.Release();
969                         return res;
970                 }
971
972                 public static string NumberToString (float value, IFormatProvider fp)
973                 {
974                         NumberFormatter inst = GetInstance (fp);
975                         inst.Init (null, value, SingleDefPrecision);
976                         NumberFormatInfo nfi = inst.GetNumberFormatInstance (fp);
977                         string res;
978                         if (inst._NaN)
979                                 res = nfi.NaNSymbol;
980                         else if (inst._infinity)
981                                 if (inst._positive)
982                                         res = nfi.PositiveInfinitySymbol;
983                                 else
984                                         res = nfi.NegativeInfinitySymbol;
985                         else
986                                 res = inst.FormatGeneral (-1, nfi);
987                         inst.Release();
988                         return res;
989                 }
990
991                 public static string NumberToString (double value, IFormatProvider fp)
992                 {
993                         NumberFormatter inst = GetInstance (fp);
994                         NumberFormatInfo nfi = inst.GetNumberFormatInstance (fp);
995                         inst.Init (null, value, DoubleDefPrecision);
996                         string res;
997                         if (inst._NaN)
998                                 res = nfi.NaNSymbol;
999                         else if (inst._infinity)
1000                                 if (inst._positive)
1001                                         res = nfi.PositiveInfinitySymbol;
1002                                 else
1003                                         res = nfi.NegativeInfinitySymbol;
1004                         else
1005                                 res = inst.FormatGeneral (-1, nfi);
1006                         inst.Release();
1007                         return res;
1008                 }
1009
1010                 private string FastIntegerToString (int value, IFormatProvider fp)
1011                 {
1012                         if (value < 0) {
1013                                 string sign = GetNumberFormatInstance(fp).NegativeSign;
1014                                 ResetCharBuf (8 + sign.Length);
1015                                 value = -value;
1016                                 Append (sign);
1017                         }
1018                         else
1019                                 ResetCharBuf (8);
1020
1021                         if (value >= 10000) {
1022                                 int v = value / 10000;
1023                                 FastAppendDigits (v, false);
1024                                 FastAppendDigits (value - v * 10000, true);
1025                         }
1026                         else
1027                                 FastAppendDigits (value, false);
1028
1029                         return new string (_cbuf, 0, _ind);
1030                 }
1031
1032                 private string IntegerToString (string format, IFormatProvider fp)
1033                 {
1034                         NumberFormatInfo nfi = GetNumberFormatInstance (fp);
1035                         switch (_specifier) {
1036                         case 'C':
1037                                 return FormatCurrency (_precision, nfi);
1038                         case 'D':
1039                                 return FormatDecimal (_precision, nfi);
1040                         case 'E':
1041                                 return FormatExponential (_precision, nfi);
1042                         case 'F':
1043                                 return FormatFixedPoint (_precision, nfi);
1044                         case 'G':
1045                                 if (_precision <= 0)
1046                                         return FormatDecimal (-1, nfi);
1047                                 return FormatGeneral (_precision, nfi);
1048                         case 'N':
1049                                 return FormatNumber (_precision, nfi);
1050                         case 'P':
1051                                 return FormatPercent (_precision, nfi);
1052                         case 'X':
1053                                 return FormatHexadecimal (_precision);
1054                         default:
1055                                 if (_isCustomFormat)
1056                                         return FormatCustom (format, nfi);
1057                                 throw new FormatException ("The specified format '" + format + "' is invalid");
1058                         }
1059                 }
1060
1061                 private string NumberToString (string format, NumberFormatInfo nfi)
1062                 {
1063                         switch (_specifier) {
1064                         case 'C':
1065                                 return FormatCurrency (_precision, nfi);
1066                         case 'E':
1067                                 return FormatExponential (_precision, nfi);
1068                         case 'F':
1069                                 return FormatFixedPoint (_precision, nfi);
1070                         case 'G':
1071                                 return FormatGeneral (_precision, nfi);
1072                         case 'N':
1073                                 return FormatNumber (_precision, nfi);
1074                         case 'P':
1075                                 return FormatPercent (_precision, nfi);
1076                         case 'X':
1077                         default:
1078                                 if (_isCustomFormat)
1079                                         return FormatCustom (format, nfi);
1080                                 throw new FormatException ("The specified format '" + format + "' is invalid");
1081                         }
1082                 }
1083
1084                 public string FormatCurrency (int precision, NumberFormatInfo nfi)
1085                 {
1086                         precision = (precision >= 0 ? precision : nfi.CurrencyDecimalDigits);
1087                         RoundDecimal (precision);
1088                         ResetCharBuf (IntegerDigits * 2 + precision * 2 + 16);
1089
1090                         if (_positive) {
1091                                 switch (nfi.CurrencyPositivePattern) {
1092                                 case 0:
1093                                         Append (nfi.CurrencySymbol);
1094                                         break;
1095                                 case 2:
1096                                         Append (nfi.CurrencySymbol);
1097                                         Append (' ');
1098                                         break;
1099                                 }
1100                         }
1101                         else {
1102                                 switch (nfi.CurrencyNegativePattern) {
1103                                 case 0:
1104                                         Append ('(');
1105                                         Append (nfi.CurrencySymbol);
1106                                         break;
1107                                 case 1:
1108                                         Append (nfi.NegativeSign);
1109                                         Append (nfi.CurrencySymbol);
1110                                         break;
1111                                 case 2:
1112                                         Append (nfi.CurrencySymbol);
1113                                         Append (nfi.NegativeSign);
1114                                         break;
1115                                 case 3:
1116                                         Append (nfi.CurrencySymbol);
1117                                         break;
1118                                 case 4:
1119                                         Append ('(');
1120                                         break;
1121                                 case 5:
1122                                         Append (nfi.NegativeSign);
1123                                         break;
1124                                 case 8:
1125                                         Append (nfi.NegativeSign);
1126                                         break;
1127                                 case 9:
1128                                         Append (nfi.NegativeSign);
1129                                         Append (nfi.CurrencySymbol);
1130                                         Append (' ');
1131                                         break;
1132                                 case 11:
1133                                         Append (nfi.CurrencySymbol);
1134                                         Append (' ');
1135                                         break;
1136                                 case 12:
1137                                         Append (nfi.CurrencySymbol);
1138                                         Append (' ');
1139                                         Append (nfi.NegativeSign);
1140                                         break;
1141                                 case 14:
1142                                         Append ('(');
1143                                         Append (nfi.CurrencySymbol);
1144                                         Append (' ');
1145                                         break;
1146                                 case 15:
1147                                         Append ('(');
1148                                         break;
1149                                 }
1150                         }
1151
1152                         AppendIntegerStringWithGroupSeparator (nfi.RawCurrencyGroupSizes, nfi.CurrencyGroupSeparator);
1153
1154                         if (precision > 0) {
1155                                 Append (nfi.CurrencyDecimalSeparator);
1156                                 AppendDecimalString (precision);
1157                         }
1158
1159                         if (_positive) {
1160                                 switch (nfi.CurrencyPositivePattern) {
1161                                 case 1:
1162                                         Append (nfi.CurrencySymbol);
1163                                         break;
1164                                 case 3:
1165                                         Append (' ');
1166                                         Append (nfi.CurrencySymbol);
1167                                         break;
1168                                 }
1169                         }
1170                         else {
1171                                 switch (nfi.CurrencyNegativePattern) {
1172                                 case 0:
1173                                         Append (')');
1174                                         break;
1175                                 case 3:
1176                                         Append (nfi.NegativeSign);
1177                                         break;
1178                                 case 4:
1179                                         Append (nfi.CurrencySymbol);
1180                                         Append (')');
1181                                         break;
1182                                 case 5:
1183                                         Append (nfi.CurrencySymbol);
1184                                         break;
1185                                 case 6:
1186                                         Append (nfi.NegativeSign);
1187                                         Append (nfi.CurrencySymbol);
1188                                         break;
1189                                 case 7:
1190                                         Append (nfi.CurrencySymbol);
1191                                         Append (nfi.NegativeSign);
1192                                         break;
1193                                 case 8:
1194                                         Append (' ');
1195                                         Append (nfi.CurrencySymbol);
1196                                         break;
1197                                 case 10:
1198                                         Append (' ');
1199                                         Append (nfi.CurrencySymbol);
1200                                         Append (nfi.NegativeSign);
1201                                         break;
1202                                 case 11:
1203                                         Append (nfi.NegativeSign);
1204                                         break;
1205                                 case 13:
1206                                         Append (nfi.NegativeSign);
1207                                         Append (' ');
1208                                         Append (nfi.CurrencySymbol);
1209                                         break;
1210                                 case 14:
1211                                         Append (')');
1212                                         break;
1213                                 case 15:
1214                                         Append (' ');
1215                                         Append (nfi.CurrencySymbol);
1216                                         Append (')');
1217                                         break;
1218                                 }
1219                         }
1220
1221                         return new string (_cbuf, 0, _ind);
1222                 }
1223
1224                 private string FormatDecimal (int precision, NumberFormatInfo nfi)
1225                 {
1226                         if (precision < _digitsLen)
1227                                 precision = _digitsLen;
1228                         if (precision == 0)
1229                                 return "0";
1230
1231                         ResetCharBuf (precision + 1);
1232                         if (!_positive)
1233                                 Append (nfi.NegativeSign);
1234                         AppendDigits (0, precision);
1235
1236                         return new string (_cbuf, 0, _ind);
1237                 }
1238
1239 #if UNSAFE_TABLES // No unsafe code under TARGET_JVM
1240                 unsafe
1241 #endif
1242                 private string FormatHexadecimal (int precision)
1243                 {
1244                         int size = Math.Max (precision, _decPointPos);
1245 #if UNSAFE_TABLES
1246                         char* digits = _specifierIsUpper ? DigitUpperTable : DigitLowerTable;
1247 #else
1248                         char[] digits = _specifierIsUpper ? DigitUpperTable : DigitLowerTable;
1249 #endif
1250                         ResetCharBuf (size);
1251                         _ind = size;
1252                         ulong val = _val1 | ((ulong)_val2 << 32);
1253                         while (size > 0) {
1254                                 _cbuf [--size] = digits [val & 0xf];
1255                                 val >>= 4;
1256                         }
1257                         return new string (_cbuf, 0, _ind);
1258                 }
1259
1260                 public string FormatFixedPoint (int precision, NumberFormatInfo nfi)
1261                 {
1262                         if (precision == -1)
1263                                 precision = nfi.NumberDecimalDigits;
1264
1265                         RoundDecimal (precision);
1266
1267                         ResetCharBuf (IntegerDigits + precision + 2);
1268
1269                         if (!_positive)
1270                                 Append (nfi.NegativeSign);
1271
1272                         AppendIntegerString (IntegerDigits);
1273
1274                         if (precision > 0) {
1275                                 Append (nfi.NumberDecimalSeparator);
1276                                 AppendDecimalString (precision);
1277                         }
1278
1279                         return new string (_cbuf, 0, _ind);
1280                 }
1281
1282                 private string FormatRoundtrip (double origval, NumberFormatInfo nfi)
1283                 {
1284                         NumberFormatter nfc = GetClone ();
1285                         if (origval >= MinRoundtripVal && origval <= MaxRoundtripVal) {
1286                                 string shortRep = FormatGeneral (_defPrecision, nfi);
1287                                 if (origval == Double.Parse (shortRep, nfi))
1288                                         return shortRep;
1289                         }
1290                         return nfc.FormatGeneral (_defPrecision + 2, nfi);
1291                 }
1292
1293                 private string FormatRoundtrip (float origval, NumberFormatInfo nfi)
1294                 {
1295                         NumberFormatter nfc = GetClone ();
1296                         string shortRep = FormatGeneral (_defPrecision, nfi);
1297                         // Check roundtrip only for "normal" double values.
1298                         if (origval == Single.Parse (shortRep, nfi))
1299                                 return shortRep;
1300                         return nfc.FormatGeneral (_defPrecision + 2, nfi);
1301                 }
1302
1303                 private string FormatGeneral (int precision, NumberFormatInfo nfi)
1304                 {
1305                         bool enableExp;
1306                         if (precision == -1) {
1307                                 enableExp = IsFloatingSource;
1308                                 precision = _defPrecision;
1309                         }
1310                         else {
1311                                 enableExp = true;
1312                                 if (precision == 0)
1313                                         precision = _defPrecision;
1314                                 RoundPos (precision);
1315                         }
1316
1317                         int intDigits = _decPointPos;
1318                         int digits = _digitsLen;
1319                         int decDigits = digits - intDigits;
1320
1321                         if ((intDigits > precision || intDigits <= -4) && enableExp)
1322                                 return FormatExponential (digits - 1, nfi, 2);
1323
1324                         if (decDigits < 0)
1325                                 decDigits = 0;
1326                         if (intDigits < 0)
1327                                 intDigits = 0;
1328                         ResetCharBuf (decDigits + intDigits + 3);
1329
1330                         if (!_positive)
1331                                 Append (nfi.NegativeSign);
1332
1333                         if (intDigits == 0)
1334                                 Append ('0');
1335                         else
1336                                 AppendDigits (digits - intDigits, digits);
1337
1338                         if (decDigits > 0) {
1339                                 Append (nfi.NumberDecimalSeparator);
1340                                 AppendDigits (0, decDigits);
1341                         }
1342
1343                         return new string (_cbuf, 0, _ind);
1344                 }
1345
1346                 public string FormatNumber (int precision, NumberFormatInfo nfi)
1347                 {
1348                         precision = (precision >= 0 ? precision : nfi.NumberDecimalDigits);
1349                         ResetCharBuf (IntegerDigits * 3 + precision);
1350                         RoundDecimal (precision);
1351
1352                         if (!_positive) {
1353                                 switch (nfi.NumberNegativePattern) {
1354                                 case 0:
1355                                         Append ('(');
1356                                         break;
1357                                 case 1:
1358                                         Append (nfi.NegativeSign);
1359                                         break;
1360                                 case 2:
1361                                         Append (nfi.NegativeSign);
1362                                         Append (' ');
1363                                         break;
1364                                 }
1365                         }
1366
1367                         AppendIntegerStringWithGroupSeparator (nfi.RawNumberGroupSizes, nfi.NumberGroupSeparator);
1368
1369                         if (precision > 0) {
1370                                 Append (nfi.NumberDecimalSeparator);
1371                                 AppendDecimalString (precision);
1372                         }
1373
1374                         if (!_positive) {
1375                                 switch (nfi.NumberNegativePattern) {
1376                                 case 0:
1377                                         Append (')');
1378                                         break;
1379                                 case 3:
1380                                         Append (nfi.NegativeSign);
1381                                         break;
1382                                 case 4:
1383                                         Append (' ');
1384                                         Append (nfi.NegativeSign);
1385                                         break;
1386                                 }
1387                         }
1388
1389                         return new string (_cbuf, 0, _ind);
1390                 }
1391
1392                 public string FormatPercent (int precision, NumberFormatInfo nfi)
1393                 {
1394                         precision = (precision >= 0 ? precision : nfi.PercentDecimalDigits);
1395                         Multiply10(2);
1396                         RoundDecimal (precision);
1397                         ResetCharBuf (IntegerDigits * 2 + precision + 16);
1398
1399                         if (_positive) {
1400                                 if (nfi.PercentPositivePattern == 2)
1401                                         Append (nfi.PercentSymbol);
1402                         }
1403                         else {
1404                                 switch (nfi.PercentNegativePattern) {
1405                                 case 0:
1406                                         Append (nfi.NegativeSign);
1407                                         break;
1408                                 case 1:
1409                                         Append (nfi.NegativeSign);
1410                                         break;
1411                                 case 2:
1412                                         Append (nfi.NegativeSign);
1413                                         Append (nfi.PercentSymbol);
1414                                         break;
1415                                 }
1416                         }
1417
1418                         AppendIntegerStringWithGroupSeparator (nfi.RawPercentGroupSizes, nfi.PercentGroupSeparator);
1419
1420                         if (precision > 0) {
1421                                 Append (nfi.PercentDecimalSeparator);
1422                                 AppendDecimalString (precision);
1423                         }
1424
1425                         if (_positive) {
1426                                 switch (nfi.PercentPositivePattern) {
1427                                 case 0:
1428                                         Append (' ');
1429                                         Append (nfi.PercentSymbol);
1430                                         break;
1431                                 case 1:
1432                                         Append (nfi.PercentSymbol);
1433                                         break;
1434                                 }
1435                         }
1436                         else {
1437                                 switch (nfi.PercentNegativePattern) {
1438                                 case 0:
1439                                         Append (' ');
1440                                         Append (nfi.PercentSymbol);
1441                                         break;
1442                                 case 1:
1443                                         Append (nfi.PercentSymbol);
1444                                         break;
1445                                 }
1446                         }
1447
1448                         return new string (_cbuf, 0, _ind);
1449                 }
1450
1451                 public string FormatExponential (int precision, NumberFormatInfo nfi)
1452                 {
1453                         if (precision == -1)
1454                                 precision = DefaultExpPrecision;
1455
1456                         RoundPos (precision + 1);
1457                         return FormatExponential (precision, nfi, 3);
1458                 }
1459
1460                 private string FormatExponential (int precision, NumberFormatInfo nfi, int expDigits)
1461                 {
1462                         int decDigits = _decPointPos;
1463                         int digits = _digitsLen;
1464                         int exponent = decDigits - 1;
1465                         decDigits = _decPointPos = 1;
1466
1467                         ResetCharBuf (precision + 8);
1468
1469                         if (!_positive)
1470                                 Append (nfi.NegativeSign);
1471
1472                         AppendOneDigit (digits - 1);
1473
1474                         if (precision > 0) {
1475                                 Append (nfi.NumberDecimalSeparator);
1476                                 AppendDigits (digits - precision - 1, digits - _decPointPos);
1477                         }
1478
1479                         AppendExponent (nfi, exponent, expDigits);
1480
1481                         return new string (_cbuf, 0, _ind);
1482                 }
1483
1484                 public string FormatCustom (string format, NumberFormatInfo nfi)
1485                 {
1486                         bool p = _positive;
1487                         int offset = 0;
1488                         int length = 0;
1489                         CustomInfo.GetActiveSection (format, ref p, IsZero, ref offset, ref length);
1490                         if (length == 0)
1491                                 return _positive ? string.Empty : nfi.NegativeSign;
1492                         _positive = p;
1493
1494                         CustomInfo info = CustomInfo.Parse (format, offset, length, nfi);
1495 #if false
1496                         Console.WriteLine ("Format : {0}",format);
1497                         Console.WriteLine ("DecimalDigits : {0}",info.DecimalDigits);
1498                         Console.WriteLine ("DecimalPointPos : {0}",info.DecimalPointPos);
1499                         Console.WriteLine ("DecimalTailSharpDigits : {0}",info.DecimalTailSharpDigits);
1500                         Console.WriteLine ("IntegerDigits : {0}",info.IntegerDigits);
1501                         Console.WriteLine ("IntegerHeadSharpDigits : {0}",info.IntegerHeadSharpDigits);
1502                         Console.WriteLine ("IntegerHeadPos : {0}",info.IntegerHeadPos);
1503                         Console.WriteLine ("UseExponent : {0}",info.UseExponent);
1504                         Console.WriteLine ("ExponentDigits : {0}",info.ExponentDigits);
1505                         Console.WriteLine ("ExponentTailSharpDigits : {0}",info.ExponentTailSharpDigits);
1506                         Console.WriteLine ("ExponentNegativeSignOnly : {0}",info.ExponentNegativeSignOnly);
1507                         Console.WriteLine ("DividePlaces : {0}",info.DividePlaces);
1508                         Console.WriteLine ("Percents : {0}",info.Percents);
1509                         Console.WriteLine ("Permilles : {0}",info.Permilles);
1510 #endif
1511                         StringBuilder sb_int = new StringBuilder (info.IntegerDigits * 2);
1512                         StringBuilder sb_dec = new StringBuilder (info.DecimalDigits * 2);
1513                         StringBuilder sb_exp = (info.UseExponent ? new StringBuilder (info.ExponentDigits * 2) : null);
1514
1515                         int diff = 0;
1516                         if (info.Percents > 0)
1517                                 Multiply10(2 * info.Percents);
1518                         if (info.Permilles > 0)
1519                                 Multiply10(3 * info.Permilles);
1520                         if (info.DividePlaces > 0)
1521                                 Divide10(info.DividePlaces);
1522
1523                         bool expPositive = true;
1524                         if (info.UseExponent && (info.DecimalDigits > 0 || info.IntegerDigits > 0)) {
1525                                 if (!IsZero) {
1526                                         RoundPos (info.DecimalDigits + info.IntegerDigits);
1527                                         diff -= _decPointPos - info.IntegerDigits;
1528                                         _decPointPos = info.IntegerDigits;
1529                                 }
1530
1531                                 expPositive = diff <= 0;
1532                                 AppendNonNegativeNumber (sb_exp, diff < 0 ? -diff : diff);
1533                         }
1534                         else
1535                                 RoundDecimal (info.DecimalDigits);
1536
1537                         if (info.IntegerDigits != 0 || !IsZeroInteger)
1538                                 AppendIntegerString (IntegerDigits, sb_int);
1539
1540                         AppendDecimalString (DecimalDigits, sb_dec);
1541
1542                         if (info.UseExponent) {
1543                                 if (info.DecimalDigits <= 0 && info.IntegerDigits <= 0)
1544                                         _positive = true;
1545
1546                                 if (sb_int.Length < info.IntegerDigits)
1547                                         sb_int.Insert (0, "0", info.IntegerDigits - sb_int.Length);
1548
1549                                 while (sb_exp.Length < info.ExponentDigits - info.ExponentTailSharpDigits)
1550                                         sb_exp.Insert (0, '0');
1551
1552                                 if (expPositive && !info.ExponentNegativeSignOnly)
1553                                         sb_exp.Insert (0, nfi.PositiveSign);
1554                                 else if (!expPositive)
1555                                         sb_exp.Insert (0, nfi.NegativeSign);
1556                         }
1557                         else {
1558                                 if (sb_int.Length < info.IntegerDigits - info.IntegerHeadSharpDigits)
1559                                         sb_int.Insert (0, "0", info.IntegerDigits - info.IntegerHeadSharpDigits - sb_int.Length);
1560                                 if (info.IntegerDigits == info.IntegerHeadSharpDigits && IsZeroOnly (sb_int))
1561                                         sb_int.Remove (0, sb_int.Length);
1562                         }
1563
1564                         ZeroTrimEnd (sb_dec, true);
1565                         while (sb_dec.Length < info.DecimalDigits - info.DecimalTailSharpDigits)
1566                                 sb_dec.Append ('0');
1567                         if (sb_dec.Length > info.DecimalDigits)
1568                                 sb_dec.Remove (info.DecimalDigits, sb_dec.Length - info.DecimalDigits);
1569
1570                         return info.Format (format, offset, length, nfi, _positive, sb_int, sb_dec, sb_exp);
1571                 }
1572                 #endregion public number formatting methods
1573
1574                 #region StringBuilder formatting helpers
1575
1576                 private static void ZeroTrimEnd (StringBuilder sb, bool canEmpty)
1577                 {
1578                         int len = 0;
1579                         for (int i = sb.Length - 1; (canEmpty ? i >= 0 : i > 0); i--) {
1580                                 if (sb [i] != '0')
1581                                         break;
1582                                 len++;
1583                         }
1584
1585                         if (len > 0)
1586                                 sb.Remove (sb.Length - len, len);
1587                 }
1588
1589                 private static bool IsZeroOnly (StringBuilder sb)
1590                 {
1591                         for (int i = 0; i < sb.Length; i++)
1592                                 if (char.IsDigit (sb [i]) && sb [i] != '0')
1593                                         return false;
1594                         return true;
1595                 }
1596
1597                 private static void AppendNonNegativeNumber (StringBuilder sb, int v)
1598                 {
1599                         if (v < 0)
1600                                 throw new ArgumentException ();
1601
1602                         int i = ScaleOrder (v) - 1;
1603                         do {
1604                                 int n = v / (int)GetTenPowerOf (i);
1605                                 sb.Append ((char)('0' | n));
1606                                 v -= (int)GetTenPowerOf (i--) * n;
1607                         } while (i >= 0);
1608                 }
1609
1610                 #endregion StringBuilder formatting helpers
1611
1612                 #region Append helpers
1613
1614                 private void AppendIntegerString (int minLength, StringBuilder sb)
1615                 {
1616                         if (_decPointPos <= 0) {
1617                                 sb.Append ('0', minLength);
1618                                 return;
1619                         }
1620
1621                         if (_decPointPos < minLength)
1622                                 sb.Append ('0', minLength - _decPointPos);
1623
1624                         AppendDigits (_digitsLen - _decPointPos, _digitsLen, sb);
1625                 }
1626
1627                 private void AppendIntegerString (int minLength)
1628                 {
1629                         if (_decPointPos <= 0) {
1630                                 Append ('0', minLength);
1631                                 return;
1632                         }
1633
1634                         if (_decPointPos < minLength)
1635                                 Append ('0', minLength - _decPointPos);
1636
1637                         AppendDigits (_digitsLen - _decPointPos, _digitsLen);
1638                 }
1639
1640                 private void AppendDecimalString (int precision, StringBuilder sb)
1641                 {
1642                         AppendDigits (_digitsLen - precision - _decPointPos, _digitsLen - _decPointPos, sb);
1643                 }
1644
1645                 private void AppendDecimalString (int precision)
1646                 {
1647                         AppendDigits (_digitsLen - precision - _decPointPos, _digitsLen - _decPointPos);
1648                 }
1649
1650                 private void AppendIntegerStringWithGroupSeparator (int[] groups, string groupSeparator)
1651                 {
1652                         if (IsZeroInteger) {
1653                                 Append ('0');
1654                                 return;
1655                         }
1656
1657                         int total = 0;
1658                         int groupIndex = 0;
1659                         for (int i = 0; i < groups.Length; i++) {
1660                                 total += groups [i];
1661                                 if (total <= _decPointPos)
1662                                         groupIndex = i;
1663                                 else
1664                                         break;
1665                         }
1666
1667                         if (groups.Length > 0 && total > 0) {
1668                                 int counter;
1669                                 int groupSize = groups [groupIndex];
1670                                 int fraction = _decPointPos > total ? _decPointPos - total : 0;
1671                                 if (groupSize == 0) {
1672                                         while (groupIndex >= 0 && groups [groupIndex] == 0)
1673                                                 groupIndex--;
1674
1675                                         groupSize = fraction > 0 ? fraction : groups [groupIndex];
1676                                 }
1677                                 if (fraction == 0)
1678                                         counter = groupSize;
1679                                 else {
1680                                         groupIndex += fraction / groupSize;
1681                                         counter = fraction % groupSize;
1682                                         if (counter == 0)
1683                                                 counter = groupSize;
1684                                         else
1685                                                 groupIndex++;
1686                                 }
1687
1688                                 if (total >= _decPointPos) {
1689                                         int lastGroupSize = groups [0];
1690                                         if (total > lastGroupSize) {
1691                                                 int lastGroupDiff = -(lastGroupSize - _decPointPos);
1692                                                 int lastGroupMod;
1693
1694                                                 if (lastGroupDiff < lastGroupSize)
1695                                                         counter = lastGroupDiff;
1696                                                 else if (lastGroupSize > 0 && (lastGroupMod = _decPointPos % lastGroupSize) > 0)
1697                                                         counter = lastGroupMod;
1698                                         }
1699                                 }
1700                                 
1701                                 for (int i = 0; ;) {
1702                                         if ((_decPointPos - i) <= counter || counter == 0) {
1703                                                 AppendDigits (_digitsLen - _decPointPos, _digitsLen - i);
1704                                                 break;
1705                                         }
1706                                         AppendDigits (_digitsLen - i - counter, _digitsLen - i);
1707                                         i += counter;
1708                                         Append (groupSeparator);
1709                                         if (--groupIndex < groups.Length && groupIndex >= 0)
1710                                                 groupSize = groups [groupIndex];
1711                                         counter = groupSize;
1712                                 }
1713                         }
1714                         else {
1715                                 AppendDigits (_digitsLen - _decPointPos, _digitsLen);
1716                         }
1717                 }
1718
1719                 // minDigits is in the range 1..3
1720                 private void AppendExponent (NumberFormatInfo nfi, int exponent, int minDigits)
1721                 {
1722                         if (_specifierIsUpper || _specifier == 'R')
1723                                 Append ('E');
1724                         else
1725                                 Append ('e');
1726
1727                         if (exponent >= 0)
1728                                 Append (nfi.PositiveSign);
1729                         else {
1730                                 Append (nfi.NegativeSign);
1731                                 exponent = -exponent;
1732                         }
1733
1734                         if (exponent == 0)
1735                                 Append ('0', minDigits);
1736                         else if (exponent < 10) {
1737                                 Append ('0', minDigits - 1);
1738                                 Append ((char)('0' | exponent));
1739                         }
1740                         else {
1741                                 uint hexDigit = FastToDecHex (exponent);
1742                                 if (exponent >= 100 || minDigits == 3)
1743                                         Append ((char)('0' | (hexDigit >> 8)));
1744                                 Append ((char)('0' | ((hexDigit >> 4) & 0xf)));
1745                                 Append ((char)('0' | (hexDigit & 0xf)));
1746                         }
1747                 }
1748
1749                 private void AppendOneDigit (int start)
1750                 {
1751                         if (_ind == _cbuf.Length)
1752                                 Resize (_ind + 10);
1753
1754                         start += _offset;
1755                         uint v;
1756                         if (start < 0)
1757                                 v = 0;
1758                         else if (start < 8)
1759                                 v = _val1;
1760                         else if (start < 16)
1761                                 v = _val2;
1762                         else if (start < 24)
1763                                 v = _val3;
1764                         else if (start < 32)
1765                                 v = _val4;
1766                         else
1767                                 v = 0;
1768                         v >>= (start & 0x7) << 2;
1769                         _cbuf [_ind++] = (char)('0' | v & 0xf);
1770                 }
1771
1772 #if UNSAFE_TABLES // No unsafe code under TARGET_JVM
1773                 unsafe
1774 #endif
1775                 private void FastAppendDigits (int val, bool force)
1776                 {
1777                         int i = _ind;
1778                         int digits;
1779                         if (force || val >= 100) {
1780                                 int v = (val * 5243) >> 19;
1781                                 digits = DecHexDigits [v];
1782                                 if (force || val >= 1000)
1783                                         _cbuf [i++] = (char)('0' | digits >> 4);
1784                                 _cbuf [i++] = (char)('0' | (digits & 0xf));
1785                                 digits = DecHexDigits [val - v * 100];
1786                         }
1787                         else
1788                                 digits = DecHexDigits [val];
1789
1790                         if (force || val >= 10)
1791                                 _cbuf [i++] = (char)('0' | digits >> 4);
1792                         _cbuf [i++] = (char)('0' | (digits & 0xf));
1793                         _ind = i;
1794                 }
1795
1796                 private void AppendDigits (int start, int end)
1797                 {
1798                         if (start >= end)
1799                                 return;
1800
1801                         int i = _ind + (end - start);
1802                         if (i > _cbuf.Length)
1803                                 Resize (i + 10);
1804                         _ind = i;
1805
1806                         end += _offset;
1807                         start += _offset;
1808
1809                         for (int next = start + 8 - (start & 0x7); ; start = next, next += 8) {
1810                                 uint v;
1811                                 if (next == 8)
1812                                         v = _val1;
1813                                 else if (next == 16)
1814                                         v = _val2;
1815                                 else if (next == 24)
1816                                         v = _val3;
1817                                 else if (next == 32)
1818                                         v = _val4;
1819                                 else
1820                                         v = 0;
1821                                 v >>= (start & 0x7) << 2;
1822                                 if (next > end)
1823                                         next = end;
1824
1825                                 _cbuf [--i] = (char)('0' | v & 0xf);
1826                                 switch (next - start) {
1827                                 case 8:
1828                                         _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
1829                                         goto case 7;
1830                                 case 7:
1831                                         _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
1832                                         goto case 6;
1833                                 case 6:
1834                                         _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
1835                                         goto case 5;
1836                                 case 5:
1837                                         _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
1838                                         goto case 4;
1839                                 case 4:
1840                                         _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
1841                                         goto case 3;
1842                                 case 3:
1843                                         _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
1844                                         goto case 2;
1845                                 case 2:
1846                                         _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
1847                                         goto case 1;
1848                                 case 1:
1849                                         if (next == end)
1850                                                 return;
1851                                         continue;
1852                                 }
1853                         }
1854                 }
1855
1856                 private void AppendDigits (int start, int end, StringBuilder sb)
1857                 {
1858                         if (start >= end)
1859                                 return;
1860
1861                         int i = sb.Length + (end - start);
1862                         sb.Length = i;
1863
1864                         end += _offset;
1865                         start += _offset;
1866
1867                         for (int next = start + 8 - (start & 0x7); ; start = next, next += 8) {
1868                                 uint v;
1869                                 if (next == 8)
1870                                         v = _val1;
1871                                 else if (next == 16)
1872                                         v = _val2;
1873                                 else if (next == 24)
1874                                         v = _val3;
1875                                 else if (next == 32)
1876                                         v = _val4;
1877                                 else
1878                                         v = 0;
1879                                 v >>= (start & 0x7) << 2;
1880                                 if (next > end)
1881                                         next = end;
1882                                 sb [--i] = (char)('0' | v & 0xf);
1883                                 switch (next - start) {
1884                                 case 8:
1885                                         sb [--i] = (char)('0' | (v >>= 4) & 0xf);
1886                                         goto case 7;
1887                                 case 7:
1888                                         sb [--i] = (char)('0' | (v >>= 4) & 0xf);
1889                                         goto case 6;
1890                                 case 6:
1891                                         sb [--i] = (char)('0' | (v >>= 4) & 0xf);
1892                                         goto case 5;
1893                                 case 5:
1894                                         sb [--i] = (char)('0' | (v >>= 4) & 0xf);
1895                                         goto case 4;
1896                                 case 4:
1897                                         sb [--i] = (char)('0' | (v >>= 4) & 0xf);
1898                                         goto case 3;
1899                                 case 3:
1900                                         sb [--i] = (char)('0' | (v >>= 4) & 0xf);
1901                                         goto case 2;
1902                                 case 2:
1903                                         sb [--i] = (char)('0' | (v >>= 4) & 0xf);
1904                                         goto case 1;
1905                                 case 1:
1906                                         if (next == end)
1907                                                 return;
1908                                         continue;
1909                                 }
1910                         }
1911                 }
1912
1913                 #endregion Append helpers
1914
1915                 #region others
1916
1917                 private void Multiply10(int count)
1918                 {
1919                         if (count <= 0 || _digitsLen == 0)
1920                                 return;
1921
1922                         _decPointPos += count;
1923                 }
1924
1925                 private void Divide10(int count)
1926                 {
1927                         if (count <= 0 || _digitsLen == 0)
1928                                 return;
1929
1930                         _decPointPos -= count;
1931                 }
1932
1933                 private NumberFormatter GetClone ()
1934                 {
1935                         return (NumberFormatter)this.MemberwiseClone ();
1936                 }
1937
1938                 #endregion others
1939
1940                 #region custom
1941
1942                 private class CustomInfo
1943                 {
1944                         public bool UseGroup = false;
1945                         public int DecimalDigits = 0;
1946                         public int DecimalPointPos = -1;
1947                         public int DecimalTailSharpDigits = 0;
1948                         public int IntegerDigits = 0;
1949                         public int IntegerHeadSharpDigits = 0;
1950                         public int IntegerHeadPos = 0;
1951                         public bool UseExponent = false;
1952                         public int ExponentDigits = 0;
1953                         public int ExponentTailSharpDigits = 0;
1954                         public bool ExponentNegativeSignOnly = true;
1955                         public int DividePlaces = 0;
1956                         public int Percents = 0;
1957                         public int Permilles = 0;
1958
1959                         public static void GetActiveSection (string format, ref bool positive, bool zero, ref int offset, ref int length)
1960                         {
1961                                 int[] lens = new int [3];
1962                                 int index = 0;
1963                                 int lastPos = 0;
1964                                 bool quoted = false;
1965
1966                                 for (int i = 0; i < format.Length; i++) {
1967                                         char c = format [i];
1968
1969                                         if (c == '\"' || c == '\'') {
1970                                                 if (i == 0 || format [i - 1] != '\\')
1971                                                         quoted = !quoted;
1972
1973                                                 continue;
1974                                         }
1975
1976                                         if (c == ';' && !quoted && (i == 0 || format [i - 1] != '\\')) {
1977                                                 lens [index++] = i - lastPos;
1978                                                 lastPos = i + 1;
1979                                                 if (index == 3)
1980                                                         break;
1981                                         }
1982                                 }
1983
1984                                 if (index == 0) {
1985                                         offset = 0;
1986                                         length = format.Length;
1987                                         return;
1988                                 }
1989                                 if (index == 1) {
1990                                         if (positive || zero) {
1991                                                 offset = 0;
1992                                                 length = lens [0];
1993                                                 return;
1994                                         }
1995                                         if (lens [0] + 1 < format.Length) {
1996                                                 positive = true;
1997                                                 offset = lens [0] + 1;
1998                                                 length = format.Length - offset;
1999                                                 return;
2000                                         }
2001                                         else {
2002                                                 offset = 0;
2003                                                 length = lens [0];
2004                                                 return;
2005                                         }
2006                                 }
2007                                 if (index == 2) {
2008                                         if (zero) {
2009                                                 offset = lens [0] + lens [1] + 2;
2010                                                 length = format.Length - offset;
2011                                                 return;
2012                                         }
2013                                         if (positive) {
2014                                                 offset = 0;
2015                                                 length = lens [0];
2016                                                 return;
2017                                         }
2018                                         if (lens [1] > 0) {
2019                                                 positive = true;
2020                                                 offset = lens [0] + 1;
2021                                                 length = lens [1];
2022                                                 return;
2023                                         }
2024                                         else {
2025                                                 offset = 0;
2026                                                 length = lens [0];
2027                                                 return;
2028                                         }
2029                                 }
2030                                 if (index == 3) {
2031                                         if (zero) {
2032                                                 offset = lens [0] + lens [1] + 2;
2033                                                 length = lens [2];
2034                                                 return;
2035                                         }
2036                                         if (positive) {
2037                                                 offset = 0;
2038                                                 length = lens [0];
2039                                                 return;
2040                                         }
2041                                         if (lens [1] > 0) {
2042                                                 positive = true;
2043                                                 offset = lens [0] + 1;
2044                                                 length = lens [1];
2045                                                 return;
2046                                         }
2047                                         else {
2048                                                 offset = 0;
2049                                                 length = lens [0];
2050                                                 return;
2051                                         }
2052                                 }
2053
2054                                 throw new ArgumentException ();
2055                         }
2056
2057                         public static CustomInfo Parse (string format, int offset, int length, NumberFormatInfo nfi)
2058                         {
2059                                 char literal = '\0';
2060                                 bool integerArea = true;
2061                                 bool decimalArea = false;
2062                                 bool exponentArea = false;
2063                                 bool sharpContinues = true;
2064
2065                                 CustomInfo info = new CustomInfo ();
2066                                 int groupSeparatorCounter = 0;
2067
2068                                 for (int i = offset; i - offset < length; i++) {
2069                                         char c = format [i];
2070
2071                                         if (c == literal && c != '\0') {
2072                                                 literal = '\0';
2073                                                 continue;
2074                                         }
2075                                         if (literal != '\0')
2076                                                 continue;
2077
2078                                         if (exponentArea && (c != '\0' && c != '0' && c != '#')) {
2079                                                 exponentArea = false;
2080                                                 integerArea = (info.DecimalPointPos < 0);
2081                                                 decimalArea = !integerArea;
2082                                                 i--;
2083                                                 continue;
2084                                         }
2085
2086                                         switch (c) {
2087                                         case '\\':
2088                                                 i++;
2089                                                 continue;
2090                                         case '\'':
2091                                         case '\"':
2092                                                 if (c == '\"' || c == '\'') {
2093                                                         literal = c;
2094                                                 }
2095                                                 continue;
2096                                         case '#':
2097                                                 if (sharpContinues && integerArea)
2098                                                         info.IntegerHeadSharpDigits++;
2099                                                 else if (decimalArea)
2100                                                         info.DecimalTailSharpDigits++;
2101                                                 else if (exponentArea)
2102                                                         info.ExponentTailSharpDigits++;
2103
2104                                                 goto case '0';
2105                                         case '0':
2106                                                 if (c != '#') {
2107                                                         sharpContinues = false;
2108                                                         if (decimalArea)
2109                                                                 info.DecimalTailSharpDigits = 0;
2110                                                         else if (exponentArea)
2111                                                                 info.ExponentTailSharpDigits = 0;
2112                                                 }
2113                                                 if (info.IntegerHeadPos == -1)
2114                                                         info.IntegerHeadPos = i;
2115
2116                                                 if (integerArea) {
2117                                                         info.IntegerDigits++;
2118                                                         if (groupSeparatorCounter > 0)
2119                                                                 info.UseGroup = true;
2120                                                         groupSeparatorCounter = 0;
2121                                                 }
2122                                                 else if (decimalArea)
2123                                                         info.DecimalDigits++;
2124                                                 else if (exponentArea)
2125                                                         info.ExponentDigits++;
2126                                                 break;
2127                                         case 'e':
2128                                         case 'E':
2129                                                 if (info.UseExponent)
2130                                                         break;
2131
2132                                                 info.UseExponent = true;
2133                                                 integerArea = false;
2134                                                 decimalArea = false;
2135                                                 exponentArea = true;
2136                                                 if (i + 1 - offset < length) {
2137                                                         char nc = format [i + 1];
2138                                                         if (nc == '+')
2139                                                                 info.ExponentNegativeSignOnly = false;
2140                                                         if (nc == '+' || nc == '-')
2141                                                                 i++;
2142                                                         else if (nc != '0' && nc != '#') {
2143                                                                 info.UseExponent = false;
2144                                                                 if (info.DecimalPointPos < 0)
2145                                                                         integerArea = true;
2146                                                         }
2147                                                 }
2148
2149                                                 break;
2150                                         case '.':
2151                                                 integerArea = false;
2152                                                 decimalArea = true;
2153                                                 exponentArea = false;
2154                                                 if (info.DecimalPointPos == -1)
2155                                                         info.DecimalPointPos = i;
2156                                                 break;
2157                                         case '%':
2158                                                 info.Percents++;
2159                                                 break;
2160                                         case '\u2030':
2161                                                 info.Permilles++;
2162                                                 break;
2163                                         case ',':
2164                                                 if (integerArea && info.IntegerDigits > 0)
2165                                                         groupSeparatorCounter++;
2166                                                 break;
2167                                         default:
2168                                                 break;
2169                                         }
2170                                 }
2171
2172                                 if (info.ExponentDigits == 0)
2173                                         info.UseExponent = false;
2174                                 else
2175                                         info.IntegerHeadSharpDigits = 0;
2176
2177                                 if (info.DecimalDigits == 0)
2178                                         info.DecimalPointPos = -1;
2179
2180                                 info.DividePlaces += groupSeparatorCounter * 3;
2181
2182                                 return info;
2183                         }
2184
2185                         public string Format (string format, int offset, int length, NumberFormatInfo nfi, bool positive, StringBuilder sb_int, StringBuilder sb_dec, StringBuilder sb_exp)
2186                         {
2187                                 StringBuilder sb = new StringBuilder ();
2188                                 char literal = '\0';
2189                                 bool integerArea = true;
2190                                 bool decimalArea = false;
2191                                 int intSharpCounter = 0;
2192                                 int sb_int_index = 0;
2193                                 int sb_dec_index = 0;
2194
2195                                 int[] groups = nfi.RawNumberGroupSizes;
2196                                 string groupSeparator = nfi.NumberGroupSeparator;
2197                                 int intLen = 0, total = 0, groupIndex = 0, counter = 0, groupSize = 0;
2198                                 if (UseGroup && groups.Length > 0) {
2199                                         intLen = sb_int.Length;
2200                                         for (int i = 0; i < groups.Length; i++) {
2201                                                 total += groups [i];
2202                                                 if (total <= intLen)
2203                                                         groupIndex = i;
2204                                         }
2205                                         groupSize = groups [groupIndex];
2206                                         int fraction = intLen > total ? intLen - total : 0;
2207                                         if (groupSize == 0) {
2208                                                 while (groupIndex >= 0 && groups [groupIndex] == 0)
2209                                                         groupIndex--;
2210
2211                                                 groupSize = fraction > 0 ? fraction : groups [groupIndex];
2212                                         }
2213                                         if (fraction == 0)
2214                                                 counter = groupSize;
2215                                         else {
2216                                                 groupIndex += fraction / groupSize;
2217                                                 counter = fraction % groupSize;
2218                                                 if (counter == 0)
2219                                                         counter = groupSize;
2220                                                 else
2221                                                         groupIndex++;
2222                                         }
2223                                 }
2224                                 else
2225                                         UseGroup = false;
2226
2227                                 for (int i = offset; i - offset < length; i++) {
2228                                         char c = format [i];
2229
2230                                         if (c == literal && c != '\0') {
2231                                                 literal = '\0';
2232                                                 continue;
2233                                         }
2234                                         if (literal != '\0') {
2235                                                 sb.Append (c);
2236                                                 continue;
2237                                         }
2238
2239                                         switch (c) {
2240                                         case '\\':
2241                                                 i++;
2242                                                 if (i - offset < length)
2243                                                         sb.Append (format [i]);
2244                                                 continue;
2245                                         case '\'':
2246                                         case '\"':
2247                                                 if (c == '\"' || c == '\'')
2248                                                         literal = c;
2249                                                 continue;
2250                                         case '#':
2251                                                 goto case '0';
2252                                         case '0':
2253                                                 if (integerArea) {
2254                                                         intSharpCounter++;
2255                                                         if (IntegerDigits - intSharpCounter < sb_int.Length + sb_int_index || c == '0')
2256                                                                 while (IntegerDigits - intSharpCounter + sb_int_index < sb_int.Length) {
2257                                                                         sb.Append (sb_int [sb_int_index++]);
2258                                                                         if (UseGroup && --intLen > 0 && --counter == 0) {
2259                                                                                 sb.Append (groupSeparator);
2260                                                                                 if (--groupIndex < groups.Length && groupIndex >= 0)
2261                                                                                         groupSize = groups [groupIndex];
2262                                                                                 counter = groupSize;
2263                                                                         }
2264                                                                 }
2265                                                         break;
2266                                                 }
2267                                                 else if (decimalArea) {
2268                                                         if (sb_dec_index < sb_dec.Length)
2269                                                                 sb.Append (sb_dec [sb_dec_index++]);
2270                                                         break;
2271                                                 }
2272
2273                                                 sb.Append (c);
2274                                                 break;
2275                                         case 'e':
2276                                         case 'E':
2277                                                 if (sb_exp == null || !UseExponent) {
2278                                                         sb.Append (c);
2279                                                         break;
2280                                                 }
2281
2282                                                 bool flag1 = true;
2283                                                 bool flag2 = false;
2284
2285                                                 int q;
2286                                                 for (q = i + 1; q - offset < length; q++) {
2287                                                         if (format [q] == '0') {
2288                                                                 flag2 = true;
2289                                                                 continue;
2290                                                         }
2291                                                         if (q == i + 1 && (format [q] == '+' || format [q] == '-'))
2292                                                                 continue;
2293                                                         if (!flag2)
2294                                                                 flag1 = false;
2295                                                         break;
2296                                                 }
2297
2298                                                 if (flag1) {
2299                                                         i = q - 1;
2300                                                         integerArea = (DecimalPointPos < 0);
2301                                                         decimalArea = !integerArea;
2302
2303                                                         sb.Append (c);
2304                                                         sb.Append (sb_exp);
2305                                                         sb_exp = null;
2306                                                 }
2307                                                 else
2308                                                         sb.Append (c);
2309
2310                                                 break;
2311                                         case '.':
2312                                                 if (DecimalPointPos == i) {
2313                                                         if (DecimalDigits > 0) {
2314                                                                 while (sb_int_index < sb_int.Length)
2315                                                                         sb.Append (sb_int [sb_int_index++]);
2316                                                         }
2317                                                         if (sb_dec.Length > 0)
2318                                                                 sb.Append (nfi.NumberDecimalSeparator);
2319                                                 }
2320                                                 integerArea = false;
2321                                                 decimalArea = true;
2322                                                 break;
2323                                         case ',':
2324                                                 break;
2325                                         case '%':
2326                                                 sb.Append (nfi.PercentSymbol);
2327                                                 break;
2328                                         case '\u2030':
2329                                                 sb.Append (nfi.PerMilleSymbol);
2330                                                 break;
2331                                         default:
2332                                                 sb.Append (c);
2333                                                 break;
2334                                         }
2335                                 }
2336
2337                                 if (!positive)
2338                                         sb.Insert (0, nfi.NegativeSign);
2339
2340                                 return sb.ToString ();
2341                         }
2342                 }
2343
2344                 #endregion
2345         }
2346 }