Example #1
0
    public SpStream Encode(SpType type, SpObject obj)
    {
        SpStream stream = new SpStream();

        if (Encode(type, obj, stream) == false)
        {
            if (stream.IsOverflow())
            {
                if (stream.Position > MAX_SIZE)
                {
                    return(null);
                }

                int size = stream.Position;
                size   = ((size + 7) / 8) * 8;
                stream = new SpStream(size);
                if (Encode(type, obj, stream) == false)
                {
                    return(null);
                }
            }
            else
            {
                return(null);
            }
        }

        return(stream);
    }
Example #2
0
	public void Parse (string str) {
		mCurrentProtocol = null;
		mCurrentType = null;
		mLastType = null;

		str = PreProcess (str);
		Scan (str, 0);
	}
Example #3
0
    public bool Encode (SpType type, SpObject obj, SpStream stream) {
        if (type == null || obj == null || stream == null)
            return false;

        mStream = stream;
		bool success = EncodeInternal (type, obj);
		return (success && stream.IsOverflow () == false);
    }
Example #4
0
 public bool IsBuildinType(SpType type)
 {
     if (type == mTypeInteger || type == mTypeBoolean || type == mTypeString)
     {
         return(true);
     }
     return(false);
 }
Example #5
0
    public void Parse(string str)
    {
        mCurrentProtocol = null;
        mCurrentType     = null;
        mLastType        = null;

        str = PreProcess(str);
        Scan(str, 0);
    }
Example #6
0
	public bool CheckAndUpdate () {
		if (Type != null)
			return true;

		// use GetTypeNoCheck instead of GetType, to prevent infinit GetType call
		// when a type reference itself like : foobar { a 0 : foobar }
        Type = mTypeManager.GetTypeNoCheck (TypeName);
		return (Type != null);
	}
Example #7
0
    public SpObject Decode(SpType type, SpStream stream)
    {
        if (type == null || stream == null)
        {
            return(null);
        }

        mStream = stream;
        return(DecodeInternal(type));
    }
Example #8
0
    public StyleSprite?getRandomStyleByType(SpType type)
    {
        StyleSprite[] styleSprites = getStyleSpritesByType(type);

        if (styleSprites.Length > 0)
        {
            return(styleSprites[Random.Range(0, styleSprites.Length - 1)]);
        }

        return(null);
    }
Example #9
0
    private void Scan(string str, int start)
    {
        int pos = str.IndexOfAny(sDelimiters, start);

        if (pos < 0)
        {
            return;
        }

        switch (str[pos])
        {
        case '{':
            string title = str.Substring(start, pos - start).Trim();
            if (IsProtocol(title))
            {
                mCurrentProtocol = NewProtocol(title);
            }
            else
            {
                mLastType    = mCurrentType;
                mCurrentType = NewType(title);
            }
            break;

        case '}':
            if (mCurrentType != null)
            {
                mListener.OnNewType(mCurrentType);
                if (mCurrentProtocol != null)
                {
                    mCurrentProtocol.AddType(mCurrentType);
                }
                mCurrentType = mLastType;
                mLastType    = null;
            }
            else if (mCurrentProtocol != null)
            {
                mListener.OnNewProtocol(mCurrentProtocol);
                mCurrentProtocol = null;
            }
            break;

        case '\n':
            SpField f = NewField(str.Substring(start, pos - start));
            if (f != null && mCurrentType != null)
            {
                mCurrentType.AddField(f);
            }
            break;
        }

        start = pos + 1;
        Scan(str, start);
    }
Example #10
0
 public void AddType(SpType type)
 {
     if (type.Name.Equals(Name + ".request"))
     {
         Request = type;
     }
     else if (type.Name.Equals(Name + ".response"))
     {
         Response = type;
     }
 }
Example #11
0
    public bool CheckAndUpdate()
    {
        if (Type != null)
        {
            return(true);
        }

        // use GetTypeNoCheck instead of GetType, to prevent infinit GetType call
        // when a type reference itself like : foobar { a 0 : foobar }
        Type = mTypeManager.GetTypeNoCheck(TypeName);
        return(Type != null);
    }
