Terraria v1.4.4.9
Terraria source code documentation
Loading...
Searching...
No Matches
FormatProvider.cs
Go to the documentation of this file.
3using System.Text;
4
6
7internal static class FormatProvider
8{
9 private static class Number
10 {
11 internal struct NumberBuffer
12 {
13 public int precision;
14
15 public int scale;
16
17 public bool sign;
18
19 public unsafe char* overrideDigits;
20
21 public unsafe char* digits => overrideDigits;
22 }
23
24 private static readonly string[] s_posCurrencyFormats = new string[4] { "$#", "#$", "$ #", "# $" };
25
26 private static readonly string[] s_negCurrencyFormats = new string[17]
27 {
28 "($#)", "-$#", "$-#", "$#-", "(#$)", "-#$", "#-$", "#$-", "-# $", "-$ #",
29 "# $-", "$ #-", "$ -#", "#- $", "($ #)", "(# $)", "$- #"
30 };
31
32 private static readonly string[] s_posPercentFormats = new string[4] { "# %", "#%", "%#", "% #" };
33
34 private static readonly string[] s_negPercentFormats = new string[12]
35 {
36 "-# %", "-#%", "-%#", "%-#", "%#-", "#-%", "#%-", "-% #", "# %-", "% #-",
37 "% -#", "#- %"
38 };
39
40 private static readonly string[] s_negNumberFormats = new string[5] { "(#)", "-#", "- #", "#-", "# -" };
41
42 private static bool IsWhite(char ch)
43 {
44 if (ch != ' ')
45 {
46 if (ch >= '\t')
47 {
48 return ch <= '\r';
49 }
50 return false;
51 }
52 return true;
53 }
54
55 private unsafe static char* MatchChars(char* p, char* pEnd, string str)
56 {
57 fixed (char* str2 = str)
58 {
59 return MatchChars(p, pEnd, str2);
60 }
61 }
62
63 private unsafe static char* MatchChars(char* p, char* pEnd, char* str)
64 {
65 if (*str == '\0')
66 {
67 return null;
68 }
69 while (true)
70 {
71 char c = ((p < pEnd) ? (*p) : '\0');
72 if (c != *str && (*str != '\u00a0' || c != ' '))
73 {
74 break;
75 }
76 p++;
77 str++;
78 if (*str == '\0')
79 {
80 return p;
81 }
82 }
83 return null;
84 }
85
86 [MethodImpl(MethodImplOptions.AggressiveInlining)]
88 {
89 string negativeSign = info.NegativeSign;
90 bool flag = negativeSign.Length == 1;
91 bool flag2 = flag;
92 if (flag2)
93 {
94 bool flag3;
95 switch (negativeSign[0])
96 {
97 case '‒':
98 case '⁻':
99 case '₋':
100 case '−':
101 case '➖':
102 case '﹣':
103 case '-':
104 flag3 = true;
105 break;
106 default:
107 flag3 = false;
108 break;
109 }
110 flag2 = flag3;
111 }
112 return flag2;
113 }
114
115 [MethodImpl(MethodImplOptions.AggressiveInlining)]
116 private unsafe static char* MatchNegativeSignChars(char* p, char* pEnd, string negativeSign, bool allowHyphenDuringParsing)
117 {
118 char* ptr = MatchChars(p, pEnd, negativeSign);
119 if (ptr == null && allowHyphenDuringParsing && p < pEnd && *p == '-')
120 {
121 ptr = p + 1;
122 }
123 return ptr;
124 }
125
126 private unsafe static bool ParseNumber(ref char* str, char* strEnd, NumberStyles options, ref NumberBuffer number, StringBuilder sb, NumberFormatInfo numfmt, bool parseDecimal)
127 {
128 number.scale = 0;
129 number.sign = false;
130 string text = null;
131 bool allowHyphenDuringParsing = AllowHyphenDuringParsing(numfmt);
132 bool flag = false;
133 string str2;
134 string str3;
135 if ((options & NumberStyles.AllowCurrencySymbol) != 0)
136 {
137 text = numfmt.CurrencySymbol;
138 str2 = numfmt.CurrencyDecimalSeparator;
139 str3 = numfmt.CurrencyGroupSeparator;
140 flag = true;
141 }
142 else
143 {
144 str2 = numfmt.NumberDecimalSeparator;
145 str3 = numfmt.NumberGroupSeparator;
146 }
147 int num = 0;
148 bool flag2 = sb != null;
149 int num2 = (flag2 ? int.MaxValue : 32);
150 char* ptr = str;
151 char c = ((ptr < strEnd) ? (*ptr) : '\0');
152 char* digits = number.digits;
153 while (true)
154 {
155 if (!IsWhite(c) || (options & NumberStyles.AllowLeadingWhite) == 0 || (((uint)num & (true ? 1u : 0u)) != 0 && (num & 0x20) == 0 && numfmt.NumberNegativePattern != 2))
156 {
157 char* ptr2;
158 if ((options & NumberStyles.AllowLeadingSign) != 0 && (num & 1) == 0 && ((ptr2 = MatchChars(ptr, strEnd, numfmt.PositiveSign)) != null || ((ptr2 = MatchNegativeSignChars(ptr, strEnd, numfmt.NegativeSign, allowHyphenDuringParsing)) != null && (number.sign = true))))
159 {
160 num |= 1;
161 ptr = ptr2 - 1;
162 }
163 else if (c == '(' && (options & NumberStyles.AllowParentheses) != 0 && (num & 1) == 0)
164 {
165 num |= 3;
166 number.sign = true;
167 }
168 else
169 {
170 if (text == null || (ptr2 = MatchChars(ptr, strEnd, text)) == null)
171 {
172 break;
173 }
174 num |= 0x20;
175 text = null;
176 ptr = ptr2 - 1;
177 }
178 }
179 c = ((++ptr < strEnd) ? (*ptr) : '\0');
180 }
181 int num3 = 0;
182 int num4 = 0;
183 while (true)
184 {
185 char* ptr2;
186 if ((c >= '0' && c <= '9') || ((options & NumberStyles.AllowHexSpecifier) != 0 && ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))))
187 {
188 num |= 4;
189 if (c != '0' || ((uint)num & 8u) != 0 || (flag2 && (options & NumberStyles.AllowHexSpecifier) != 0))
190 {
191 if (num3 < num2)
192 {
193 if (flag2)
194 {
195 sb.Append(c);
196 }
197 else
198 {
199 digits[num3++] = c;
200 }
201 if (c != '0' || parseDecimal)
202 {
203 num4 = num3;
204 }
205 }
206 if ((num & 0x10) == 0)
207 {
208 number.scale++;
209 }
210 num |= 8;
211 }
212 else if (((uint)num & 0x10u) != 0)
213 {
214 number.scale--;
215 }
216 }
217 else if ((options & NumberStyles.AllowDecimalPoint) != 0 && (num & 0x10) == 0 && ((ptr2 = MatchChars(ptr, strEnd, str2)) != null || (flag && (num & 0x20) == 0 && (ptr2 = MatchChars(ptr, strEnd, numfmt.NumberDecimalSeparator)) != null)))
218 {
219 num |= 0x10;
220 ptr = ptr2 - 1;
221 }
222 else
223 {
224 if ((options & NumberStyles.AllowThousands) == 0 || (num & 4) == 0 || ((uint)num & 0x10u) != 0 || ((ptr2 = MatchChars(ptr, strEnd, str3)) == null && (!flag || ((uint)num & 0x20u) != 0 || (ptr2 = MatchChars(ptr, strEnd, numfmt.NumberGroupSeparator)) == null)))
225 {
226 break;
227 }
228 ptr = ptr2 - 1;
229 }
230 c = ((++ptr < strEnd) ? (*ptr) : '\0');
231 }
232 bool flag3 = false;
233 number.precision = num4;
234 if (flag2)
235 {
236 sb.Append('\0');
237 }
238 else
239 {
240 digits[num4] = '\0';
241 }
242 if (((uint)num & 4u) != 0)
243 {
244 if ((c == 'E' || c == 'e') && (options & NumberStyles.AllowExponent) != 0)
245 {
246 char* ptr3 = ptr;
247 c = ((++ptr < strEnd) ? (*ptr) : '\0');
248 char* ptr2;
249 if ((ptr2 = MatchChars(ptr, strEnd, numfmt.PositiveSign)) != null)
250 {
251 c = (((ptr = ptr2) < strEnd) ? (*ptr) : '\0');
252 }
253 else if ((ptr2 = MatchNegativeSignChars(ptr, strEnd, numfmt.NegativeSign, allowHyphenDuringParsing)) != null)
254 {
255 c = (((ptr = ptr2) < strEnd) ? (*ptr) : '\0');
256 flag3 = true;
257 }
258 if (c >= '0' && c <= '9')
259 {
260 int num5 = 0;
261 do
262 {
263 num5 = num5 * 10 + (c - 48);
264 c = ((++ptr < strEnd) ? (*ptr) : '\0');
265 if (num5 > 1000)
266 {
267 num5 = 9999;
268 while (c >= '0' && c <= '9')
269 {
270 c = ((++ptr < strEnd) ? (*ptr) : '\0');
271 }
272 }
273 }
274 while (c >= '0' && c <= '9');
275 if (flag3)
276 {
277 num5 = -num5;
278 }
279 number.scale += num5;
280 }
281 else
282 {
283 ptr = ptr3;
284 c = ((ptr < strEnd) ? (*ptr) : '\0');
285 }
286 }
287 while (true)
288 {
289 if (!IsWhite(c) || (options & NumberStyles.AllowTrailingWhite) == 0)
290 {
291 char* ptr2;
292 if ((options & NumberStyles.AllowTrailingSign) != 0 && (num & 1) == 0 && ((ptr2 = MatchChars(ptr, strEnd, numfmt.PositiveSign)) != null || ((ptr2 = MatchNegativeSignChars(ptr, strEnd, numfmt.NegativeSign, allowHyphenDuringParsing)) != null && (number.sign = true))))
293 {
294 num |= 1;
295 ptr = ptr2 - 1;
296 }
297 else if (c == ')' && ((uint)num & 2u) != 0)
298 {
299 num &= -3;
300 }
301 else
302 {
303 if (text == null || (ptr2 = MatchChars(ptr, strEnd, text)) == null)
304 {
305 break;
306 }
307 text = null;
308 ptr = ptr2 - 1;
309 }
310 }
311 c = ((++ptr < strEnd) ? (*ptr) : '\0');
312 }
313 if ((num & 2) == 0)
314 {
315 if ((num & 8) == 0)
316 {
317 if (!parseDecimal)
318 {
319 number.scale = 0;
320 }
321 if ((num & 0x10) == 0)
322 {
323 number.sign = false;
324 }
325 }
326 str = ptr;
327 return true;
328 }
329 }
330 str = ptr;
331 return false;
332 }
333
334 private static bool TrailingZeros(ReadOnlySpan<char> s, int index)
335 {
336 for (int i = index; i < s.Length; i++)
337 {
338 if (s[i] != 0)
339 {
340 return false;
341 }
342 }
343 return true;
344 }
345
346 internal unsafe static bool TryStringToNumber(ReadOnlySpan<char> str, NumberStyles options, ref NumberBuffer number, StringBuilder sb, NumberFormatInfo numfmt, bool parseDecimal)
347 {
348 fixed (char* ptr = &MemoryMarshal.GetReference(str))
349 {
350 char* str2 = ptr;
351 if (!ParseNumber(ref str2, str2 + str.Length, options, ref number, sb, numfmt, parseDecimal) || (str2 - ptr < str.Length && !TrailingZeros(str, (int)(str2 - ptr))))
352 {
353 return false;
354 }
355 }
356 return true;
357 }
358
359 internal unsafe static void Int32ToDecChars(char* buffer, ref int index, uint value, int digits)
360 {
361 while (--digits >= 0 || value != 0)
362 {
363 buffer[--index] = (char)(value % 10 + 48);
364 value /= 10;
365 }
366 }
367
368 internal static char ParseFormatSpecifier(ReadOnlySpan<char> format, out int digits)
369 {
370 char c = '\0';
371 if (format.Length > 0)
372 {
373 c = format[0];
374 if ((uint)(c - 65) <= 25u || (uint)(c - 97) <= 25u)
375 {
376 if (format.Length == 1)
377 {
378 digits = -1;
379 return c;
380 }
381 if (format.Length == 2)
382 {
383 int num = format[1] - 48;
384 if ((uint)num < 10u)
385 {
386 digits = num;
387 return c;
388 }
389 }
390 else if (format.Length == 3)
391 {
392 int num2 = format[1] - 48;
393 int num3 = format[2] - 48;
394 if ((uint)num2 < 10u && (uint)num3 < 10u)
395 {
396 digits = num2 * 10 + num3;
397 return c;
398 }
399 }
400 int num4 = 0;
401 int num5 = 1;
402 while (num5 < format.Length && (uint)(format[num5] - 48) < 10u)
403 {
404 int num6 = num4 * 10 + format[num5++] - 48;
405 if (num6 < num4)
406 {
408 }
409 num4 = num6;
410 }
411 if (num5 == format.Length || format[num5] == '\0')
412 {
413 digits = num4;
414 return c;
415 }
416 }
417 }
418 digits = -1;
419 if (format.Length != 0 && c != 0)
420 {
421 return '\0';
422 }
423 return 'G';
424 }
425
426 internal unsafe static void NumberToString(ref System.Text.ValueStringBuilder sb, ref NumberBuffer number, char format, int nMaxDigits, NumberFormatInfo info, bool isDecimal)
427 {
428 int num = -1;
429 switch (format)
430 {
431 case 'C':
432 case 'c':
433 num = ((nMaxDigits >= 0) ? nMaxDigits : info.CurrencyDecimalDigits);
434 if (nMaxDigits < 0)
435 {
436 nMaxDigits = info.CurrencyDecimalDigits;
437 }
438 RoundNumber(ref number, number.scale + nMaxDigits);
439 FormatCurrency(ref sb, ref number, num, nMaxDigits, info);
440 break;
441 case 'F':
442 case 'f':
443 if (nMaxDigits < 0)
444 {
445 nMaxDigits = (num = info.NumberDecimalDigits);
446 }
447 else
448 {
449 num = nMaxDigits;
450 }
451 RoundNumber(ref number, number.scale + nMaxDigits);
452 if (number.sign)
453 {
454 sb.Append(info.NegativeSign);
455 }
456 FormatFixed(ref sb, ref number, num, nMaxDigits, info, null, info.NumberDecimalSeparator, null);
457 break;
458 case 'N':
459 case 'n':
460 if (nMaxDigits < 0)
461 {
462 nMaxDigits = (num = info.NumberDecimalDigits);
463 }
464 else
465 {
466 num = nMaxDigits;
467 }
468 RoundNumber(ref number, number.scale + nMaxDigits);
469 FormatNumber(ref sb, ref number, num, nMaxDigits, info);
470 break;
471 case 'E':
472 case 'e':
473 if (nMaxDigits < 0)
474 {
475 nMaxDigits = (num = 6);
476 }
477 else
478 {
479 num = nMaxDigits;
480 }
481 nMaxDigits++;
482 RoundNumber(ref number, nMaxDigits);
483 if (number.sign)
484 {
485 sb.Append(info.NegativeSign);
486 }
487 FormatScientific(ref sb, ref number, num, nMaxDigits, info, format);
488 break;
489 case 'G':
490 case 'g':
491 {
492 bool flag = true;
493 if (nMaxDigits < 1)
494 {
495 if (isDecimal && nMaxDigits == -1)
496 {
497 nMaxDigits = (num = 29);
498 flag = false;
499 }
500 else
501 {
502 nMaxDigits = (num = number.precision);
503 }
504 }
505 else
506 {
507 num = nMaxDigits;
508 }
509 if (flag)
510 {
511 RoundNumber(ref number, nMaxDigits);
512 }
513 else if (isDecimal && *number.digits == '\0')
514 {
515 number.sign = false;
516 }
517 if (number.sign)
518 {
519 sb.Append(info.NegativeSign);
520 }
521 FormatGeneral(ref sb, ref number, num, nMaxDigits, info, (char)(format - 2), !flag);
522 break;
523 }
524 case 'P':
525 case 'p':
526 if (nMaxDigits < 0)
527 {
528 nMaxDigits = (num = info.PercentDecimalDigits);
529 }
530 else
531 {
532 num = nMaxDigits;
533 }
534 number.scale += 2;
535 RoundNumber(ref number, number.scale + nMaxDigits);
536 FormatPercent(ref sb, ref number, num, nMaxDigits, info);
537 break;
538 default:
540 }
541 }
542
543 private static void FormatCurrency(ref System.Text.ValueStringBuilder sb, ref NumberBuffer number, int nMinDigits, int nMaxDigits, NumberFormatInfo info)
544 {
545 string text = (number.sign ? s_negCurrencyFormats[info.CurrencyNegativePattern] : s_posCurrencyFormats[info.CurrencyPositivePattern]);
546 string text2 = text;
547 foreach (char c in text2)
548 {
549 switch (c)
550 {
551 case '#':
552 FormatFixed(ref sb, ref number, nMinDigits, nMaxDigits, info, info.CurrencyGroupSizes, info.CurrencyDecimalSeparator, info.CurrencyGroupSeparator);
553 break;
554 case '-':
555 sb.Append(info.NegativeSign);
556 break;
557 case '$':
558 sb.Append(info.CurrencySymbol);
559 break;
560 default:
561 sb.Append(c);
562 break;
563 }
564 }
565 }
566
567 private unsafe static void FormatFixed(ref System.Text.ValueStringBuilder sb, ref NumberBuffer number, int nMinDigits, int nMaxDigits, NumberFormatInfo info, int[] groupDigits, string sDecimal, string sGroup)
568 {
569 int scale = number.scale;
570 char* ptr = number.digits;
572 if (scale > 0)
573 {
574 if (groupDigits != null)
575 {
576 int num = 0;
577 int num2 = groupDigits[num];
578 int num3 = groupDigits.Length;
579 int num4 = scale;
580 int length2 = sGroup.Length;
581 int num5 = 0;
582 if (num3 != 0)
583 {
584 while (scale > num2 && groupDigits[num] != 0)
585 {
586 num4 += length2;
587 if (num < num3 - 1)
588 {
589 num++;
590 }
591 num2 += groupDigits[num];
592 if (num2 < 0 || num4 < 0)
593 {
594 throw new ArgumentOutOfRangeException();
595 }
596 }
597 num5 = ((num2 != 0) ? groupDigits[0] : 0);
598 }
599 char* ptr2 = stackalloc char[num4];
600 num = 0;
601 int num6 = 0;
602 int num7 = ((scale < length) ? scale : length);
603 char* ptr3 = ptr2 + num4 - 1;
604 for (int num8 = scale - 1; num8 >= 0; num8--)
605 {
606 *(ptr3--) = ((num8 < num7) ? ptr[num8] : '0');
607 if (num5 > 0)
608 {
609 num6++;
610 if (num6 == num5 && num8 != 0)
611 {
612 for (int num9 = length2 - 1; num9 >= 0; num9--)
613 {
614 *(ptr3--) = sGroup[num9];
615 }
616 if (num < num3 - 1)
617 {
618 num++;
619 num5 = groupDigits[num];
620 }
621 num6 = 0;
622 }
623 }
624 }
625 sb.Append(ptr2, num4);
626 ptr += num7;
627 }
628 else
629 {
630 int num10 = Math.Min(length, scale);
631 sb.Append(ptr, num10);
632 ptr += num10;
633 if (scale > length)
634 {
635 sb.Append('0', scale - length);
636 }
637 }
638 }
639 else
640 {
641 sb.Append('0');
642 }
643 if (nMaxDigits > 0)
644 {
645 sb.Append(sDecimal);
646 if (scale < 0 && nMaxDigits > 0)
647 {
648 int num11 = Math.Min(-scale, nMaxDigits);
649 sb.Append('0', num11);
650 scale += num11;
651 nMaxDigits -= num11;
652 }
653 while (nMaxDigits > 0)
654 {
655 sb.Append((*ptr != 0) ? (*(ptr++)) : '0');
656 nMaxDigits--;
657 }
658 }
659 }
660
661 private static void FormatNumber(ref System.Text.ValueStringBuilder sb, ref NumberBuffer number, int nMinDigits, int nMaxDigits, NumberFormatInfo info)
662 {
663 string text = (number.sign ? s_negNumberFormats[info.NumberNegativePattern] : "#");
664 string text2 = text;
665 foreach (char c in text2)
666 {
667 switch (c)
668 {
669 case '#':
670 FormatFixed(ref sb, ref number, nMinDigits, nMaxDigits, info, info.NumberGroupSizes, info.NumberDecimalSeparator, info.NumberGroupSeparator);
671 break;
672 case '-':
673 sb.Append(info.NegativeSign);
674 break;
675 default:
676 sb.Append(c);
677 break;
678 }
679 }
680 }
681
682 private unsafe static void FormatScientific(ref System.Text.ValueStringBuilder sb, ref NumberBuffer number, int nMinDigits, int nMaxDigits, NumberFormatInfo info, char expChar)
683 {
684 char* digits = number.digits;
685 sb.Append((*digits != 0) ? (*(digits++)) : '0');
686 if (nMaxDigits != 1)
687 {
688 sb.Append(info.NumberDecimalSeparator);
689 }
690 while (--nMaxDigits > 0)
691 {
692 sb.Append((*digits != 0) ? (*(digits++)) : '0');
693 }
694 int value = ((*number.digits != 0) ? (number.scale - 1) : 0);
695 FormatExponent(ref sb, info, value, expChar, 3, positiveSign: true);
696 }
697
698 private unsafe static void FormatExponent(ref System.Text.ValueStringBuilder sb, NumberFormatInfo info, int value, char expChar, int minDigits, bool positiveSign)
699 {
700 sb.Append(expChar);
701 if (value < 0)
702 {
703 sb.Append(info.NegativeSign);
704 value = -value;
705 }
706 else if (positiveSign)
707 {
708 sb.Append(info.PositiveSign);
709 }
710 char* ptr = stackalloc char[11];
711 int index = 10;
712 Int32ToDecChars(ptr, ref index, (uint)value, minDigits);
713 int num = 10 - index;
714 while (--num >= 0)
715 {
716 sb.Append(ptr[index++]);
717 }
718 }
719
720 private unsafe static void FormatGeneral(ref System.Text.ValueStringBuilder sb, ref NumberBuffer number, int nMinDigits, int nMaxDigits, NumberFormatInfo info, char expChar, bool bSuppressScientific)
721 {
722 int i = number.scale;
723 bool flag = false;
724 if (!bSuppressScientific && (i > nMaxDigits || i < -3))
725 {
726 i = 1;
727 flag = true;
728 }
729 char* digits = number.digits;
730 if (i > 0)
731 {
732 do
733 {
734 sb.Append((*digits != 0) ? (*(digits++)) : '0');
735 }
736 while (--i > 0);
737 }
738 else
739 {
740 sb.Append('0');
741 }
742 if (*digits != 0 || i < 0)
743 {
744 sb.Append(info.NumberDecimalSeparator);
745 for (; i < 0; i++)
746 {
747 sb.Append('0');
748 }
749 while (*digits != 0)
750 {
751 sb.Append(*(digits++));
752 }
753 }
754 if (flag)
755 {
756 FormatExponent(ref sb, info, number.scale - 1, expChar, 2, positiveSign: true);
757 }
758 }
759
760 private static void FormatPercent(ref System.Text.ValueStringBuilder sb, ref NumberBuffer number, int nMinDigits, int nMaxDigits, NumberFormatInfo info)
761 {
762 string text = (number.sign ? s_negPercentFormats[info.PercentNegativePattern] : s_posPercentFormats[info.PercentPositivePattern]);
763 string text2 = text;
764 foreach (char c in text2)
765 {
766 switch (c)
767 {
768 case '#':
769 FormatFixed(ref sb, ref number, nMinDigits, nMaxDigits, info, info.PercentGroupSizes, info.PercentDecimalSeparator, info.PercentGroupSeparator);
770 break;
771 case '-':
772 sb.Append(info.NegativeSign);
773 break;
774 case '%':
775 sb.Append(info.PercentSymbol);
776 break;
777 default:
778 sb.Append(c);
779 break;
780 }
781 }
782 }
783
784 private unsafe static void RoundNumber(ref NumberBuffer number, int pos)
785 {
786 char* digits = number.digits;
787 int i;
788 for (i = 0; i < pos && digits[i] != 0; i++)
789 {
790 }
791 if (i == pos && digits[i] >= '5')
792 {
793 while (i > 0 && digits[i - 1] == '9')
794 {
795 i--;
796 }
797 if (i > 0)
798 {
799 char* num = digits + (i - 1);
800 *num = (char)(*num + 1);
801 }
802 else
803 {
804 number.scale++;
805 *digits = '1';
806 i = 1;
807 }
808 }
809 else
810 {
811 while (i > 0 && digits[i - 1] == '0')
812 {
813 i--;
814 }
815 }
816 if (i == 0)
817 {
818 number.scale = 0;
819 number.sign = false;
820 }
821 digits[i] = '\0';
822 }
823
824 private unsafe static int FindSection(ReadOnlySpan<char> format, int section)
825 {
826 if (section == 0)
827 {
828 return 0;
829 }
830 fixed (char* ptr = &MemoryMarshal.GetReference(format))
831 {
832 int num = 0;
833 while (true)
834 {
835 if (num >= format.Length)
836 {
837 return 0;
838 }
839 char c;
840 char c2 = (c = ptr[num++]);
841 if ((uint)c2 <= 34u)
842 {
843 if (c2 == '\0')
844 {
845 break;
846 }
847 if (c2 != '"')
848 {
849 continue;
850 }
851 }
852 else if (c2 != '\'')
853 {
854 switch (c2)
855 {
856 default:
857 continue;
858 case '\\':
859 if (num < format.Length && ptr[num] != 0)
860 {
861 num++;
862 }
863 continue;
864 case ';':
865 break;
866 }
867 if (--section == 0)
868 {
869 if (num >= format.Length || ptr[num] == '\0' || ptr[num] == ';')
870 {
871 break;
872 }
873 return num;
874 }
875 continue;
876 }
877 while (num < format.Length && ptr[num] != 0 && ptr[num++] != c)
878 {
879 }
880 }
881 return 0;
882 }
883 }
884
886 {
887 int num = 0;
888 char* digits = number.digits;
889 int num2 = FindSection(format, (*digits == '\0') ? 2 : (number.sign ? 1 : 0));
890 int num3;
891 int num4;
892 bool flag;
893 bool flag2;
894 int num5;
895 int num6;
896 int num9;
897 while (true)
898 {
899 num3 = 0;
900 num4 = -1;
901 num5 = int.MaxValue;
902 num6 = 0;
903 flag = false;
904 int num7 = -1;
905 flag2 = false;
906 int num8 = 0;
907 num9 = num2;
908 fixed (char* ptr = &MemoryMarshal.GetReference(format))
909 {
910 char c;
911 while (num9 < format.Length && (c = ptr[num9++]) != 0)
912 {
913 switch (c)
914 {
915 case ';':
916 break;
917 case '#':
918 num3++;
919 continue;
920 case '0':
921 if (num5 == int.MaxValue)
922 {
923 num5 = num3;
924 }
925 num3++;
926 num6 = num3;
927 continue;
928 case '.':
929 if (num4 < 0)
930 {
931 num4 = num3;
932 }
933 continue;
934 case ',':
935 if (num3 <= 0 || num4 >= 0)
936 {
937 continue;
938 }
939 if (num7 >= 0)
940 {
941 if (num7 == num3)
942 {
943 num++;
944 continue;
945 }
946 flag2 = true;
947 }
948 num7 = num3;
949 num = 1;
950 continue;
951 case '%':
952 num8 += 2;
953 continue;
954 case '‰':
955 num8 += 3;
956 continue;
957 case '"':
958 case '\'':
959 while (num9 < format.Length && ptr[num9] != 0 && ptr[num9++] != c)
960 {
961 }
962 continue;
963 case '\\':
964 if (num9 < format.Length && ptr[num9] != 0)
965 {
966 num9++;
967 }
968 continue;
969 case 'E':
970 case 'e':
971 if ((num9 < format.Length && ptr[num9] == '0') || (num9 + 1 < format.Length && (ptr[num9] == '+' || ptr[num9] == '-') && ptr[num9 + 1] == '0'))
972 {
973 while (++num9 < format.Length && ptr[num9] == '0')
974 {
975 }
976 flag = true;
977 }
978 continue;
979 default:
980 continue;
981 }
982 break;
983 }
984 }
985 if (num4 < 0)
986 {
987 num4 = num3;
988 }
989 if (num7 >= 0)
990 {
991 if (num7 == num4)
992 {
993 num8 -= num * 3;
994 }
995 else
996 {
997 flag2 = true;
998 }
999 }
1000 if (*digits != 0)
1001 {
1002 number.scale += num8;
1003 int pos = (flag ? num3 : (number.scale + num3 - num4));
1004 RoundNumber(ref number, pos);
1005 if (*digits != 0)
1006 {
1007 break;
1008 }
1009 num9 = FindSection(format, 2);
1010 if (num9 == num2)
1011 {
1012 break;
1013 }
1014 num2 = num9;
1015 continue;
1016 }
1017 number.sign = false;
1018 number.scale = 0;
1019 break;
1020 }
1021 num5 = ((num5 < num4) ? (num4 - num5) : 0);
1022 num6 = ((num6 > num4) ? (num4 - num6) : 0);
1023 int num10;
1024 int num11;
1025 if (flag)
1026 {
1027 num10 = num4;
1028 num11 = 0;
1029 }
1030 else
1031 {
1032 num10 = ((number.scale > num4) ? number.scale : num4);
1033 num11 = number.scale - num4;
1034 }
1035 num9 = num2;
1036 Span<int> span = stackalloc int[4];
1037 int num12 = -1;
1038 if (flag2 && info.NumberGroupSeparator.Length > 0)
1039 {
1040 int[] numberGroupSizes = info.NumberGroupSizes;
1041 int num13 = 0;
1042 int i = 0;
1043 int num14 = numberGroupSizes.Length;
1044 if (num14 != 0)
1045 {
1046 i = numberGroupSizes[num13];
1047 }
1048 int num15 = i;
1049 int num16 = num10 + ((num11 < 0) ? num11 : 0);
1050 for (int num17 = ((num5 > num16) ? num5 : num16); num17 > i; i += num15)
1051 {
1052 if (num15 == 0)
1053 {
1054 break;
1055 }
1056 num12++;
1057 if (num12 >= span.Length)
1058 {
1059 int[] array = new int[span.Length * 2];
1060 span.CopyTo(array);
1061 span = array;
1062 }
1063 span[num12] = i;
1064 if (num13 < num14 - 1)
1065 {
1066 num13++;
1067 num15 = numberGroupSizes[num13];
1068 }
1069 }
1070 }
1071 if (number.sign && num2 == 0)
1072 {
1073 sb.Append(info.NegativeSign);
1074 }
1075 bool flag3 = false;
1076 fixed (char* ptr3 = &MemoryMarshal.GetReference(format))
1077 {
1078 char* ptr2 = digits;
1079 char c;
1080 while (num9 < format.Length && (c = ptr3[num9++]) != 0 && c != ';')
1081 {
1082 if (num11 > 0 && (c == '#' || c == '.' || c == '0'))
1083 {
1084 while (num11 > 0)
1085 {
1086 sb.Append((*ptr2 != 0) ? (*(ptr2++)) : '0');
1087 if (flag2 && num10 > 1 && num12 >= 0 && num10 == span[num12] + 1)
1088 {
1089 sb.Append(info.NumberGroupSeparator);
1090 num12--;
1091 }
1092 num10--;
1093 num11--;
1094 }
1095 }
1096 switch (c)
1097 {
1098 case '#':
1099 case '0':
1100 if (num11 < 0)
1101 {
1102 num11++;
1103 c = ((num10 <= num5) ? '0' : '\0');
1104 }
1105 else
1106 {
1107 c = ((*ptr2 != 0) ? (*(ptr2++)) : ((num10 > num6) ? '0' : '\0'));
1108 }
1109 if (c != 0)
1110 {
1111 sb.Append(c);
1112 if (flag2 && num10 > 1 && num12 >= 0 && num10 == span[num12] + 1)
1113 {
1114 sb.Append(info.NumberGroupSeparator);
1115 num12--;
1116 }
1117 }
1118 num10--;
1119 break;
1120 case '.':
1121 if (!(num10 != 0 || flag3) && (num6 < 0 || (num4 < num3 && *ptr2 != 0)))
1122 {
1123 sb.Append(info.NumberDecimalSeparator);
1124 flag3 = true;
1125 }
1126 break;
1127 case '‰':
1128 sb.Append(info.PerMilleSymbol);
1129 break;
1130 case '%':
1131 sb.Append(info.PercentSymbol);
1132 break;
1133 case '"':
1134 case '\'':
1135 while (num9 < format.Length && ptr3[num9] != 0 && ptr3[num9] != c)
1136 {
1137 sb.Append(ptr3[num9++]);
1138 }
1139 if (num9 < format.Length && ptr3[num9] != 0)
1140 {
1141 num9++;
1142 }
1143 break;
1144 case '\\':
1145 if (num9 < format.Length && ptr3[num9] != 0)
1146 {
1147 sb.Append(ptr3[num9++]);
1148 }
1149 break;
1150 case 'E':
1151 case 'e':
1152 {
1153 bool positiveSign = false;
1154 int num18 = 0;
1155 if (flag)
1156 {
1157 if (num9 < format.Length && ptr3[num9] == '0')
1158 {
1159 num18++;
1160 }
1161 else if (num9 + 1 < format.Length && ptr3[num9] == '+' && ptr3[num9 + 1] == '0')
1162 {
1163 positiveSign = true;
1164 }
1165 else if (num9 + 1 >= format.Length || ptr3[num9] != '-' || ptr3[num9 + 1] != '0')
1166 {
1167 sb.Append(c);
1168 break;
1169 }
1170 while (++num9 < format.Length && ptr3[num9] == '0')
1171 {
1172 num18++;
1173 }
1174 if (num18 > 10)
1175 {
1176 num18 = 10;
1177 }
1178 int value = ((*digits != 0) ? (number.scale - num4) : 0);
1179 FormatExponent(ref sb, info, value, c, num18, positiveSign);
1180 flag = false;
1181 break;
1182 }
1183 sb.Append(c);
1184 if (num9 < format.Length)
1185 {
1186 if (ptr3[num9] == '+' || ptr3[num9] == '-')
1187 {
1188 sb.Append(ptr3[num9++]);
1189 }
1190 while (num9 < format.Length && ptr3[num9] == '0')
1191 {
1192 sb.Append(ptr3[num9++]);
1193 }
1194 }
1195 break;
1196 }
1197 default:
1198 sb.Append(c);
1199 break;
1200 case ',':
1201 break;
1202 }
1203 }
1204 }
1205 }
1206 }
1207
1208 internal unsafe static void FormatBigInteger(ref System.Text.ValueStringBuilder sb, int precision, int scale, bool sign, ReadOnlySpan<char> format, NumberFormatInfo numberFormatInfo, char[] digits, int startIndex)
1209 {
1210 fixed (char* ptr = digits)
1211 {
1212 Number.NumberBuffer number = default(Number.NumberBuffer);
1213 number.overrideDigits = ptr + startIndex;
1214 number.precision = precision;
1215 number.scale = scale;
1216 number.sign = sign;
1217 int digits2;
1218 char c = Number.ParseFormatSpecifier(format, out digits2);
1219 if (c != 0)
1220 {
1221 Number.NumberToString(ref sb, ref number, c, digits2, numberFormatInfo, isDecimal: false);
1222 }
1223 else
1224 {
1225 Number.NumberToStringFormat(ref sb, ref number, format, numberFormatInfo);
1226 }
1227 }
1228 }
1229
1230 internal unsafe static bool TryStringToBigInteger(ReadOnlySpan<char> s, NumberStyles styles, NumberFormatInfo numberFormatInfo, StringBuilder receiver, out int precision, out int scale, out bool sign)
1231 {
1232 Number.NumberBuffer number = default(Number.NumberBuffer);
1233 number.overrideDigits = (char*)1;
1234 if (!Number.TryStringToNumber(s, styles, ref number, receiver, numberFormatInfo, parseDecimal: false))
1235 {
1236 precision = 0;
1237 scale = 0;
1238 sign = false;
1239 return false;
1240 }
1241 precision = number.precision;
1242 scale = number.scale;
1243 sign = number.sign;
1244 return true;
1245 }
1246}
static unsafe char * MatchChars(char *p, char *pEnd, char *str)
static unsafe char * MatchNegativeSignChars(char *p, char *pEnd, string negativeSign, bool allowHyphenDuringParsing)
static unsafe bool TryStringToNumber(ReadOnlySpan< char > str, NumberStyles options, ref NumberBuffer number, StringBuilder sb, NumberFormatInfo numfmt, bool parseDecimal)
static unsafe void FormatScientific(ref System.Text.ValueStringBuilder sb, ref NumberBuffer number, int nMinDigits, int nMaxDigits, NumberFormatInfo info, char expChar)
static unsafe void NumberToString(ref System.Text.ValueStringBuilder sb, ref NumberBuffer number, char format, int nMaxDigits, NumberFormatInfo info, bool isDecimal)
static unsafe char * MatchChars(char *p, char *pEnd, string str)
static unsafe void FormatFixed(ref System.Text.ValueStringBuilder sb, ref NumberBuffer number, int nMinDigits, int nMaxDigits, NumberFormatInfo info, int[] groupDigits, string sDecimal, string sGroup)
static unsafe void FormatExponent(ref System.Text.ValueStringBuilder sb, NumberFormatInfo info, int value, char expChar, int minDigits, bool positiveSign)
static void FormatNumber(ref System.Text.ValueStringBuilder sb, ref NumberBuffer number, int nMinDigits, int nMaxDigits, NumberFormatInfo info)
static unsafe void Int32ToDecChars(char *buffer, ref int index, uint value, int digits)
static unsafe void RoundNumber(ref NumberBuffer number, int pos)
static unsafe bool ParseNumber(ref char *str, char *strEnd, NumberStyles options, ref NumberBuffer number, StringBuilder sb, NumberFormatInfo numfmt, bool parseDecimal)
static unsafe void NumberToStringFormat(ref System.Text.ValueStringBuilder sb, ref NumberBuffer number, ReadOnlySpan< char > format, NumberFormatInfo info)
static readonly string[] s_negNumberFormats
static char ParseFormatSpecifier(ReadOnlySpan< char > format, out int digits)
static void FormatPercent(ref System.Text.ValueStringBuilder sb, ref NumberBuffer number, int nMinDigits, int nMaxDigits, NumberFormatInfo info)
static bool AllowHyphenDuringParsing(NumberFormatInfo info)
static readonly string[] s_negCurrencyFormats
static void FormatCurrency(ref System.Text.ValueStringBuilder sb, ref NumberBuffer number, int nMinDigits, int nMaxDigits, NumberFormatInfo info)
static readonly string[] s_posPercentFormats
static unsafe int FindSection(ReadOnlySpan< char > format, int section)
static bool TrailingZeros(ReadOnlySpan< char > s, int index)
static readonly string[] s_posCurrencyFormats
static readonly string[] s_negPercentFormats
static unsafe void FormatGeneral(ref System.Text.ValueStringBuilder sb, ref NumberBuffer number, int nMinDigits, int nMaxDigits, NumberFormatInfo info, char expChar, bool bSuppressScientific)
static unsafe bool TryStringToBigInteger(ReadOnlySpan< char > s, NumberStyles styles, NumberFormatInfo numberFormatInfo, StringBuilder receiver, out int precision, out int scale, out bool sign)
static unsafe void FormatBigInteger(ref System.Text.ValueStringBuilder sb, int precision, int scale, bool sign, ReadOnlySpan< char > format, NumberFormatInfo numberFormatInfo, char[] digits, int startIndex)
static byte Min(byte val1, byte val2)
Definition Math.cs:912
static unsafe ReadOnlySpan< char > CreateReadOnlySpanFromNullTerminated(char *value)
static string Argument_BadFormatSpecifier
Definition SR.cs:488
Definition SR.cs:7
StringBuilder Append(char value, int repeatCount)
void CopyTo(Span< T > destination)
Definition Span.cs:224
int Length
Definition Span.cs:70