예제 #1
0
 public static object Parse(
     XmlReader rdr,
     Type valueType,
     MappingAction action,
     out Type parsedType,
     out Type parsedArrayType)
 {
     parsedType = parsedArrayType = null;
     rdr.ReadToDescendant("value");
     var mappingStack = new MappingStack("request");
     return new XmlRpcDeserializer().ParseValueElement(rdr, valueType, mappingStack, action);
 }
예제 #2
0
 public static object Parse(
   XmlReader rdr,
   Type valueType,
   MappingAction action,
   XmlRpcDeserializer deserializer,
   out Type parsedType,
   out Type parsedArrayType)
 {
   parsedType = parsedArrayType = null;
   rdr.ReadToDescendant("value");
   MappingStack parseStack = new MappingStack("request");
   object obj = deserializer.ParseValueElement(rdr, valueType, parseStack, action);
   return obj;
 }
예제 #3
0
 private object MapDouble(string value, Type valType, MappingStack mappingStack, MappingAction mappingAction,
                          out Type mappedType)
 {
     CheckExpectedType(valType, typeof(double), mappingStack);
     mappedType = typeof(double);
     return(OnStack("double", mappingStack, (() =>
     {
         try
         {
             return double.Parse(value, CultureInfo.InvariantCulture.NumberFormat);
         }
         catch (Exception exception0)
         {
             throw new XmlRpcInvalidXmlRpcException(mappingStack.MappingType + " contains invalid double value " +
                                                    StackDump(mappingStack));
         }
     })));
 }
        private XmlRpcFaultException ParseFault(IEnumerator<Node> iter, MappingStack parseStack,
                                                MappingAction mappingAction)
        {
            iter.MoveNext();
            Type mappedType;
            var xmlRpcStruct = MapHashtable(iter, null, parseStack, mappingAction, out mappedType) as XmlRpcStruct;
            
            object obj1 = xmlRpcStruct["faultCode"];
            object obj2 = xmlRpcStruct["faultString"];
            if (obj1 is string)
            {
                int result;
                if (!int.TryParse(obj1 as string, out result))
                    throw new XmlRpcInvalidXmlRpcException("faultCode not int or string");
                obj1 = result;
            }
            return new XmlRpcFaultException((int)obj1, (string)obj2);

        }
예제 #5
0
        protected object MapHashtable(IEnumerator <Node> iter, Type valType, MappingStack mappingStack,
                                      MappingAction mappingAction, out Type mappedType)
        {
            mappedType = null;
            var xmlRpcStruct = new XmlRpcStruct();

            (mappingStack).Push("struct mapped to XmlRpcStruct");
            try
            {
                while (iter.MoveNext())
                {
                    if (iter.Current is StructMember)
                    {
                        string str = (iter.Current as StructMember).Value;
                        if (xmlRpcStruct.ContainsKey(str) && !IgnoreDuplicateMembers)
                        {
                            throw new XmlRpcInvalidXmlRpcException(mappingStack.MappingType +
                                                                   " contains struct value with duplicate member " + str +
                                                                   " " + StackDump(mappingStack));
                        }
                        else
                        {
                            iter.MoveNext();
                            object obj = OnStack(string.Format("member {0}", str), mappingStack,
                                                 (() => MapValueNode(iter, null, mappingStack, mappingAction)));
                            if (!xmlRpcStruct.ContainsKey(str))
                            {
                                xmlRpcStruct[str] = obj;
                            }
                        }
                    }
                    else
                    {
                        break;
                    }
                }
            }
            finally
            {
                mappingStack.Pop();
            }
            return(xmlRpcStruct);
        }
예제 #6
0
 private object MapBoolean(string value, Type valType, MappingStack mappingStack, MappingAction mappingAction,
                           out Type mappedType)
 {
     CheckExpectedType(valType, typeof(bool), mappingStack);
     mappedType = typeof(bool);
     return(OnStack("boolean", mappingStack, (() =>
     {
         if (value == "1")
         {
             return true;
         }
         if (value == "0")
         {
             return false;
         }
         throw new XmlRpcInvalidXmlRpcException(mappingStack.MappingType + " contains invalid boolean value " +
                                                StackDump(mappingStack));
     })));
 }