Example #12
0
    public SpTypeManager()
    {
        mTypeInteger = new SpType("integer");
        mTypeBoolean = new SpType("boolean");
        mTypeString  = new SpType("string");

        OnNewType(mTypeInteger);
        OnNewType(mTypeString);
        OnNewType(mTypeBoolean);

        mCodec = new SpCodec(this);
    }
Example #13
0
    public bool Encode(SpType type, SpObject obj, SpStream stream)
    {
        if (type == null || obj == null || stream == null)
        {
            return(false);
        }

        mStream = stream;
        bool success = EncodeInternal(type, obj);

        return(success && stream.IsOverflow() == false);
    }
Example #14
0
    public void OnNewType(SpType type)
    {
        if (GetType(type.Name) != null)
        {
            return;
        }

        if (IsTypeComplete(type))
        {
            mTypes.Add(type.Name, type);
        }
        else
        {
            mIncompleteTypes.Add(type.Name, type);
        }
    }
Example #15
0
    public static SpRpc Create(SpTypeManager tm, string package)
    {
        if (tm == null)
        {
            return(null);
        }

        SpType t = tm.GetType(package);

        if (t == null)
        {
            return(null);
        }

        SpRpc rpc = new SpRpc(tm, t);

        return(rpc);
    }
Example #16
0
    public SpType GetType(string name)
    {
        if (mTypes.ContainsKey(name))
        {
            return(mTypes[name]);
        }

        if (mIncompleteTypes.ContainsKey(name))
        {
            SpType t = mIncompleteTypes[name];
            if (IsTypeComplete(t))
            {
                mIncompleteTypes.Remove(name);
                mTypes.Add(name, t);
            }
            return(t);
        }

        return(null);
    }
Example #17
0
	public SpStream Encode (SpType type, SpObject obj) {
		SpStream stream = new SpStream ();
		
		if (Encode (type, obj, stream) == false) {
			if (stream.IsOverflow ()) {
				if (stream.Position > MAX_SIZE)
					return null;
				
				int size = stream.Position;
				size = ((size + 7) / 8) * 8;
				stream = new SpStream (size);
				if (Encode (type, obj, stream) == false)
					return null;
			}
			else {
				return null;
			}
		}
		
		return stream;
	}
Example #18
0
	private void Scan (string str, int start) {
		int pos = str.IndexOfAny (sDelimiters, start);
		if (pos < 0)
			return;

		switch (str[pos]) {
		case '{':
			string title = str.Substring (start, pos - start).Trim ();
            if (IsProtocol (title)) {
                mCurrentProtocol = NewProtocol (title);
			}
			else {
                mLastType = mCurrentType;
                mCurrentType = NewType (title);
			}
			break;
		case '}':
            if (mCurrentType != null) {
                mListener.OnNewType (mCurrentType);
                if (mCurrentProtocol != null)
                    mCurrentProtocol.AddType (mCurrentType);
                mCurrentType = mLastType;
                mLastType = null;
			}
            else if (mCurrentProtocol != null) {
                mListener.OnNewProtocol (mCurrentProtocol);
                mCurrentProtocol = null;
            }
			break;
		case '\n':
			SpField f = NewField (str.Substring(start, pos - start));
            if (f != null && mCurrentType != null) {
                mCurrentType.AddField (f);
			}
			break;
		}
		
		start = pos + 1;
		Scan (str, start);
	}
Example #19
0
    private SpType NewType(string str)
    {
        if (str[0] == '.')
        {
            str = str.Substring(1);
        }
        else
        {
            if (mLastType != null)
            {
                str = mLastType.Name + "." + str;
            }

            if (mCurrentProtocol != null)
            {
                str = mCurrentProtocol.Name + "." + str;
            }
        }

        SpType t = new SpType(str);

        return(t);
    }
Example #20
0
    public SpObject Decode (SpType type, SpStream stream) {
        if (type == null || stream == null)
            return null;

        mStream = stream;
        return DecodeInternal (type);
    }
Example #21
0
 public SpRpc (SpTypeManager tm, SpType t) {
     mHostTypeManager = tm;
     mHeaderType = t;
 }
Example #22
0
 public void AddType (SpType type) {
     if (type.Name.Equals (Name + ".request"))
         Request = type;
     else if (type.Name.Equals (Name + ".response"))
         Response = type;
 }
