//
// System.Web.UI.WebControls.Unit.cs
//
// Authors:
// Miguel de Icaza (miguel@novell.com)
// Ben Maurer (bmaurer@ximian.com).
//
// Copyright (C) 2005 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.
//
using System.Globalization;
using System.ComponentModel;
using System.Security.Permissions;
using System.Web.Util;
namespace System.Web.UI.WebControls{
[TypeConverter(typeof (UnitConverter))]
#if NET_2_0
[Serializable]
#else
// CAS
[AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
#endif
public struct Unit {
enum ParsingStage
{
Trim,
SignOrSep,
DigitOrSep,
DigitOrUnit,
Unit
}
UnitType type;
double value;
bool valueSet;
public static readonly Unit Empty;
public Unit (double value, UnitType type)
{
if (value < -32768 || value > 32767)
throw new ArgumentOutOfRangeException ("value");
this.type = type;
if (type == UnitType.Pixel)
this.value = (int) value;
else
this.value = value;
valueSet = true;
}
public Unit (double value) : this (value, UnitType.Pixel)
{
}
public Unit (int value) : this ((double) value, UnitType.Pixel)
{
}
internal Unit (string input, char sep)
{
if (input == null || input == String.Empty){
type = (UnitType) 0;
value = 0.0;
return;
}
value = 0.0;
double dv = 0, factor = .1;
int i = 0;
int count = input.Length;
int sign = 1, unitStart = -1, unitLen = 0, wsCount = 0;
char c;
ParsingStage ps = ParsingStage.Trim;
bool done = false, haveSep = false, haveDigits = false, isWhiteSpace;
while (!done && i < count) {
c = input [i];
switch (ps) {
case ParsingStage.Trim:
if (Char.IsWhiteSpace (c)) {
i++;
continue;
}
ps = ParsingStage.SignOrSep;
continue;
case ParsingStage.SignOrSep:
wsCount = 0;
if (c == '-') {
sign = -1;
i++;
ps = ParsingStage.DigitOrSep;
continue;
}
if (c == sep) {
i++;
haveSep = true;
ps = ParsingStage.DigitOrUnit;
dv = 0;
continue;
}
if (Char.IsDigit (c)) {
ps = ParsingStage.DigitOrSep;
continue;
}
throw new FormatException ();
case ParsingStage.DigitOrSep:
if (Char.IsDigit (c)) {
dv = dv * 10 + ((int) c) - ((int)'0');
i++;
haveDigits = true;
continue;
}
if (c == sep) {
if (wsCount > 0)
throw new ArgumentOutOfRangeException ("input");
i++;
haveSep = true;
value = dv * sign;
dv = 0;
ps = ParsingStage.DigitOrUnit;
continue;
}
isWhiteSpace = Char.IsWhiteSpace (c);
if (isWhiteSpace || c == '%' || Char.IsLetter (c)) {
if (isWhiteSpace) {
if (!haveDigits)
throw new ArgumentOutOfRangeException ("input");
wsCount++;
i++;
continue;
}
value = dv * sign;
dv = 0;
unitStart = i;
if (haveSep) {
haveDigits = false;
ps = ParsingStage.DigitOrUnit;
} else
ps = ParsingStage.Unit;
wsCount = 0;
continue;
}
throw new FormatException ();
case ParsingStage.DigitOrUnit:
if (c == '%') {
unitStart = i;
unitLen = 1;
done = true;
continue;
}
isWhiteSpace = Char.IsWhiteSpace (c);
if (isWhiteSpace || Char.IsLetter (c)) {
if (isWhiteSpace) {
wsCount++;
i++;
continue;
}
ps = ParsingStage.Unit;
unitStart = i;
continue;
}
if (Char.IsDigit (c)) {
if (wsCount > 0)
throw new ArgumentOutOfRangeException ();
dv = dv + (((int) c) - ((int) '0')) * factor;
factor = factor *.1;
i++;
continue;
}
throw new FormatException ();
case ParsingStage.Unit:
if (c == '%' || Char.IsLetter (c)) {
i++;
unitLen++;
continue;
}
if (unitLen == 0 && Char.IsWhiteSpace (c)) {
i++;
unitStart++;
continue;
}
done = true;
break;
}
}
value += dv * sign;
if (unitStart >= 0) {
int unitTail = unitStart + unitLen;
if (unitTail < count) {
for (int j = unitTail; j < count; j++) {
if (!Char.IsWhiteSpace (input [j]))
throw new ArgumentOutOfRangeException ("input");
}
}
if (unitLen == 1 && input [unitStart] == '%')
type = UnitType.Percentage;
else {
switch (input.Substring (unitStart, unitLen).ToLower (Helpers.InvariantCulture)) {
case "in": type = UnitType.Inch; break;
case "cm": type = UnitType.Cm; break;
case "mm": type = UnitType.Mm; break;
case "pt": type = UnitType.Point; break;
case "pc": type = UnitType.Pica; break;
case "em": type = UnitType.Em; break;
case "ex": type = UnitType.Ex; break;
case "px":
type = UnitType.Pixel;
break;
default:
throw new ArgumentOutOfRangeException ("value");
}
}
} else
type = UnitType.Pixel;
if (haveSep && type == UnitType.Pixel)
throw new FormatException ("Pixel units do not allow floating point values");
valueSet = true;
}
public Unit (string value) : this (value, '.')
{
}
public Unit (string value, CultureInfo culture) : this (value, culture.NumberFormat.NumberDecimalSeparator [0])
{
}
internal Unit (string value, CultureInfo culture, UnitType t) : this (value, '.')
{
}
public bool IsEmpty {
get {
return type == 0;
}
}
public UnitType Type {
get {
if (type == 0)
return UnitType.Pixel;
return type;
}
}
public double Value {
get {
return value;
}
}
public static Unit Parse (string s)
{
return new Unit (s);
}
public static System.Web.UI.WebControls.Unit Parse (string s, System.Globalization.CultureInfo culture)
{
return new Unit (s, culture);
}
public static Unit Percentage (double n)
{
return new Unit (n, UnitType.Percentage);
}
public static Unit Pixel (int n)
{
return new Unit (n);
}
public static Unit Point (int n)
{
return new Unit (n, UnitType.Point);
}
public override bool Equals (object obj)
{
if (obj is Unit){
Unit other = (Unit) obj;
return (other.type == type && other.value == value && valueSet == other.valueSet);
}
return false;
}
public override int GetHashCode ()
{
return Type.GetHashCode () ^ Value.GetHashCode ();
}
public static bool operator == (Unit left, Unit right)
{
return left.Type == right.Type && left.Value == right.Value && left.valueSet == right.valueSet;
}
public static bool operator != (Unit left, Unit right)
{
return left.Type != right.Type || left.Value != right.Value || left.valueSet != right.valueSet;
}
public static implicit operator Unit (int n)
{
return new Unit (n);
}
string GetExtension ()
{
switch (type){
case UnitType.Pixel: return "px";
case UnitType.Point: return "pt";
case UnitType.Pica: return "pc";
case UnitType.Inch: return "in";
case UnitType.Mm: return "mm";
case UnitType.Cm: return "cm";
case UnitType.Percentage: return "%";
case UnitType.Em: return "em";
case UnitType.Ex: return "ex";
default: return "";
}
}
public string ToString (CultureInfo culture)
{
if (type == 0)
return "";
string ex = GetExtension ();
return value.ToString (culture) + ex;
}
public override string ToString ()
{
return ToString (Helpers.InvariantCulture);
}
#if NET_2_0
public string ToString (IFormatProvider provider)
{
if (type == 0)
return "";
string ex = GetExtension ();
return value.ToString (provider) + ex;
}
#endif
}
}
|