예제 #7
0
 private object MapInt(string value, Type valType, MappingStack mappingStack, MappingAction mappingAction,
                       out Type mappedType)
 {
     CheckExpectedType(valType, typeof(int), mappingStack);
     if (valType != null && valType.IsEnum)
     {
         return(MapNumberToEnum(value, valType, "int", mappingStack, out mappedType));
     }
     mappedType = typeof(int);
     return(OnStack("integer", mappingStack, (() =>
     {
         int local0;
         if (!int.TryParse(value, out local0))
         {
             throw new XmlRpcInvalidXmlRpcException(mappingStack.MappingType + " contains invalid int value " +
                                                    StackDump(mappingStack));
         }
         return local0;
     })));
 }
예제 #8
0
        private XmlRpcFaultException ParseFault(IEnumerator <Node> iter, MappingStack parseStack,
                                                MappingAction mappingAction)
        {
            iter.MoveNext();
            Type mappedType;
            var  xmlRpcStruct = MapHashtable(iter, null, parseStack, mappingAction, out mappedType) as XmlRpcStruct;

            object obj1 = xmlRpcStruct["faultCode"];
            object obj2 = xmlRpcStruct["faultString"];

            if (obj1 is string)
            {
                int result;
                if (!int.TryParse(obj1 as string, out result))
                {
                    throw new XmlRpcInvalidXmlRpcException("faultCode not int or string");
                }
                obj1 = result;
            }
            return(new XmlRpcFaultException((int)obj1, (string)obj2));
        }
예제 #9
0
 private object MapBase64(string value, Type valType, MappingStack mappingStack,
                          out Type mappedType)
 {
     CheckExpectedType(valType, typeof(byte[]), mappingStack);
     mappedType = typeof(int);
     return(OnStack("base64", mappingStack, (() =>
     {
         if (value == "")
         {
             return new byte[0];
         }
         try
         {
             return Convert.FromBase64String(value);
         }
         catch (Exception exception0)
         {
             throw new XmlRpcInvalidXmlRpcException(mappingStack.MappingType + " contains invalid base64 value " +
                                                    StackDump(mappingStack));
         }
     })));
 }
예제 #10
0
        private void AddCustomField(IEnumerator <Node> iter, MappingStack mappingStack, MappingAction mappingAction, string name,
                                    object instance)
        {
            Type valType;

            if (iter.Current is Base64Value || iter.Current is LongValue)
            {
                valType = typeof(long);
            }
            else if (iter.Current is BooleanValue)
            {
                valType = typeof(bool);
            }
            else if (iter.Current is DateTimeValue)
            {
                valType = typeof(DateTime);
            }
            else if (iter.Current is DoubleValue)
            {
                valType = typeof(double);
            }
            else if (iter.Current is IntValue)
            {
                valType = typeof(int);
            }
            else if (iter.Current is StringValue)
            {
                valType = typeof(string);
            }
            else
            {
                return;
            }

            object obj = OnStack(name, mappingStack, (() => MapValueNode(iter, valType, mappingStack, mappingAction)));

            ((Table)instance).SetCustomField(name, obj);
        }
예제 #11
0
        private XmlRpcException DeserializeFault(IEnumerator <Node> iter)
        {
            var parseStack = new MappingStack("fault response");

            throw ParseFault(iter, parseStack, MappingAction.Error);
        }
예제 #12
0
        private void ReportMissingMembers(Type valueType, IEnumerable <string> names, MappingStack mappingStack)
        {
            var    stringBuilder = new StringBuilder();
            int    num           = 0;
            string str1          = "";

            foreach (string memberName in names)
            {
                if (MemberMappingAction(valueType, memberName, MappingAction.Error) == MappingAction.Error)
                {
                    stringBuilder.Append(str1);
                    stringBuilder.Append(memberName);
                    str1 = " ";
                    ++num;
                }
            }
            if (num <= 0)
            {
                return;
            }
            string str2 = "";

            if (num > 1)
            {
                str2 = "s";
            }
            throw new XmlRpcTypeMismatchException(mappingStack.MappingType +
                                                  " contains struct value with missing non-optional member" + str2 +
                                                  ": " + (stringBuilder) + " " + StackDump(mappingStack));
        }