Example #23
0
 public SpRpc(SpTypeManager tm, SpType t)
 {
     mHostTypeManager = tm;
     mHeaderType      = t;
 }
Example #24
0
    private bool EncodeInternal (SpType type, SpObject obj) {
		if (mStream == null || type == null || obj == null) {
            return false;
		}

        // buildin type decoding should not be here
		if (mTypeManager.IsBuildinType (type)) {
			return false;
		}

        int begin = mStream.Position;

        // fn. will be update later
        short fn = 0;
        mStream.Write (fn);

		List<KeyValuePair<SpObject, SpField>> objs = new List<KeyValuePair<SpObject, SpField>> ();
        int current_tag = -1;
		
		Dictionary<int, SpField>.ValueCollection.Enumerator en = type.Fields.Values.GetEnumerator ();
		while (en.MoveNext ()) {
			SpField f = en.Current;

			if (f == null) {
				return false;
			}

            SpObject o = obj[f.Name];
            if (o == null || IsTypeMatch (f, o) == false)
                continue;

			if (f.Tag <= current_tag) {
				return false;
			}

            if (f.Tag - current_tag > 1) {
                mStream.Write ((short)(2 * (f.Tag - current_tag - 1) - 1));
                fn++;
            }

            bool standalone = true;
            if (f.IsTable == false) {
                if (f.Type == mTypeManager.Boolean) {
                    int value = o.AsBoolean () ? 1 : 0;
                    mStream.Write ((short)((value + 1) * 2));
                    standalone = false;

               }
                else if (f.Type == mTypeManager.Integer) {
                    int value = o.AsInt ();
                    if (value >= 0 && value < 0x7fff) {
                        mStream.Write ((short)((value + 1) * 2));
						standalone = false;
                   }
                }
            }

			if (standalone) {
                objs.Add (new KeyValuePair<SpObject, SpField> (o, f));
                mStream.Write ((short)0);
            }

            fn++;
            current_tag = f.Tag;
        }
		
		List<KeyValuePair<SpObject, SpField>>.Enumerator e = objs.GetEnumerator ();
		while (e.MoveNext ()) {
			KeyValuePair<SpObject, SpField> entry = e.Current;

            if (entry.Value.IsTable) {
                int array_begin = mStream.Position;
                int size = 0;
                mStream.Write (size);

				if (entry.Value.Type == mTypeManager.Integer) {
                   byte len = 4;

					Dictionary<object, SpObject>.Enumerator enumerator = entry.Key.AsTable ().GetEnumerator ();
					while (enumerator.MoveNext ()) {
						SpObject o = enumerator.Current.Value;
                        if (o.IsLong ()) {
                            len = 8;
                            break;
                        }
                    }

                    mStream.Write (len);
					enumerator = entry.Key.AsTable ().GetEnumerator ();
					while (enumerator.MoveNext ()) {
						SpObject o = enumerator.Current.Value;
                        if (len == 4) {
                            mStream.Write (o.AsInt ());
                        }
                        else {
                            mStream.Write (o.AsLong ());
                        }
                    }
                }
				else if (entry.Value.Type == mTypeManager.Boolean) {
					Dictionary<object, SpObject>.Enumerator enumerator = entry.Key.AsTable ().GetEnumerator ();
					while (enumerator.MoveNext ()) {
						SpObject o = enumerator.Current.Value;
                        mStream.Write ((byte)(o.AsBoolean () ? 1 : 0));
                    }
                }
				else if (entry.Value.Type == mTypeManager.String) {
					Dictionary<object, SpObject>.Enumerator enumerator = entry.Key.AsTable ().GetEnumerator ();
					while (enumerator.MoveNext ()) {
						SpObject o = enumerator.Current.Value;
                        byte[] b = Encoding.UTF8.GetBytes (o.AsString ());
                        mStream.Write (b.Length);
                        mStream.Write (b);
                    }
                }
				else {
					
					Dictionary<object, SpObject>.Enumerator enumerator = entry.Key.AsTable ().GetEnumerator ();
					while (enumerator.MoveNext ()) {
						SpObject o = enumerator.Current.Value;

                        int obj_begin = mStream.Position;
                        int obj_size = 0;
                        mStream.Write (obj_size);

						if (EncodeInternal (entry.Value.Type, o) == false) {
							return false;
						}

                        int obj_end = mStream.Position;
                        obj_size = (int)(obj_end - obj_begin - 4);
                        mStream.Position = obj_begin;
                        mStream.Write (obj_size);
                        mStream.Position = obj_end;
					}
                }

                int array_end = mStream.Position;
                size = (int)(array_end - array_begin - 4);
                mStream.Position = array_begin;
                mStream.Write (size);
                mStream.Position = array_end;
            }
            else {
                if (entry.Key.IsString ()) {
					byte[] b = Encoding.UTF8.GetBytes (entry.Key.AsString ());
                    mStream.Write (b.Length);
                    mStream.Write (b);
                }
				else if (entry.Key.IsInt ()) {
                   mStream.Write ((int)4);
                    mStream.Write (entry.Key.AsInt ());
                }
				else if (entry.Key.IsLong ()) {
                   mStream.Write ((int)8);
                    mStream.Write (entry.Key.AsLong ());
                }
                else if (entry.Key.IsBoolean ()) {
                    // boolean should not be here
                    return false;
                }
                else {
                    int obj_begin = mStream.Position;
                    int obj_size = 0;
                    mStream.Write (obj_size);

					if (EncodeInternal (entry.Value.Type, entry.Key) == false) {
						return false;
					}

                    int obj_end = mStream.Position;
                    obj_size = (int)(obj_end - obj_begin - 4);
                    mStream.Position = obj_begin;
                    mStream.Write (obj_size);
                    mStream.Position = obj_end;
                }
            }
        }

        int end = mStream.Position;
        mStream.Position = begin;
        mStream.Write (fn);
        mStream.Position = end;

        return true;
    }
