// Author:
// Derek Holden (dholden@draper.com)
// Bob Smith (bob@thestuff.net)
+// Mohammad DAMT (mdamt@cdl2000.com)
//
// (C) Derek Holden
// (C) Bob Smith http://www.thestuff.net
+// (c) 2003, PT Cakram Datalingga Duaribu http://www.cdl2000.com
+//
+
+//
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//
// Other than that this is totally ECMA compliant.
//
+using System.Runtime.InteropServices;
+
namespace System.Globalization {
+#if NET_2_0
+ [ComVisible (true)]
+#endif
[Serializable]
public sealed class NumberFormatInfo : ICloneable, IFormatProvider {
- private bool readOnly;
+ private bool isReadOnly;
+ // used for temporary storage. Used in InitPatterns ()
+ string decimalFormats;
+ string currencyFormats;
+ string percentFormats;
+ string digitPattern = "#";
+ string zeroPattern = "0";
// Currency Related Format Info
private int currencyDecimalDigits;
private int currencyPositivePattern;
private string currencySymbol;
- private string naNSymbol;
+ private string nanSymbol;
private string negativeInfinitySymbol;
private string negativeSign;
private string perMilleSymbol;
private string positiveInfinitySymbol;
private string positiveSign;
-
- internal NumberFormatInfo (int lcid)
+
+ string ansiCurrencySymbol; // TODO, MS.NET serializes this.
+ int m_dataItem; // Unused, but MS.NET serializes this.
+ bool m_useUserOverride; // Unused, but MS.NET serializes this.
+ bool validForParseAsNumber; // Unused, but MS.NET serializes this.
+ bool validForParseAsCurrency; // Unused, but MS.NET serializes this.
+#if NET_2_0
+ string[] nativeDigits = invariantNativeDigits;
+ int digitSubstitution = 1; // DigitShapes.None.
+
+ static string [] invariantNativeDigits = new string [] {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
+#endif
+
+ internal NumberFormatInfo (int lcid, bool read_only)
{
+ isReadOnly = read_only;
+
//FIXME: should add more LCID
// CultureInfo uses this one also.
if (lcid != 0x007F)
// The Invariant Culture Info ID.
case 0x007f:
- readOnly = false;
+ isReadOnly = false;
// Currency Related Format Info
currencyDecimalDigits = 2;
currencyPositivePattern = 0;
currencySymbol = "$";
- naNSymbol = "NaN";
+ nanSymbol = "NaN";
negativeInfinitySymbol = "-Infinity";
negativeSign = "-";
numberDecimalSeparator = ".";
numberGroupSeparator = ",";
numberGroupSizes = new int[1] { 3 };
- numberNegativePattern = 0;
+ numberNegativePattern = 1;
// Percent Related Format Info
percentDecimalDigits = 2;
break;
}
}
+
+ internal NumberFormatInfo (bool read_only) : this (0x007f, read_only)
+ {
+ }
- public NumberFormatInfo () : this (0x007f)
+ public NumberFormatInfo () : this (false)
{
}
-
+
+ // this is called by mono/mono/metadata/locales.c
+ void InitPatterns ()
+ {
+ string [] partOne, partTwo;
+ string [] posNeg = decimalFormats.Split (new char [1] {';'}, 2);
+
+ if (posNeg.Length == 2) {
+
+ partOne = posNeg [0].Split (new char [1] {'.'}, 2);
+
+ if (partOne.Length == 2) {
+ // assumed same for both positive and negative
+ // decimal digit side
+ numberDecimalDigits = 0;
+ for (int i = 0; i < partOne [1].Length; i ++) {
+ if (partOne [1][i] == digitPattern [0]) {
+ numberDecimalDigits ++;
+ } else
+ break;
+ }
+
+ // decimal grouping side
+ partTwo = partOne [0].Split (',');
+ if (partTwo.Length > 1) {
+ numberGroupSizes = new int [partTwo.Length - 1];
+ for (int i = 0; i < numberGroupSizes.Length; i ++) {
+ string pat = partTwo [i + 1];
+ numberGroupSizes [i] = pat.Length;
+ }
+ } else {
+ numberGroupSizes = new int [1] { 0 };
+ }
+
+ if (posNeg [1].StartsWith ("(") && posNeg [1].EndsWith (")")) {
+ numberNegativePattern = 0;
+ } else if (posNeg [1].StartsWith ("- ")) {
+ numberNegativePattern = 2;
+ } else if (posNeg [1].StartsWith ("-")) {
+ numberNegativePattern = 1;
+ } else if (posNeg [1].EndsWith (" -")) {
+ numberNegativePattern = 4;
+ } else if (posNeg [1].EndsWith ("-")) {
+ numberNegativePattern = 3;
+ } else {
+ numberNegativePattern = 1;
+ }
+ }
+ }
+
+ posNeg = currencyFormats.Split (new char [1] {';'}, 2);
+ if (posNeg.Length == 2) {
+ partOne = posNeg [0].Split (new char [1] {'.'}, 2);
+
+ if (partOne.Length == 2) {
+ // assumed same for both positive and negative
+ // decimal digit side
+ currencyDecimalDigits = 0;
+ for (int i = 0; i < partOne [1].Length; i ++) {
+ if (partOne [1][i] == zeroPattern [0])
+ currencyDecimalDigits ++;
+ else
+ break;
+ }
+
+ // decimal grouping side
+ partTwo = partOne [0].Split (',');
+ if (partTwo.Length > 1) {
+ currencyGroupSizes = new int [partTwo.Length - 1];
+ for (int i = 0; i < currencyGroupSizes.Length; i ++) {
+ string pat = partTwo [i + 1];
+ currencyGroupSizes [i] = pat.Length;
+ }
+ } else {
+ currencyGroupSizes = new int [1] { 0 };
+ }
+
+ if (posNeg [1].StartsWith ("(\u00a4 ") && posNeg [1].EndsWith (")")) {
+ currencyNegativePattern = 14;
+ } else if (posNeg [1].StartsWith ("(\u00a4") && posNeg [1].EndsWith (")")) {
+ currencyNegativePattern = 0;
+ } else if (posNeg [1].StartsWith ("\u00a4 ") && posNeg [1].EndsWith ("-")) {
+ currencyNegativePattern = 11;
+ } else if (posNeg [1].StartsWith ("\u00a4") && posNeg [1].EndsWith ("-")) {
+ currencyNegativePattern = 3;
+ } else if (posNeg [1].StartsWith ("(") && posNeg [1].EndsWith (" \u00a4")) {
+ currencyNegativePattern = 15;
+ } else if (posNeg [1].StartsWith ("(") && posNeg [1].EndsWith ("\u00a4")) {
+ currencyNegativePattern = 4;
+ } else if (posNeg [1].StartsWith ("-") && posNeg [1].EndsWith (" \u00a4")) {
+ currencyNegativePattern = 8;
+ } else if (posNeg [1].StartsWith ("-") && posNeg [1].EndsWith ("\u00a4")) {
+ currencyNegativePattern = 5;
+ } else if (posNeg [1].StartsWith ("-\u00a4 ")) {
+ currencyNegativePattern = 9;
+ } else if (posNeg [1].StartsWith ("-\u00a4")) {
+ currencyNegativePattern = 1;
+ } else if (posNeg [1].StartsWith ("\u00a4 -")) {
+ currencyNegativePattern = 12;
+ } else if (posNeg [1].StartsWith ("\u00a4-")) {
+ currencyNegativePattern = 2;
+ } else if (posNeg [1].EndsWith (" \u00a4-")) {
+ currencyNegativePattern = 10;
+ } else if (posNeg [1].EndsWith ("\u00a4-")) {
+ currencyNegativePattern = 7;
+ } else if (posNeg [1].EndsWith ("- \u00a4")) {
+ currencyNegativePattern = 13;
+ } else if (posNeg [1].EndsWith ("-\u00a4")) {
+ currencyNegativePattern = 6;
+ } else {
+ currencyNegativePattern = 0;
+ }
+
+ if (posNeg [0].StartsWith ("\u00a4 ")) {
+ currencyPositivePattern = 2;
+ } else if (posNeg [0].StartsWith ("\u00a4")) {
+ currencyPositivePattern = 0;
+ } else if (posNeg [0].EndsWith (" \u00a4")) {
+ currencyPositivePattern = 3;
+ } else if (posNeg [0].EndsWith ("\u00a4")) {
+ currencyPositivePattern = 1;
+ } else {
+ currencyPositivePattern = 0;
+ }
+ }
+ }
+
+ // we don't have percentNegativePattern in CLDR so
+ // the percentNegativePattern are just guesses
+ if (percentFormats.StartsWith ("%")) {
+ percentPositivePattern = 2;
+ percentNegativePattern = 2;
+ } else if (percentFormats.EndsWith (" %")) {
+ percentPositivePattern = 0;
+ percentNegativePattern = 0;
+ } else if (percentFormats.EndsWith ("%")) {
+ percentPositivePattern = 1;
+ percentNegativePattern = 1;
+ } else {
+ percentPositivePattern = 0;
+ percentNegativePattern = 0;
+ }
+
+ partOne = percentFormats.Split (new char [1] {'.'}, 2);
+
+ if (partOne.Length == 2) {
+ // assumed same for both positive and negative
+ // decimal digit side
+ percentDecimalDigits = 0;
+ for (int i = 0; i < partOne [1].Length; i ++) {
+ if (partOne [1][i] == digitPattern [0])
+ percentDecimalDigits ++;
+ else
+ break;
+ }
+
+ // percent grouping side
+ partTwo = partOne [0].Split (',');
+ if (partTwo.Length > 1) {
+ percentGroupSizes = new int [partTwo.Length - 1];
+ for (int i = 0; i < percentGroupSizes.Length; i ++) {
+ string pat = partTwo [i + 1];
+ percentGroupSizes [i] = pat.Length;
+ }
+ } else {
+ percentGroupSizes = new int [1] { 0 };
+ }
+ }
+
+ }
+
// =========== Currency Format Properties =========== //
public int CurrencyDecimalDigits {
throw new ArgumentOutOfRangeException
("The value specified for the property is less than 0 or greater than 99");
- if (readOnly)
+ if (isReadOnly)
throw new InvalidOperationException
("The current instance is read-only and a set operation was attempted");
throw new ArgumentNullException
("The value specified for the property is a null reference");
- if (readOnly)
+ if (isReadOnly)
throw new InvalidOperationException
("The current instance is read-only and a set operation was attempted");
throw new ArgumentNullException
("The value specified for the property is a null reference");
- if (readOnly)
+ if (isReadOnly)
throw new InvalidOperationException
("The current instance is read-only and a set operation was attempted");
}
public int[] CurrencyGroupSizes {
+ get {
+ return (int []) RawCurrencyGroupSizes.Clone ();
+ }
+
+ set {
+ RawCurrencyGroupSizes = value;
+ }
+ }
+
+ internal int[] RawCurrencyGroupSizes {
get {
return currencyGroupSizes;
}
set {
- if (value == null || value.Length == 0)
+ if (value == null)
throw new ArgumentNullException
("The value specified for the property is a null reference");
- if (readOnly)
+ if (isReadOnly)
throw new InvalidOperationException
("The current instance is read-only and a set operation was attempted");
+ if (value.Length == 0) {
+ currencyGroupSizes = new int [0];
+ return;
+ }
+
// All elements except last need to be in range 1 - 9, last can be 0.
int last = value.Length - 1;
throw new ArgumentOutOfRangeException
("The value specified for the property is less than 0 or greater than 15");
- if (readOnly)
+ if (isReadOnly)
throw new InvalidOperationException
("The current instance is read-only and a set operation was attempted");
throw new ArgumentOutOfRangeException
("The value specified for the property is less than 0 or greater than 3");
- if (readOnly)
+ if (isReadOnly)
throw new InvalidOperationException
("The current instance is read-only and a set operation was attempted");
throw new ArgumentNullException
("The value specified for the property is a null reference");
- if (readOnly)
+ if (isReadOnly)
throw new InvalidOperationException
("The current instance is read-only and a set operation was attempted");
public static NumberFormatInfo CurrentInfo {
get {
- // This should be culture specific
- NumberFormatInfo nfi = new NumberFormatInfo ();
- nfi.readOnly = true;
+ NumberFormatInfo nfi = (NumberFormatInfo) System.Threading.Thread.CurrentThread.CurrentCulture.NumberFormat;
+ nfi.isReadOnly = true;
return nfi;
}
}
// This uses invariant info, which is same as in the constructor
NumberFormatInfo nfi = new NumberFormatInfo ();
nfi.NumberNegativePattern = 1;
- nfi.readOnly = true;
+ nfi.isReadOnly = true;
return nfi;
}
}
public bool IsReadOnly {
get {
- return readOnly;
+ return isReadOnly;
}
}
public string NaNSymbol {
get {
- return naNSymbol;
+ return nanSymbol;
}
set {
throw new ArgumentNullException
("The value specified for the property is a null reference");
- if (readOnly)
+ if (isReadOnly)
throw new InvalidOperationException
("The current instance is read-only and a set operation was attempted");
- naNSymbol = value;
+ nanSymbol = value;
+ }
+ }
+
+#if NET_2_0
+ [MonoNotSupported ("We don't have native digit info")]
+ [ComVisible (false)]
+ public string [] NativeDigits {
+ get { return nativeDigits; }
+ set {
+ if (value == null)
+ throw new ArgumentNullException ("value");
+ if (value.Length != 10)
+ throw new ArgumentException ("Argument array length must be 10");
+ foreach (string s in value)
+ if (String.IsNullOrEmpty (s))
+ throw new ArgumentException ("Argument array contains one or more null strings");
+ nativeDigits = value;
}
}
+
+ [MonoNotSupported ("We don't have native digit info")]
+ [ComVisible (false)]
+ public DigitShapes DigitSubstitution {
+ get { return (DigitShapes) digitSubstitution; }
+ set { digitSubstitution = (int) value; }
+ }
+#endif
public string NegativeInfinitySymbol {
get {
throw new ArgumentNullException
("The value specified for the property is a null reference");
- if (readOnly)
+ if (isReadOnly)
throw new InvalidOperationException
("The current instance is read-only and a set operation was attempted");
throw new ArgumentNullException
("The value specified for the property is a null reference");
- if (readOnly)
+ if (isReadOnly)
throw new InvalidOperationException
("The current instance is read-only and a set operation was attempted");
throw new ArgumentOutOfRangeException
("The value specified for the property is less than 0 or greater than 99");
- if (readOnly)
+ if (isReadOnly)
throw new InvalidOperationException
("The current instance is read-only and a set operation was attempted");
throw new ArgumentNullException
("The value specified for the property is a null reference");
- if (readOnly)
+ if (isReadOnly)
throw new InvalidOperationException
("The current instance is read-only and a set operation was attempted");
throw new ArgumentNullException
("The value specified for the property is a null reference");
- if (readOnly)
+ if (isReadOnly)
throw new InvalidOperationException
("The current instance is read-only and a set operation was attempted");
}
public int[] NumberGroupSizes {
+ get {
+ return (int []) RawNumberGroupSizes.Clone ();
+ }
+
+ set {
+ RawNumberGroupSizes = value;
+ }
+ }
+
+ internal int[] RawNumberGroupSizes {
get {
return numberGroupSizes;
}
set {
- if (value == null || value.Length == 0)
+ if (value == null)
throw new ArgumentNullException
("The value specified for the property is a null reference");
- if (readOnly)
+ if (isReadOnly)
throw new InvalidOperationException
("The current instance is read-only and a set operation was attempted");
+ if (value.Length == 0) {
+ numberGroupSizes = new int [0];
+ return;
+ }
// All elements except last need to be in range 1 - 9, last can be 0.
int last = value.Length - 1;
throw new ArgumentOutOfRangeException
("The value specified for the property is less than 0 or greater than 15");
- if (readOnly)
+ if (isReadOnly)
throw new InvalidOperationException
("The current instance is read-only and a set operation was attempted");
throw new ArgumentOutOfRangeException
("The value specified for the property is less than 0 or greater than 99");
- if (readOnly)
+ if (isReadOnly)
throw new InvalidOperationException
("The current instance is read-only and a set operation was attempted");
throw new ArgumentNullException
("The value specified for the property is a null reference");
- if (readOnly)
+ if (isReadOnly)
throw new InvalidOperationException
("The current instance is read-only and a set operation was attempted");
throw new ArgumentNullException
("The value specified for the property is a null reference");
- if (readOnly)
+ if (isReadOnly)
throw new InvalidOperationException
("The current instance is read-only and a set operation was attempted");
}
public int[] PercentGroupSizes {
+ get {
+ return (int []) RawPercentGroupSizes.Clone ();
+ }
+
+ set {
+ RawPercentGroupSizes = value;
+ }
+ }
+
+ internal int[] RawPercentGroupSizes {
get {
return percentGroupSizes;
}
set {
- if (value == null || value.Length == 0)
+ if (value == null)
throw new ArgumentNullException
("The value specified for the property is a null reference");
- if (readOnly)
+ if (isReadOnly)
throw new InvalidOperationException
("The current instance is read-only and a set operation was attempted");
+ if (this == CultureInfo.CurrentCulture.NumberFormat)
+ throw new Exception ("HERE the value was modified");
+
+ if (value.Length == 0) {
+ percentGroupSizes = new int [0];
+ return;
+ }
+
// All elements except last need to be in range 1 - 9, last can be 0.
int last = value.Length - 1;
throw new ArgumentOutOfRangeException
("The value specified for the property is less than 0 or greater than 15");
- if (readOnly)
+ if (isReadOnly)
throw new InvalidOperationException
("The current instance is read-only and a set operation was attempted");
throw new ArgumentOutOfRangeException
("The value specified for the property is less than 0 or greater than 3");
- if (readOnly)
+ if (isReadOnly)
throw new InvalidOperationException
("The current instance is read-only and a set operation was attempted");
throw new ArgumentNullException
("The value specified for the property is a null reference");
- if (readOnly)
+ if (isReadOnly)
throw new InvalidOperationException
("The current instance is read-only and a set operation was attempted");
throw new ArgumentNullException
("The value specified for the property is a null reference");
- if (readOnly)
+ if (isReadOnly)
throw new InvalidOperationException
("The current instance is read-only and a set operation was attempted");
throw new ArgumentNullException
("The value specified for the property is a null reference");
- if (readOnly)
+ if (isReadOnly)
throw new InvalidOperationException
("The current instance is read-only and a set operation was attempted");
throw new ArgumentNullException
("The value specified for the property is a null reference");
- if (readOnly)
+ if (isReadOnly)
throw new InvalidOperationException
("The current instance is read-only and a set operation was attempted");
public object GetFormat (Type formatType)
{
- return (formatType == GetType()) ? this : null;
+ return (formatType == typeof (NumberFormatInfo)) ? this : null;
}
public object Clone ()
{
NumberFormatInfo clone = (NumberFormatInfo) MemberwiseClone();
// clone is not read only
- clone.readOnly = false;
+ clone.isReadOnly = false;
return clone;
}
public static NumberFormatInfo ReadOnly (NumberFormatInfo nfi)
{
NumberFormatInfo copy = (NumberFormatInfo)nfi.Clone();
- copy.readOnly = true;
+ copy.isReadOnly = true;
return copy;
}