예제 #13
0
        public object MapValueNode(IEnumerator <Node> iter, Type valType, MappingStack mappingStack,
                                   MappingAction mappingAction)
        {
            var valueNode = iter.Current as ValueNode;

            if (valType != null && valType.BaseType == null)
            {
                valType = null;
            }
            if (valueNode is StringValue && valueNode.ImplicitValue)
            {
                CheckImplictString(valType, mappingStack);
            }
            object obj = null;
            Type   mappedType;

            if (iter.Current is ArrayValue)
            {
                obj = MapArray(iter, valType, mappingStack, mappingAction, out mappedType);
            }
            else if (iter.Current is StructValue)
            {
                if (valType != null && valType != typeof(XmlRpcStruct) && !valType.IsSubclassOf(typeof(XmlRpcStruct)))
                {
                    obj = MapStruct(iter, valType, mappingStack, mappingAction, out mappedType);
                }
                else
                {
                    if (valType == null || valType == typeof(object))
                    {
                        valType = typeof(XmlRpcStruct);
                    }
                    obj = MapHashtable(iter, valType, mappingStack, mappingAction, out mappedType);
                }
            }
            else if (iter.Current is Base64Value)
            {
                obj = MapBase64(valueNode.Value, valType, mappingStack, out mappedType);
            }
            else if (iter.Current is IntValue)
            {
                obj = MapInt(valueNode.Value, valType, mappingStack, mappingAction, out mappedType);
            }
            else if (iter.Current is LongValue)
            {
                obj = MapLong(valueNode.Value, valType, mappingStack, mappingAction, out mappedType);
            }
            else if (iter.Current is StringValue)
            {
                obj = MapString(valueNode.Value, valType, mappingStack, mappingAction, out mappedType);
            }
            else if (iter.Current is BooleanValue)
            {
                obj = MapBoolean(valueNode.Value, valType, mappingStack, mappingAction, out mappedType);
            }
            else if (iter.Current is DoubleValue)
            {
                obj = MapDouble(valueNode.Value, valType, mappingStack, mappingAction, out mappedType);
            }
            else if (iter.Current is DateTimeValue)
            {
                obj = MapDateTime(valueNode.Value, valType, mappingStack, mappingAction, out mappedType);
            }
            else if (iter.Current is NilValue)
            {
                obj = MapNilValue(valType, mappingStack, out mappedType);
            }
            return(obj);
        }
예제 #14
0
     XmlRpcFaultException ParseFault(
 IEnumerator<Node> iter,
 MappingStack parseStack,
 MappingAction mappingAction)
     {
         iter.MoveNext();  // move to StructValue
           Type parsedType;
           var faultStruct = MapHashtable(iter, null, parseStack, mappingAction,
         out parsedType) as XmlRpcStruct;
           object faultCode = faultStruct["faultCode"];
           object faultString = faultStruct["faultString"];
           if (faultCode is string)
           {
         int value;
         if (!Int32.TryParse(faultCode as string, out value))
           throw new XmlRpcInvalidXmlRpcException("faultCode not int or string");
         faultCode = value;
           }
           return new XmlRpcFaultException((int)faultCode, (string)faultString);
     }
예제 #15
0
 private object MapNumberToEnum(string value, Type enumType, string xmlRpcType, MappingStack mappingStack,
                                out Type mappedType)
 {
     mappedType = enumType;
     return(OnStack(xmlRpcType, mappingStack, (() =>
     {
         try
         {
             object local2 = Convert.ChangeType(long.Parse(value), Enum.GetUnderlyingType(enumType), null);
             if (Enum.IsDefined(enumType, local2))
             {
                 return Enum.ToObject(enumType, local2);
             }
             throw new XmlRpcInvalidEnumValue(mappingStack.MappingType + " contains " + xmlRpcType +
                                              "mapped to undefined enum value " + StackDump(mappingStack));
         }
         catch (XmlRpcInvalidEnumValue exception0)
         {
             throw;
         }
         catch (Exception exception1)
         {
             throw new XmlRpcInvalidEnumValue(mappingStack.MappingType + " contains invalid or out of range " +
                                              xmlRpcType + " value mapped to enum " + StackDump(mappingStack));
         }
     })));
 }