Example #25
0
    private bool EncodeInternal(SpType type, SpObject obj)
    {
        if (mStream == null || type == null || obj == null)
        {
            return(false);
        }

        // buildin type decoding should not be here
        if (mTypeManager.IsBuildinType(type))
        {
            return(false);
        }

        int begin = mStream.Position;

        // fn. will be update later
        short fn = 0;

        mStream.Write(fn);

        List <KeyValuePair <SpObject, SpField> > objs = new List <KeyValuePair <SpObject, SpField> > ();
        int current_tag = -1;

        Dictionary <int, SpField> .ValueCollection.Enumerator en = type.Fields.Values.GetEnumerator();
        while (en.MoveNext())
        {
            SpField f = en.Current;

            if (f == null)
            {
                return(false);
            }

            SpObject o = obj[f.Name];
            if (o == null || IsTypeMatch(f, o) == false)
            {
                continue;
            }

            if (f.Tag <= current_tag)
            {
                return(false);
            }

            if (f.Tag - current_tag > 1)
            {
                mStream.Write((short)(2 * (f.Tag - current_tag - 1) - 1));
                fn++;
            }

            bool standalone = true;
            if (f.IsTable == false)
            {
                if (f.Type == mTypeManager.Boolean)
                {
                    int value = o.AsBoolean() ? 1 : 0;
                    mStream.Write((short)((value + 1) * 2));
                    standalone = false;
                }
                else if (f.Type == mTypeManager.Integer)
                {
                    int value = o.AsInt();
                    if (value >= 0 && value < 0x7fff)
                    {
                        mStream.Write((short)((value + 1) * 2));
                        standalone = false;
                    }
                }
            }

            if (standalone)
            {
                objs.Add(new KeyValuePair <SpObject, SpField> (o, f));
                mStream.Write((short)0);
            }

            fn++;
            current_tag = f.Tag;
        }

        List <KeyValuePair <SpObject, SpField> > .Enumerator e = objs.GetEnumerator();
        while (e.MoveNext())
        {
            KeyValuePair <SpObject, SpField> entry = e.Current;

            if (entry.Value.IsTable)
            {
                int array_begin = mStream.Position;
                int size        = 0;
                mStream.Write(size);

                if (entry.Value.Type == mTypeManager.Integer)
                {
                    byte len = 4;

                    Dictionary <object, SpObject> .Enumerator enumerator = entry.Key.AsTable().GetEnumerator();
                    while (enumerator.MoveNext())
                    {
                        SpObject o = enumerator.Current.Value;
                        if (o.IsLong())
                        {
                            len = 8;
                            break;
                        }
                    }

                    mStream.Write(len);
                    enumerator = entry.Key.AsTable().GetEnumerator();
                    while (enumerator.MoveNext())
                    {
                        SpObject o = enumerator.Current.Value;
                        if (len == 4)
                        {
                            mStream.Write(o.AsInt());
                        }
                        else
                        {
                            mStream.Write(o.AsLong());
                        }
                    }
                }
                else if (entry.Value.Type == mTypeManager.Boolean)
                {
                    Dictionary <object, SpObject> .Enumerator enumerator = entry.Key.AsTable().GetEnumerator();
                    while (enumerator.MoveNext())
                    {
                        SpObject o = enumerator.Current.Value;
                        mStream.Write((byte)(o.AsBoolean() ? 1 : 0));
                    }
                }
                else if (entry.Value.Type == mTypeManager.String)
                {
                    Dictionary <object, SpObject> .Enumerator enumerator = entry.Key.AsTable().GetEnumerator();
                    while (enumerator.MoveNext())
                    {
                        SpObject o = enumerator.Current.Value;
                        byte[]   b = Encoding.UTF8.GetBytes(o.AsString());
                        mStream.Write(b.Length);
                        mStream.Write(b);
                    }
                }
                else
                {
                    Dictionary <object, SpObject> .Enumerator enumerator = entry.Key.AsTable().GetEnumerator();
                    while (enumerator.MoveNext())
                    {
                        SpObject o = enumerator.Current.Value;

                        int obj_begin = mStream.Position;
                        int obj_size  = 0;
                        mStream.Write(obj_size);

                        if (EncodeInternal(entry.Value.Type, o) == false)
                        {
                            return(false);
                        }

                        int obj_end = mStream.Position;
                        obj_size         = (int)(obj_end - obj_begin - 4);
                        mStream.Position = obj_begin;
                        mStream.Write(obj_size);
                        mStream.Position = obj_end;
                    }
                }

                int array_end = mStream.Position;
                size             = (int)(array_end - array_begin - 4);
                mStream.Position = array_begin;
                mStream.Write(size);
                mStream.Position = array_end;
            }
            else
            {
                if (entry.Key.IsString())
                {
                    byte[] b = Encoding.UTF8.GetBytes(entry.Key.AsString());
                    mStream.Write(b.Length);
                    mStream.Write(b);
                }
                else if (entry.Key.IsInt())
                {
                    mStream.Write((int)4);
                    mStream.Write(entry.Key.AsInt());
                }
                else if (entry.Key.IsLong())
                {
                    mStream.Write((int)8);
                    mStream.Write(entry.Key.AsLong());
                }
                else if (entry.Key.IsBoolean())
                {
                    // boolean should not be here
                    return(false);
                }
                else
                {
                    int obj_begin = mStream.Position;
                    int obj_size  = 0;
                    mStream.Write(obj_size);

                    if (EncodeInternal(entry.Value.Type, entry.Key) == false)
                    {
                        return(false);
                    }

                    int obj_end = mStream.Position;
                    obj_size         = (int)(obj_end - obj_begin - 4);
                    mStream.Position = obj_begin;
                    mStream.Write(obj_size);
                    mStream.Position = obj_end;
                }
            }
        }

        int end = mStream.Position;

        mStream.Position = begin;
        mStream.Write(fn);
        mStream.Position = end;

        return(true);
    }
