The Labs \ Source Viewer \ SSCLI \ Microsoft.JScript \ StringPrototype

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. namespace Microsoft.JScript
  16. {
  17.    
  18.     using Microsoft.JScript.Vsa;
  19.     using System;
  20.     using System.Collections;
  21.     using System.Globalization;
  22.     using System.Text;
  23.     using System.Text.RegularExpressions;
  24.    
  25.     public class StringPrototype : StringObject
  26.     {
  27.         static internal readonly StringPrototype ob = new StringPrototype(FunctionPrototype.ob, ObjectPrototype.ob);
  28.         static internal StringConstructor _constructor;
  29.        
  30.         internal StringPrototype(FunctionPrototype funcprot, ObjectPrototype parent) : base(parent, "")
  31.         {
  32.             this.noExpando = true;
  33.         }
  34.        
  35.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_anchor)]
  36.         public static string anchor(object thisob, object anchorName)
  37.         {
  38.             string thisStr = Convert.ToString(thisob);
  39.             string anchorStr = Convert.ToString(anchorName);
  40.             return "<A NAME=\"" + anchorStr + "\">" + thisStr + "</A>";
  41.         }
  42.        
  43.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_big)]
  44.         public static string big(object thisob)
  45.         {
  46.             return "<BIG>" + Convert.ToString(thisob) + "</BIG>";
  47.         }
  48.        
  49.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_blink)]
  50.         public static string blink(object thisob)
  51.         {
  52.             return "<BLINK>" + Convert.ToString(thisob) + "</BLINK>";
  53.         }
  54.        
  55.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_bold)]
  56.         public static string bold(object thisob)
  57.         {
  58.             return "<B>" + Convert.ToString(thisob) + "</B>";
  59.         }
  60.        
  61.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_charAt)]
  62.         public static string charAt(object thisob, double pos)
  63.         {
  64.             string thisStr = Convert.ToString(thisob);
  65.             double position = Convert.ToInteger(pos);
  66.             if (position < 0 || !(position < thisStr.Length))
  67.                 return "";
  68.             return thisStr.Substring((int)position, 1);
  69.         }
  70.        
  71.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_charCodeAt)]
  72.         public static object charCodeAt(object thisob, double pos)
  73.         {
  74.             //This returns an object so that integers stay integers
  75.             string thisStr = Convert.ToString(thisob);
  76.             double position = Convert.ToInteger(pos);
  77.             if (position < 0 || !(position < thisStr.Length))
  78.                 return Double.NaN;
  79.             return (int)(thisStr[(int)position]);
  80.         }
  81.        
  82.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject | JSFunctionAttributeEnum.HasVarArgs, JSBuiltin.String_concat)]
  83.         public static string concat(object thisob, params object[] args)
  84.         {
  85.             StringBuilder concat = new StringBuilder(Convert.ToString(thisob));
  86.             for (int i = 0; i < args.Length; i++)
  87.                 concat.Append(Convert.ToString(args[i]));
  88.             return concat.ToString();
  89.         }
  90.        
  91.         public static StringConstructor constructor {
  92.             get { return StringPrototype._constructor; }
  93.         }
  94.        
  95.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_fixed)]
  96.         public static string @fixed(object thisob)
  97.         {
  98.             return "<TT>" + Convert.ToString(thisob) + "</TT>";
  99.         }
  100.        
  101.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_fontcolor)]
  102.         public static string fontcolor(object thisob, object colorName)
  103.         {
  104.             string thisStr = Convert.ToString(thisob);
  105.             string colorStr = Convert.ToString(thisob);
  106.             return "<FONT COLOR=\"" + colorStr + "\">" + thisStr + "</FONT>";
  107.         }
  108.        
  109.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_fontsize)]
  110.         public static string fontsize(object thisob, object fontSize)
  111.         {
  112.             string thisStr = Convert.ToString(thisob);
  113.             string fontStr = Convert.ToString(fontSize);
  114.             return "<FONT SIZE=\"" + fontStr + "\">" + thisStr + "</FONT>";
  115.         }
  116.        
  117.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_indexOf)]
  118.         public static int indexOf(object thisob, object searchString, double position)
  119.         {
  120.             string thisStr = Convert.ToString(thisob);
  121.             string searchStr = Convert.ToString(searchString);
  122.             double startIndex = Convert.ToInteger(position);
  123.             int length = thisStr.Length;
  124.             if (startIndex < 0)
  125.                 startIndex = 0;
  126.             if (startIndex >= length)
  127.                 return searchStr.Length == 0 ? 0 : -1;
  128.             return thisStr.IndexOf(searchStr, (int)startIndex);
  129.         }
  130.        
  131.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_italics)]
  132.         public static string italics(object thisob)
  133.         {
  134.             return "<I>" + Convert.ToString(thisob) + "</I>";
  135.         }
  136.        
  137.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_lastIndexOf)]
  138.         public static int lastIndexOf(object thisob, object searchString, double position)
  139.         {
  140.             string thisStr = Convert.ToString(thisob);
  141.             string searchStr = Convert.ToString(searchString);
  142.             int length = thisStr.Length;
  143.             int j = position != position || position > length ? length : (int)position;
  144.             if (j < 0)
  145.                 j = 0;
  146.             if (j >= length)
  147.                 j = length;
  148.             int slength = searchStr.Length;
  149.             if (slength == 0)
  150.                 return j;
  151.             int k = j - 1 + slength;
  152.             if (k >= length)
  153.                 k = length - 1;
  154.             if (k < 0)
  155.                 return -1;
  156.             return thisStr.LastIndexOf(searchStr, k);
  157.         }
  158.        
  159.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_link)]
  160.         public static string link(object thisob, object linkRef)
  161.         {
  162.             string thisStr = Convert.ToString(thisob);
  163.             string linkStr = Convert.ToString(linkRef);
  164.             return "<A HREF=\"" + linkStr + "\">" + thisStr + "</A>";
  165.         }
  166.        
  167.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_localeCompare)]
  168.         public static int localeCompare(object thisob, object thatob)
  169.         {
  170.             return String.Compare(Convert.ToString(thisob), Convert.ToString(thatob), StringComparison.CurrentCulture);
  171.         }
  172.        
  173.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject | JSFunctionAttributeEnum.HasEngine, JSBuiltin.String_match)]
  174.         public static object match(object thisob, VsaEngine engine, object regExp)
  175.         {
  176.             string thisStr = Convert.ToString(thisob);
  177.             RegExpObject regExpObject = StringPrototype.ToRegExpObject(regExp, engine);
  178.             Match match;
  179.             if (!regExpObject.globalInt) {
  180.                 match = regExpObject.regex.Match(thisStr);
  181.                 if (!match.Success) {
  182.                     regExpObject.lastIndexInt = 0;
  183.                     return DBNull.Value;
  184.                 }
  185.                 if (regExpObject.regExpConst != null) {
  186.                     regExpObject.lastIndexInt = regExpObject.regExpConst.UpdateConstructor(regExpObject.regex, match, thisStr);
  187.                     return new RegExpMatch(regExpObject.regExpConst.arrayPrototype, regExpObject.regex, match, thisStr);
  188.                 }
  189.                 else
  190.                     return new RegExpMatch(engine.Globals.globalObject.originalRegExp.arrayPrototype, regExpObject.regex, match, thisStr);
  191.             }
  192.             MatchCollection matches = regExpObject.regex.Matches(thisStr);
  193.             if (matches.Count == 0) {
  194.                 regExpObject.lastIndexInt = 0;
  195.                 return DBNull.Value;
  196.             }
  197.             match = matches[matches.Count - 1];
  198.             regExpObject.lastIndexInt = regExpObject.regExpConst.UpdateConstructor(regExpObject.regex, match, thisStr);
  199.             return new RegExpMatch(regExpObject.regExpConst.arrayPrototype, regExpObject.regex, matches, thisStr);
  200.         }
  201.        
  202.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_replace)]
  203.         public static string replace(object thisob, object regExp, object replacement)
  204.         {
  205.             string thisStr = Convert.ToString(thisob);
  206.             RegExpObject regExpObject = regExp as RegExpObject;
  207.             if (regExpObject != null)
  208.                 return StringPrototype.ReplaceWithRegExp(thisStr, regExpObject, replacement);
  209.             Regex regex = regExp as Regex;
  210.             if (regex != null)
  211.                 return StringPrototype.ReplaceWithRegExp(thisStr, new RegExpObject(regex), replacement);
  212.             return StringPrototype.ReplaceWithString(thisStr, Convert.ToString(regExp), Convert.ToString(replacement));
  213.         }
  214.        
  215.         private static string ReplaceWithRegExp(string thisob, RegExpObject regExpObject, object replacement)
  216.         {
  217.             RegExpReplace replacer = replacement is ScriptFunction ? (RegExpReplace)(new ReplaceUsingFunction(regExpObject.regex, (ScriptFunction)replacement, thisob)) : (RegExpReplace)(new ReplaceWithString(Convert.ToString(replacement)));
  218.             MatchEvaluator matchEvaluator = new MatchEvaluator(replacer.Evaluate);
  219.             string newString = regExpObject.globalInt ? regExpObject.regex.Replace(thisob, matchEvaluator) : regExpObject.regex.Replace(thisob, matchEvaluator, 1);
  220.             regExpObject.lastIndexInt = replacer.lastMatch == null ? 0 : regExpObject.regExpConst.UpdateConstructor(regExpObject.regex, replacer.lastMatch, thisob);
  221.             return newString;
  222.         }
  223.        
  224.         private static string ReplaceWithString(string thisob, string searchString, string replaceString)
  225.         {
  226.             int index = thisob.IndexOf(searchString);
  227.             if (index < 0)
  228.                 return thisob;
  229.             StringBuilder newString = new StringBuilder(thisob.Substring(0, index));
  230.             newString.Append(replaceString);
  231.             newString.Append(thisob.Substring(index + searchString.Length));
  232.             return newString.ToString();
  233.         }
  234.        
  235.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject | JSFunctionAttributeEnum.HasEngine, JSBuiltin.String_search)]
  236.         public static int search(object thisob, VsaEngine engine, object regExp)
  237.         {
  238.             string thisStr = Convert.ToString(thisob);
  239.             RegExpObject regExpObject = StringPrototype.ToRegExpObject(regExp, engine);
  240.             Match match = regExpObject.regex.Match(thisStr);
  241.             if (!match.Success) {
  242.                 regExpObject.lastIndexInt = 0;
  243.                 return -1;
  244.             }
  245.             regExpObject.lastIndexInt = regExpObject.regExpConst.UpdateConstructor(regExpObject.regex, match, thisStr);
  246.             return match.Index;
  247.         }
  248.        
  249.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_slice)]
  250.         public static string slice(object thisob, double start, object end)
  251.         {
  252.             string thisStr = Convert.ToString(thisob);
  253.             int length = thisStr.Length;
  254.             double startIndex = Convert.ToInteger(start);
  255.             double endIndex = (end == null || end is Missing) ? length : Convert.ToInteger(end);
  256.             if (startIndex < 0) {
  257.                 startIndex = length + startIndex;
  258.                 if (startIndex < 0)
  259.                     startIndex = 0;
  260.             }
  261.             else if (startIndex > length)
  262.                 startIndex = length;
  263.             if (endIndex < 0) {
  264.                 endIndex = length + endIndex;
  265.                 if (endIndex < 0)
  266.                     endIndex = 0;
  267.             }
  268.             else if (endIndex > length)
  269.                 endIndex = length;
  270.             int nChars = (int)(endIndex - startIndex);
  271.             if (nChars <= 0)
  272.                 return "";
  273.             else
  274.                 return thisStr.Substring((int)startIndex, nChars);
  275.         }
  276.        
  277.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_small)]
  278.         public static string small(object thisob)
  279.         {
  280.             return "<SMALL>" + Convert.ToString(thisob) + "</SMALL>";
  281.         }
  282.        
  283.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject | JSFunctionAttributeEnum.HasEngine, JSBuiltin.String_split)]
  284.         public static ArrayObject split(object thisob, VsaEngine engine, object separator, object limit)
  285.         {
  286.             string thisStr = Convert.ToString(thisob);
  287.             uint limitValue = UInt32.MaxValue;
  288.             if (limit != null && !(limit is Missing) && limit != DBNull.Value) {
  289.                 double lmt = Convert.ToInteger(limit);
  290.                 if (lmt >= 0 && lmt < UInt32.MaxValue)
  291.                     limitValue = (uint)lmt;
  292.             }
  293.             if (limitValue == 0)
  294.                 return (ArrayObject)engine.GetOriginalArrayConstructor().Construct();
  295.             if (separator == null || separator is Missing) {
  296.                 ArrayObject array = (ArrayObject)engine.GetOriginalArrayConstructor().Construct();
  297.                 array.SetValueAtIndex(0, thisob);
  298.                 return array;
  299.             }
  300.             RegExpObject regExpObject = separator as RegExpObject;
  301.             if (regExpObject != null)
  302.                 return StringPrototype.SplitWithRegExp(thisStr, engine, regExpObject, limitValue);
  303.             Regex regex = separator as Regex;
  304.             if (regex != null)
  305.                 return StringPrototype.SplitWithRegExp(thisStr, engine, new RegExpObject(regex), limitValue);
  306.             return StringPrototype.SplitWithString(thisStr, engine, Convert.ToString(separator), limitValue);
  307.         }
  308.        
  309.         private static ArrayObject SplitWithRegExp(string thisob, VsaEngine engine, RegExpObject regExpObject, uint limit)
  310.         {
  311.             ArrayObject array = (ArrayObject)engine.GetOriginalArrayConstructor().Construct();
  312.             Match match = regExpObject.regex.Match(thisob);
  313.            
  314.             if (!match.Success) {
  315.                 array.SetValueAtIndex(0, thisob);
  316.                 regExpObject.lastIndexInt = 0;
  317.                 return array;
  318.             }
  319.            
  320.            
  321.             Match lastMatch;
  322.             int prevIndex = 0;
  323.             uint i = 0;
  324.            
  325.             do {
  326.                 int len = match.Index - prevIndex;
  327.                 if (len > 0) {
  328.                     array.SetValueAtIndex(i++, thisob.Substring(prevIndex, len));
  329.                     if (limit > 0 && i >= limit) {
  330.                         regExpObject.lastIndexInt = regExpObject.regExpConst.UpdateConstructor(regExpObject.regex, match, thisob);
  331.                         return array;
  332.                     }
  333.                 }
  334.                
  335.                
  336.                 prevIndex = match.Index + match.Length;
  337.                 lastMatch = match;
  338.                 match = match.NextMatch();
  339.             }
  340.             while (match.Success);
  341.            
  342.             if (prevIndex < thisob.Length)
  343.                 array.SetValueAtIndex(i, thisob.Substring(prevIndex));
  344.             regExpObject.lastIndexInt = regExpObject.regExpConst.UpdateConstructor(regExpObject.regex, lastMatch, thisob);
  345.            
  346.             return array;
  347.         }
  348.        
  349.         private static ArrayObject SplitWithString(string thisob, VsaEngine engine, string separator, uint limit)
  350.         {
  351.             ArrayObject array = (ArrayObject)engine.GetOriginalArrayConstructor().Construct();
  352.             if (separator.Length == 0) {
  353.                 if (limit > thisob.Length)
  354.                     limit = (uint)thisob.Length;
  355.                 for (int i = 0; i < limit; i++)
  356.                     array.SetValueAtIndex((uint)i, thisob[i].ToString());
  357.             }
  358.             else {
  359.                 int prevIndex = 0;
  360.                 uint i = 0;
  361.                 int index;
  362.                 while ((index = thisob.IndexOf(separator, prevIndex)) >= 0) {
  363.                     array.SetValueAtIndex(i++, thisob.Substring(prevIndex, index - prevIndex));
  364.                     if (i >= limit)
  365.                         return array;
  366.                     prevIndex = index + separator.Length;
  367.                 }
  368.                 if (i == 0)
  369.                     array.SetValueAtIndex(0, thisob);
  370.                 else
  371.                     array.SetValueAtIndex(i, thisob.Substring(prevIndex));
  372.             }
  373.             return array;
  374.         }
  375.        
  376.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_strike)]
  377.         public static string strike(object thisob)
  378.         {
  379.             return "<STRIKE>" + Convert.ToString(thisob) + "</STRIKE>";
  380.         }
  381.        
  382.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_sub)]
  383.         public static string sub(object thisob)
  384.         {
  385.             return "<SUB>" + Convert.ToString(thisob) + "</SUB>";
  386.         }
  387.        
  388.         [NotRecommended("substr")]
  389.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_substr)]
  390.         public static string substr(object thisob, double start, object count)
  391.         {
  392.             string thisStr = thisob as string;
  393.             if (thisStr == null)
  394.                 thisStr = Convert.ToString(thisob);
  395.             int length = thisStr.Length;
  396.             double startIndex = Convert.ToInteger(start);
  397.             if (startIndex < 0)
  398.                 startIndex += length;
  399.             if (startIndex < 0)
  400.                 startIndex = 0;
  401.             else if (startIndex > length)
  402.                 startIndex = length;
  403.             int nChars = count is int ? (int)count : ((count == null || count is Missing) ? length - (int)Runtime.DoubleToInt64(startIndex) : (int)Runtime.DoubleToInt64(Convert.ToInteger(count)));
  404.             if (startIndex + nChars > length)
  405.                 nChars = length - (int)startIndex;
  406.             if (nChars <= 0)
  407.                 return "";
  408.             else
  409.                 return thisStr.Substring((int)startIndex, nChars);
  410.         }
  411.        
  412.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_substring)]
  413.         public static string substring(object thisob, double start, object end)
  414.         {
  415.             string thisStr = thisob as string;
  416.             if (thisStr == null)
  417.                 thisStr = Convert.ToString(thisob);
  418.             int length = thisStr.Length;
  419.             double startIndex = Convert.ToInteger(start);
  420.             if (startIndex < 0)
  421.                 startIndex = 0;
  422.             else if (startIndex > length)
  423.                 startIndex = length;
  424.             double endIndex = (end == null || end is Missing) ? length : Convert.ToInteger(end);
  425.             if (endIndex < 0)
  426.                 endIndex = 0;
  427.             else if (endIndex > length)
  428.                 endIndex = length;
  429.             if (startIndex > endIndex) {
  430.                 double temp = startIndex;
  431.                 startIndex = endIndex;
  432.                 endIndex = temp;
  433.             }
  434.             return thisStr.Substring((int)startIndex, (int)(endIndex - startIndex));
  435.         }
  436.        
  437.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_sup)]
  438.         public static string sup(object thisob)
  439.         {
  440.             return "<SUP>" + Convert.ToString(thisob) + "</SUP>";
  441.         }
  442.        
  443.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_toLocaleLowerCase)]
  444.         public static string toLocaleLowerCase(object thisob)
  445.         {
  446.             return Convert.ToString(thisob).ToLower(CultureInfo.CurrentUICulture);
  447.         }
  448.        
  449.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_toLocaleUpperCase)]
  450.         public static string toLocaleUpperCase(object thisob)
  451.         {
  452.             return Convert.ToString(thisob).ToUpperInvariant();
  453.         }
  454.        
  455.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_toLowerCase)]
  456.         public static string toLowerCase(object thisob)
  457.         {
  458.             return Convert.ToString(thisob).ToLowerInvariant();
  459.         }
  460.        
  461.         private static RegExpObject ToRegExpObject(object regExp, VsaEngine engine)
  462.         {
  463.             if (regExp == null || regExp is Missing)
  464.                 return (RegExpObject)engine.GetOriginalRegExpConstructor().Construct("", false, false, false);
  465.             RegExpObject result = regExp as RegExpObject;
  466.             if (result != null)
  467.                 return result;
  468.             Regex regex = regExp as Regex;
  469.             if (regex != null)
  470.                 return new RegExpObject(regex);
  471.             return (RegExpObject)engine.GetOriginalRegExpConstructor().Construct(Convert.ToString(regExp), false, false, false);
  472.         }
  473.        
  474.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_toString)]
  475.         public static string toString(object thisob)
  476.         {
  477.             StringObject strob = thisob as StringObject;
  478.             if (strob != null)
  479.                 return strob.value;
  480.             ConcatString concatStr = thisob as ConcatString;
  481.             if (concatStr != null)
  482.                 return concatStr.ToString();
  483.             IConvertible ic = Convert.GetIConvertible(thisob);
  484.             if (Convert.GetTypeCode(thisob, ic) == TypeCode.String)
  485.                 return ic.ToString(null);
  486.             throw new JScriptException(JSError.StringExpected);
  487.         }
  488.        
  489.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_toUpperCase)]
  490.         public static string toUpperCase(object thisob)
  491.         {
  492.             return Convert.ToString(thisob).ToUpperInvariant();
  493.         }
  494.        
  495.         [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_valueOf)]
  496.         public static object valueOf(object thisob)
  497.         {
  498.             return StringPrototype.toString(thisob);
  499.         }
  500.     }
  501. }

Developer Fusion