Exemplo n.º 1
0
		/// <summary>
		/// Метод десериализации объекта.
		/// </summary>
		/// <param name="stream">Поток десериализации.</param>
		/// <param name="root">Объект, в который будет производится десериализация.</param>
		/// <returns></returns>
		public static object Deserialize(Stream stream, object root, bool isLoad = false)
		{
			try
			{
				if(stream == null)
					throw new ArgumentNullException("stream");
				if(stream.CanRead == false)
					throw new Exception("Указанный поток десериализации не позволяет чтение!");

				DeserContext cox = new DeserContext(stream);

				ushort typeID;
				while((typeID = stream.ReadUInt16()) < ushort.MaxValue)
				{
					if(typeID == 0)
					{
						SerTypeInfo sti = new SerTypeInfo();
						sti.Load(stream);
						cox.types.Process(sti);
						continue;
					}
					if(typeID == (ushort)InfraTypes.GOLObjectRegistrator)
					{		
						#region
						ushort xx = stream.ReadUInt16();
						Type stt = cox.types[xx];
						uint stid = stream.ReadUInt32();
						OID stoid = (OID)FromBytes(typeof(OID), stream.ReadBytes(16));
						GlobalObject go = GOL.Get(stoid);
						if(go != null)
						{
							if(GOL.IsInitMode == false && isLoad == false && Pulsar.Server.ServerParamsBase.IsServer)
								throw new Exception("Попытка перезаписать объект на сервере!");
							if(go.Equals(root) == false)
								cox.objs.Add(stid, new DeserObj(go));
						}
						else
						{
							if(root != null && root is GlobalObject && ((GlobalObject)root).OID == stoid)
							{
								go = (GlobalObject)root;
								root = null;
							}
							else
							{
								object obj = FormatterServices.GetUninitializedObject(stt);
								if(obj is GlobalObject == false)
									throw new SerializationException(String.Format("Тип [{0}] не наследует GlobalObject!", stt.FullName));
								go = (GlobalObject)obj;
								go.OID = stoid;
							}
							cox.objs.Add(stid, new DeserObj(go));
							////GOL.AddUninitialized(go, 0, null);
							GOL.Add(go);
						}
						if(isLoad == false)
							go.BeginWrite();

						#endregion
						continue;
					}
					if(typeID == (ushort)InfraTypes.GOLObjectStub)
					{
						#region
						Type stt = cox.types[stream.ReadUInt16()];
						uint stid = stream.ReadUInt32();
						OID stoid = (OID)FromBytes(typeof(OID), stream.ReadBytes(16));

						GlobalObject go = GOL.Locate(stt,stoid);
						if(go != null)
						{
							cox.objs.Add(stid, new DeserObj(go));
							if(go.IsInitialized)
							 cox.objs[stid].WaitsCount = 0;
							else
							{
								if(cox.lateLoad.Contains(stid) == false)
									cox.lateLoad.Add(stid);
							}
							////if(GOL.IsUninitialized(stoid) == false)
							//// cox.objs[stid].WaitsCount = 0;
							////else
							////{
							//// GOL.AddUninitialized(go, stid, cox);
							//// if(cox.lateLoad.Contains(stid) == false)
							////  cox.lateLoad.Add(stid);
							////}
						}
						else /*if(GOL.LateInitMode == GOLLateInitModes.AllowAll ||
														(GOL.LateInitMode == GOLLateInitModes.AllowEssences && 
															stt.IsDefined(typeof(PulsarEssenceAttribute), true)))*/
						{
							object obj = FormatterServices.GetUninitializedObject(stt);
							if(obj is GlobalObject == false)
								throw new SerializationException(String.Format("Тип [{0}] не наследует IGOLObject!", stt.FullName));

							go = (GlobalObject)obj;
							go.OID = stoid;
							cox.objs.Add(stid, new DeserObj(go));
							////GOL.AddUninitialized(go, stid, cox);
							GOL.Add(go);
							cox.lateLoad.Add(stid);
						}
						//else
						// throw new SerializationException(String.Format("Заглушка объекта {{{0}}} типа [{1}] не раскрыта!",
						//  stoid, stt.FullName));
						#endregion
						continue;
					}

					SerObjectInfo si = new SerObjectInfo();
					si.typeID = typeID;
					si.Load(stream);

					Type t = cox.types[si.typeID];
					DeserObj siObjID = null;

					if(typeID == (ushort)InfraTypes.PulsarPrimitiveHolder)
					{
						SerFieldInfo fsi = si.index["Primitive"];
						t = cox.types[fsi.typeID];
						Object val = null;
						if(typeof(ISelfSerialization).IsAssignableFrom(t))
						{
							val = root == null ? FormatterServices.GetUninitializedObject(t) : root;
							var tw = TypeSerializationWrap.GetTypeSerializationWrap(t);
							tw.OnDeserializing(val);
							((ISelfSerialization)val).Deserialize(fsi.value);
							tw.OnDeserialized(val);
						}
						else
							val = FromBytes(t, fsi.value);
						return val;
					}



					if(root == null) // && cox.objs.Count == 0)				 && t != typeof(PulsarPrimitiveHolder)
						cox.objs.TryGetValue(si.objID, out siObjID);
					else
					{
						if(t.IsAssignableFrom(root.GetType()) == false || si.index == null || si.index.ContainsKey("$root$") == false)
							throw new Exception("Данные сериализации не соответствуют объекту root!");
						cox.objs.Add(si.objID, siObjID = new DeserObj(root));
						if(si.index.ContainsKey("oid"))
							((GlobalObject)root).OID = (OID)FromBytes(typeof(OID),si.index["oid"].value);
						root = null;
					}

					if(t == typeof(PulsarEmptyStub))
					{
						#region
						t = cox.types[si.index[""].typeID];
						if(siObjID == null)
							cox.objs.Add(si.objID, siObjID = new DeserObj(t));
						siObjID.IsEmpty = true;
						ConstructorInfo ci = t.GetConstructor(fieldsDiscovery, null, Type.EmptyTypes, null);
						if(ci != null)
							ci.Invoke(siObjID.Obj, null);
						if(si.index.ContainsKey("oid") && siObjID.Obj is GlobalObject)  //  
							if(siObjID.Obj is GlobalObject)
								((GlobalObject)siObjID.Obj).OID =  new OID(si.index["oid"].value);
							else
							{
								InterfaceMapping im = t.GetInterfaceMap(typeof(IOIDObject));
								if(im.TargetMethods.Length == 0)
									throw new SerializationException(String.Format("Тип [{0}] не содержит свойство OID!", t.FullName));
								if(t != im.TargetMethods[0].DeclaringType)
									t = im.TargetMethods[0].DeclaringType;
								PropertyInfo pi = t.GetProperty("OID", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
								if(pi == null)
									throw new SerializationException(String.Format("Тип [{0}] не содержит свойство OID!", t.FullName));
								MethodInfo mi = pi.GetSetMethod(true);
								if(mi == null)
									throw new SerializationException(String.Format("Тип [{0}] не реализует set метод для свойства OID!",
																																																																				siObjID.Obj.GetType().FullName));
								mi.Invoke(siObjID.Obj, new object[] { new OID(si.index["oid"].value) });
							}
						#endregion
						siObjID.WaitsCount = 0;
					}

					if(siObjID == null)
						//if(typeof(GlobalObject).IsAssignableFrom(t))
						// if(pars
						// throw new Exception("Попытка создать объект Пульсара вне GOL!");
						//else
							cox.objs.Add(si.objID, siObjID = new DeserObj(t));
					if(siObjID.WaitsCount != 0)
						CallOnDeserializing(siObjID.Obj);

					if(siObjID.WaitsCount != 0 &&  siObjID.Obj is ISerializable)
					{
						if(siObjID.WaitsCount == -1)
							siObjID.WaitsCount = 0;
						#region
						siObjID.Tag = new object[2];
						SerFieldInfo fsi = si.index["m_members"];
						object val = null;
						UnPackArray(ref val, fsi.value, typeof(string), si.objID, cox);
						((object[])siObjID.Tag)[0] = val;

						val = null;
						fsi = si.index["m_data"];
						UnPackArray(ref val, fsi.value, typeof(object), si.objID, cox);
						((object[])siObjID.Tag)[1] = val;

						if(siObjID.WaitsCount != 0)
							continue;
						#endregion
					}

					if(siObjID.WaitsCount == 0)
					{
						OnFullDeser(cox, si.objID, true);
						continue;
					}

					string pref = "";
					if(siObjID.WaitsCount == -1)
						siObjID.WaitsCount = 0;
					while(t != typeof(object))
					{
						foreach(FieldWrap fw in TypeSerializationWrap.GetTypeSerializationWrap(t).Fields)
						{
							if(si.index == null || si.index.ContainsKey(pref + fw.Name) == false)
								continue;

							SerFieldInfo fsi = si.index[pref + fw.Name];
							Type valType = cox.types[fsi.typeID];
							object val = null; 

							if(fsi.typeID <= 25 || valType.IsEnum  || fsi.typeID == (uint)InfraTypes.RefString)
									//) && fsi.typeID != 18  && fsi.typeID != 19 )
								val = FromBytes(valType, fsi.value);
							else if(typeof(ISelfSerialization).IsAssignableFrom(valType))
							{
								val = FormatterServices.GetUninitializedObject(valType);
								TypeSerializationWrap tw = TypeSerializationWrap.GetTypeSerializationWrap(valType);
								tw.OnDeserializing(val);
								((ISelfSerialization)val).Deserialize(fsi.value);
								tw.OnDeserialized(val);
							}
							else if(valType == typeof(Type))
								val = cox.types[BitConverter.ToUInt16(fsi.value, 0)];
							else if(valType.IsArray)
								UnPackArray(ref val, fsi.value, valType.GetElementType(), si.objID, cox);
							else
							{
								uint id = BitConverter.ToUInt32(fsi.value, 0);

								DeserObj dObj = null;

								if(cox.objs.TryGetValue(id, out dObj)) //  cox.objs.ContainsKey(id)
								{
									if(dObj.WaitsCount == 0)
										val = dObj.Obj;
									else
									{
										siObjID.WaitsCount++;

										List<LateDeserInfo> lll;
										if(cox.lateSet.TryGetValue(id, out lll) == false)
											cox.lateSet.Add(id, lll = new List<LateDeserInfo>());
										lll.Add(new LateDeserInfo(si.objID, fw));
										continue;
									}
								}
								else
								{
									// Противоречит "глубокой" сериализации
									//if(typeof(GlobalObject).IsAssignableFrom(valType))
									// throw new Exception("Попытка создать GlobalObject вне GOL!");
									cox.objs.Add(id, new DeserObj(valType));
									siObjID.WaitsCount++;
									
									List<LateDeserInfo> lll;
									if(cox.lateSet.TryGetValue(id, out lll) == false)
										cox.lateSet.Add(id, lll = new List<LateDeserInfo>());
									lll.Add(new LateDeserInfo(si.objID, fw));
									continue;
								}
							}
							fw.Set(siObjID.Obj, val);
						}
						t = t.BaseType;
						if(t == null || t == typeof(object))
							break;
						pref += '.';
					}

					if(siObjID.WaitsCount == 0)
						OnFullDeser(cox, si.objID, true);
				}
				if(cox.lateSet.Count > 0) //!! && GOL.LateInitMode != GOLLateInitModes.AllowAll)
				{
					#region
					////List<GlobalObject> toLoad = new List<GlobalObject>(cox.lateLoad.Count);
					////foreach(uint i in cox.lateLoad)
					//// if(cox.objs[i].Obj is GlobalObject)
					////  toLoad.Add((GlobalObject)cox.objs[i].Obj);
					//// else
					////  throw new Exception("Найдено неразрешимое кольцевое замыкание объектов!");
					////if(toLoad.Count == 0)
					//// throw new Exception("Найдено неразрешимое кольцевое замыкание объектов!");
					////GOL.LoadGlobalObjects(toLoad);

					if(cox.lateLoad.Count > 0)
						GOL.LoadGlobalObjects(cox.lateLoad.ForEach((i)=> (GlobalObject)	cox.objs[i].Obj));

					foreach(uint i in cox.lateLoad)
					{
					 GlobalObject go = (GlobalObject)	cox.objs[i].Obj;
						if(go.IsInitialized)
							OnFullDeser(cox,i,false);
						else
						 throw new PulsarException("Не удалось загрузить глобальный объект [{0}] типа {1}!", go.OID, go.GetType());
					}		 
					if(cox.lateSet.Count != 0)
						throw new Exception("Найдено неразрешимое кольцевое замыкание объектов!");
					#endregion
				}
				if(cox.objs.Count == 0)
					return null;
				//if(cox.objs[1].Obj is PulsarPrimitiveHolder)
				// return ((PulsarPrimitiveHolder)cox.objs[1].Obj).Primitive;
				return cox.objs[1].Obj;
			}
			catch
			{
				//--- Debbuger Break --- //
				if(System.Diagnostics.Debugger.IsAttached)
					System.Diagnostics.Debugger.Break();
				//--- Debbuger Break --- //
				throw;
			}
		}