Example #26
0
    private SpObject DecodeInternal (SpType type) {
        if (mStream == null || type == null)
            return null;

        // buildin type decoding should not be here
        if (mTypeManager.IsBuildinType (type))
            return null;

        SpObject obj = new SpObject ();

        List<int> tags = new List<int> ();
        int current_tag = 0;

        short fn = mStream.ReadInt16 ();
        for (short i = 0; i < fn; i++) {
            int value = (int)mStream.ReadUInt16 ();

            if (value == 0) {
                tags.Add (current_tag);
                current_tag++;
            }
            else {
                if (value % 2 == 0) {
                    SpField f = type.GetFieldByTag (current_tag);
                    if (f == null)
                        return null;

                    value = value / 2 - 1;
                    if (f.Type == mTypeManager.Integer) {
                        obj.Insert (f.Name, value);
                    }
                    else if (f.Type == mTypeManager.Boolean) {
                        obj.Insert (f.Name, (value == 0 ? false : true));
                    }
                    else {
                        return null;
                    }
                    current_tag++;
                }
                else {
                    current_tag += (value + 1) / 2;
                }
            }
        }

		for (int c = 0; c < tags.Count; c++) {
			int tag = tags[c];

            SpField f = type.GetFieldByTag (tag);
            if (f == null)
                return null;

            if (f.IsTable) {
                int size = mStream.ReadInt32 ();

                if (f.Type == mTypeManager.Integer) {
                    byte n = mStream.ReadByte ();
                    int count = (size - 1) / n;

                    SpObject tbl = new SpObject ();
                    for (int i = 0; i < count; i++) {
                        switch (n) {
                        case 4:
							tbl.Insert (i, mStream.ReadInt32 ());
                            break;
                        case 8:
							tbl.Insert (i, mStream.ReadInt64 ());
                            break;
                        default:
                            return null;
                        }
                    }
					obj.Insert (f.Name, tbl);
                }
                else if (f.Type == mTypeManager.Boolean) {
                    SpObject tbl = new SpObject ();
                    for (int i = 0; i < size; i++) {
						tbl.Insert (i, mStream.ReadBoolean ());
                    }
					obj.Insert (f.Name, tbl);
                }
                else if (f.Type == mTypeManager.String) {
					SpObject tbl = new SpObject ();
					int k = 0;
                    while (size > 0) {
                        int str_len = mStream.ReadInt32 ();
                        size -= 4;
						tbl.Insert (k, Encoding.UTF8.GetString (mStream.ReadBytes (str_len), 0, str_len));
						k++;
                        size -= str_len;
                    }
					obj.Insert (f.Name, tbl);
                }
                else if (f.Type == null) {
                    // unknown type
                    mStream.ReadBytes (size);
                }
                else {
					SpObject tbl = new SpObject ();
					int k = 0;
                    while (size > 0) {
                        int obj_len = mStream.ReadInt32 ();
                        size -= 4;

						SpObject o = DecodeInternal (f.Type);
						if (f.KeyName != null) {
							tbl.Insert (o.AsTable ()[f.KeyName].Value, o);
						}
						else {
							tbl.Insert (k, o);
						}
						k++;
                        size -= obj_len;
                    }
					obj.Insert (f.Name, tbl);
                }
            }
            else {
                int size = mStream.ReadInt32 ();

                if (f.Type == mTypeManager.Integer) {
                    switch (size) {
                    case 4:
                        obj.Insert (f.Name, mStream.ReadInt32 ());
                        break;
                    case 8:
                        obj.Insert (f.Name, mStream.ReadInt64 ());
                        break;
                    default:
                        return null;
                    }
                }
                else if (f.Type == mTypeManager.Boolean) {
                    // boolean should not be here
                    return null;
                }
                else if (f.Type == mTypeManager.String) {
                    obj.Insert (f.Name, Encoding.UTF8.GetString (mStream.ReadBytes (size), 0, size));
                }
                else if (f.Type == null) {
                    // unknown type
                    mStream.ReadBytes (size);
                }
                else {
                    obj.Insert (f.Name, DecodeInternal (f.Type));
                }
            }
        }

        return obj;
    }