예제 #16
0
 private object MapStringToEnum(string value, Type enumType, string xmlRpcType, MappingStack mappingStack,
                                MappingAction mappingAction, out Type mappedType)
 {
     mappedType = enumType;
     return(OnStack(xmlRpcType, mappingStack, (() =>
     {
         try
         {
             return Enum.Parse(enumType, value, true);
         }
         catch (XmlRpcInvalidEnumValue exception_0)
         {
             throw;
         }
         catch (Exception exception_1)
         {
             throw new XmlRpcInvalidEnumValue(mappingStack.MappingType + " contains invalid or out of range " +
                                              xmlRpcType + " value mapped to enum " + StackDump(mappingStack));
         }
     })));
 }
예제 #17
0
        public XmlRpcRequest DeserializeRequest(XmlReader rdr, Type svcType)
        {
            try
              {
            XmlRpcRequest request = new XmlRpcRequest();
            IEnumerator<Node> iter = new XmlRpcParser().ParseRequest(rdr).GetEnumerator();

            iter.MoveNext();
            string methodName = (iter.Current as MethodName).Name;
            request.method = methodName;

            request.mi = null;
            ParameterInfo[] pis = null;
            if (svcType != null)
            {
              // retrieve info for the method which handles this XML-RPC method
              XmlRpcServiceInfo svcInfo
            = XmlRpcServiceInfo.CreateServiceInfo(svcType);
              request.mi = svcInfo.GetMethodInfo(request.method);
              // if a service type has been specified and we cannot find the requested
              // method then we must throw an exception
              if (request.mi == null)
              {
            string msg = String.Format("unsupported method called: {0}",
                                        request.method);
            throw new XmlRpcUnsupportedMethodException(msg);
              }
              // method must be marked with XmlRpcMethod attribute
              Attribute attr = Attribute.GetCustomAttribute(request.mi,
            typeof(XmlRpcMethodAttribute));
              if (attr == null)
              {
            throw new XmlRpcMethodAttributeException(
              "Method must be marked with the XmlRpcMethod attribute.");
              }
              pis = request.mi.GetParameters();
            }

            bool gotParams = iter.MoveNext();
            if (!gotParams)
            {
              if (svcType != null)
              {
            if (pis.Length == 0)
            {
              request.args = new object[0];
              return request;
            }
            else
            {
              throw new XmlRpcInvalidParametersException(
                "Method takes parameters and params element is missing.");
            }
              }
              else
              {
            request.args = new object[0];
            return request;
              }
            }

            int paramsPos = pis != null ? GetParamsPos(pis) : -1;
            Type paramsType = null;
            if (paramsPos != -1)
              paramsType = pis[paramsPos].ParameterType.GetElementType();
            int minParamCount = pis == null ? int.MaxValue
              : (paramsPos == -1 ? pis.Length : paramsPos);
            MappingStack mappingStack = new MappingStack("request");
            MappingAction mappingAction = MappingAction.Error;
            var objs = new List<object>();
            var paramsObjs = new List<object>();
            int paramCount = 0;

            while (iter.MoveNext())
            {
              paramCount++;
              if (svcType != null && paramCount > minParamCount && paramsPos == -1)
            throw new XmlRpcInvalidParametersException(
              "Request contains too many param elements based on method signature.");
              if (paramCount <= minParamCount)
              {
            if (svcType != null)
            {
              mappingStack.Push(String.Format("parameter {0}", paramCount));
              // TODO: why following commented out?
              //          parseStack.Push(String.Format("parameter {0} mapped to type {1}",
              //            i, pis[i].ParameterType.Name));
              var obj = MapValueNode(iter,
                pis[paramCount - 1].ParameterType, mappingStack, mappingAction);
              objs.Add(obj);
            }
            else
            {
              mappingStack.Push(String.Format("parameter {0}", paramCount));
              var obj = MapValueNode(iter, null, mappingStack, mappingAction);
              objs.Add(obj);
            }
            mappingStack.Pop();
              }
              else
              {
            mappingStack.Push(String.Format("parameter {0}", paramCount + 1));
            var paramsObj = MapValueNode(iter, paramsType, mappingStack, mappingAction);
            paramsObjs.Add(paramsObj);
            mappingStack.Pop();
              }
            }

            if (svcType != null && paramCount < minParamCount)
              throw new XmlRpcInvalidParametersException(
            "Request contains too few param elements based on method signature.");

            if (paramsPos != -1)
            {
              Object[] args = new Object[1];
              args[0] = paramCount - minParamCount;
              Array varargs = (Array)Activator.CreateInstance(pis[paramsPos].ParameterType, args);
              for (int i = 0; i < paramsObjs.Count; i++)
            varargs.SetValue(paramsObjs[i], i);
              objs.Add(varargs);
            }
            request.args = objs.ToArray();
            return request;
              }
              catch (XmlException ex)
              {
            throw new XmlRpcIllFormedXmlException("Request contains invalid XML", ex);
              }
        }