Example #27
0
	private SpType NewType (string str) {
        if (str[0] == '.') {
            str = str.Substring (1);
        }
        else {
            if (mLastType != null)
                str = mLastType.Name + "." + str;

            if (mCurrentProtocol != null)
                str = mCurrentProtocol.Name + "." + str;
        }

		SpType t = new SpType (str);
		return t;
	}
Example #28
0
 public StyleSprite[] getStyleSpritesByType(SpType type)
 {
     return(spPrefabDict[type].styleSprites);
 }
Example #29
0
 private bool IsTypeComplete(SpType type)
 {
     return(type.CheckAndUpdate());
 }
Example #30
0
 public GameObject getSpPrefabByType(SpType type)
 {
     return(spPrefabDict[type].prefab);
 }
Example #31
0
    private SpObject DecodeInternal(SpType type)
    {
        if (mStream == null || type == null)
        {
            return(null);
        }

        // buildin type decoding should not be here
        if (mTypeManager.IsBuildinType(type))
        {
            return(null);
        }

        SpObject obj = new SpObject();

        List <int> tags        = new List <int> ();
        int        current_tag = 0;

        short fn = mStream.ReadInt16();

        for (short i = 0; i < fn; i++)
        {
            int value = (int)mStream.ReadUInt16();

            if (value == 0)
            {
                tags.Add(current_tag);
                current_tag++;
            }
            else
            {
                if (value % 2 == 0)
                {
                    SpField f = type.GetFieldByTag(current_tag);
                    if (f == null)
                    {
                        return(null);
                    }

                    value = value / 2 - 1;
                    if (f.Type == mTypeManager.Integer)
                    {
                        obj.Insert(f.Name, value);
                    }
                    else if (f.Type == mTypeManager.Boolean)
                    {
                        obj.Insert(f.Name, (value == 0 ? false : true));
                    }
                    else
                    {
                        return(null);
                    }
                    current_tag++;
                }
                else
                {
                    current_tag += (value + 1) / 2;
                }
            }
        }

        for (int c = 0; c < tags.Count; c++)
        {
            int tag = tags[c];

            SpField f = type.GetFieldByTag(tag);
            if (f == null)
            {
                return(null);
            }

            if (f.IsTable)
            {
                int size = mStream.ReadInt32();

                if (f.Type == mTypeManager.Integer)
                {
                    byte n     = mStream.ReadByte();
                    int  count = (size - 1) / n;

                    SpObject tbl = new SpObject();
                    for (int i = 0; i < count; i++)
                    {
                        switch (n)
                        {
                        case 4:
                            tbl.Insert(i, mStream.ReadInt32());
                            break;

                        case 8:
                            tbl.Insert(i, mStream.ReadInt64());
                            break;

                        default:
                            return(null);
                        }
                    }
                    obj.Insert(f.Name, tbl);
                }
                else if (f.Type == mTypeManager.Boolean)
                {
                    SpObject tbl = new SpObject();
                    for (int i = 0; i < size; i++)
                    {
                        tbl.Insert(i, mStream.ReadBoolean());
                    }
                    obj.Insert(f.Name, tbl);
                }
                else if (f.Type == mTypeManager.String)
                {
                    SpObject tbl = new SpObject();
                    int      k   = 0;
                    while (size > 0)
                    {
                        int str_len = mStream.ReadInt32();
                        size -= 4;
                        tbl.Insert(k, Encoding.UTF8.GetString(mStream.ReadBytes(str_len), 0, str_len));
                        k++;
                        size -= str_len;
                    }
                    obj.Insert(f.Name, tbl);
                }
                else if (f.Type == null)
                {
                    // unknown type
                    mStream.ReadBytes(size);
                }
                else
                {
                    SpObject tbl = new SpObject();
                    int      k   = 0;
                    while (size > 0)
                    {
                        int obj_len = mStream.ReadInt32();
                        size -= 4;

                        SpObject o = DecodeInternal(f.Type);
                        if (f.KeyName != null)
                        {
                            tbl.Insert(o.AsTable()[f.KeyName].Value, o);
                        }
                        else
                        {
                            tbl.Insert(k, o);
                        }
                        k++;
                        size -= obj_len;
                    }
                    obj.Insert(f.Name, tbl);
                }
            }
            else
            {
                int size = mStream.ReadInt32();

                if (f.Type == mTypeManager.Integer)
                {
                    switch (size)
                    {
                    case 4:
                        obj.Insert(f.Name, mStream.ReadInt32());
                        break;

                    case 8:
                        obj.Insert(f.Name, mStream.ReadInt64());
                        break;

                    default:
                        return(null);
                    }
                }
                else if (f.Type == mTypeManager.Boolean)
                {
                    // boolean should not be here
                    return(null);
                }
                else if (f.Type == mTypeManager.String)
                {
                    obj.Insert(f.Name, Encoding.UTF8.GetString(mStream.ReadBytes(size), 0, size));
                }
                else if (f.Type == null)
                {
                    // unknown type
                    mStream.ReadBytes(size);
                }
                else
                {
                    obj.Insert(f.Name, DecodeInternal(f.Type));
                }
            }
        }

        return(obj);
    }