예제 #18
0
 private XmlRpcException DeserializeFault(IEnumerator<Node> iter)
 {
     MappingStack faultStack = new MappingStack("fault response");
       // TODO: use global action setting
       MappingAction mappingAction = MappingAction.Error;
       XmlRpcFaultException faultEx = ParseFault(iter, faultStack, // TODO: fix
     mappingAction);
       throw faultEx;
 }
예제 #19
0
        private object MapStruct(IEnumerator <Node> iter, Type valueType, MappingStack mappingStack,
                                 MappingAction mappingAction, out Type mappedType)
        {
            mappedType = null;
            if (valueType.IsPrimitive)
            {
                throw new XmlRpcTypeMismatchException(mappingStack.MappingType + " contains struct value where " +
                                                      XmlRpcTypeInfo.GetXmlRpcTypeString(valueType) + " expected " +
                                                      StackDump(mappingStack));
            }
            if (valueType.IsGenericType)
            {
                if (valueType.GetGenericTypeDefinition() == typeof(Nullable <>))
                {
                    valueType = valueType.GetGenericArguments()[0];
                }
            }
            object instance;

            try
            {
                instance = Activator.CreateInstance(valueType);
            }
            catch (Exception ex)
            {
                throw new XmlRpcTypeMismatchException(mappingStack.MappingType + " contains struct value where " +
                                                      XmlRpcTypeInfo.GetXmlRpcTypeString(valueType) +
                                                      " expected (as type " + valueType.Name + ") " +
                                                      StackDump(mappingStack));
            }
            MappingAction mappingAction1 = mappingAction;

            if (valueType != null)
            {
                (mappingStack).Push("struct mapped to type " + valueType.Name);
                mappingAction1 = StructMappingAction(valueType, mappingAction);
            }
            else
            {
                (mappingStack).Push("struct");
            }
            List <string> names = new List <string>();

            CreateFieldNamesMap(valueType, names);
            int           num  = 0;
            List <string> list = new List <string>();

            try
            {
                while (iter.MoveNext())
                {
                    if (iter.Current is StructMember)
                    {
                        string XmlRpcName = (iter.Current as StructMember).Value;
                        if (list.Contains(XmlRpcName))
                        {
                            if (!IgnoreDuplicateMembers)
                            {
                                throw new XmlRpcInvalidXmlRpcException(mappingStack.MappingType +
                                                                       " contains struct value with duplicate member " +
                                                                       XmlRpcName + " " + StackDump(mappingStack));
                            }
                        }
                        else
                        {
                            list.Add(XmlRpcName);
                            string     name    = GetStructName(valueType, XmlRpcName) ?? XmlRpcName;
                            MemberInfo element = valueType.GetField(name) ??
                                                 (MemberInfo)valueType.GetProperty(name);
                            if (element == null)
                            {
                                iter.MoveNext();
                                //If this is a table object, then we need to populate
                                // the value in the custom fields dictionary.
                                if (valueType.IsSubclassOf(typeof(Table)))
                                {
                                    AddCustomField(iter, mappingStack, mappingAction, name, instance);
                                }
                                if (iter.Current is ComplexValueNode)
                                {
                                    int depth = iter.Current.Depth;
                                    while (!(iter.Current is EndComplexValueNode) || iter.Current.Depth != depth)
                                    {
                                        iter.MoveNext();
                                    }
                                }
                            }
                            else
                            {
                                if (names.Contains(name))
                                {
                                    names.Remove(name);
                                }
                                else if (Attribute.IsDefined(element, typeof(NonSerializedAttribute)))
                                {
                                    (mappingStack).Push(string.Format("member {0}", name));
                                    throw new XmlRpcNonSerializedMember(
                                              "Cannot map XML-RPC struct member onto member marked as [NonSerialized]:  " +
                                              StackDump(mappingStack));
                                }
                                Type memberType = element.MemberType == MemberTypes.Field
                                                      ? (element as FieldInfo).FieldType
                                                      : (element as PropertyInfo).PropertyType;
                                string p = valueType == null
                                               ? string.Format("member {0}", name)
                                               : string.Format("member {0} mapped to type {1}", name,
                                                               memberType.Name);

                                iter.MoveNext();
                                object obj = OnStack(p, mappingStack,
                                                     (() =>
                                                      MapValueNode(iter, memberType, mappingStack, mappingAction)));
                                if (element.MemberType == MemberTypes.Field)
                                {
                                    (element as FieldInfo).SetValue(instance, obj);
                                }
                                else
                                {
                                    (element as PropertyInfo).SetValue(instance, obj, null);
                                }
                                ++num;
                            }
                        }
                    }
                    else
                    {
                        break;
                    }
                }
                if (mappingAction1 == MappingAction.Error && names.Count > 0)
                {
                    ReportMissingMembers(valueType, names, mappingStack);
                }
                return(instance);
            }
            finally
            {
                mappingStack.Pop();
            }
        }
 private XmlRpcException DeserializeFault(IEnumerator<Node> iter)
 {
     var parseStack = new MappingStack("fault response");
     throw ParseFault(iter, parseStack, MappingAction.Error);
 }
예제 #21
0
    public static object ParseValue(string xml, Type valueType)
    {
      MappingAction action = MappingAction.Error;

      StringReader sr = new StringReader(xml);
      XmlReader rdr = XmlRpcXmlReader.Create(sr);
      rdr.MoveToContent();
      MappingStack parseStack = new MappingStack("value");
      var deser = new XmlRpcDeserializer();
      object obj = deser.ParseValueElement(rdr, valueType, parseStack, action);
      return obj;
    }
예제 #22
0
        private object MapArray(IEnumerator <Node> iter, Type valType, MappingStack mappingStack,
                                MappingAction mappingAction, out Type mappedType)
        {
            mappedType = null;
            if (valType != null && !valType.IsArray && (valType != typeof(Array) && valType != typeof(object)))
            {
                throw new XmlRpcTypeMismatchException(mappingStack.MappingType + " contains array value where " +
                                                      XmlRpcTypeInfo.GetXmlRpcTypeString(valType) + " expected " +
                                                      StackDump(mappingStack));
            }
            if (valType != null)
            {
                if (XmlRpcTypeInfo.GetXmlRpcType(valType) == XmlRpcType.tMultiDimArray)
                {
                    (mappingStack).Push("array mapped to type " + valType.Name);
                    return(MapMultiDimArray(iter, valType, mappingStack, mappingAction));
                }
                else
                {
                    (mappingStack).Push("array mapped to type " + valType.Name);
                }
            }
            else
            {
                (mappingStack).Push("array");
            }
            List <object> list        = new List <object>();
            Type          valType1    = DetermineArrayItemType(valType);
            bool          flag        = false;
            Type          elementType = null;

            while (iter.MoveNext() && iter.Current is ValueNode)
            {
                (mappingStack).Push(string.Format("element {0}", list.Count));
                object obj = MapValueNode(iter, valType1, mappingStack, mappingAction);
                list.Add(obj);
                mappingStack.Pop();
            }
            foreach (object obj in list)
            {
                if (obj != null)
                {
                    if (!flag)
                    {
                        elementType = obj.GetType();
                        flag        = true;
                    }
                    else if (elementType != obj.GetType())
                    {
                        elementType = null;
                    }
                }
            }
            object[] args = new object[1]
            {
                list.Count
            };
            object obj1 = valType == null || valType == typeof(Array) || valType == typeof(object)
                              ? (elementType != null
                                     ? Array.CreateInstance(elementType, (int)args[0])
                                     : CreateArrayInstance(typeof(object[]), args))
                              : CreateArrayInstance(valType, args);

            for (int index = 0; index < list.Count; ++index)
            {
                ((Array)obj1).SetValue(list[index], index);
            }
            mappingStack.Pop();
            return(obj1);
        }
예제 #23
0
 string StackDump(MappingStack parseStack)
 {
     StringBuilder sb = new StringBuilder();
     foreach (string elem in parseStack)
     {
         sb.Insert(0, elem);
         sb.Insert(0, " : ");
     }
     sb.Insert(0, parseStack.MappingType);
     sb.Insert(0, "[");
     sb.Append("]");
     return sb.ToString();
 }