PageRenderTime 30ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/2.0/Source/ExtSupport/WrapperTypeDef.cpp

#
C++ | 442 lines | 322 code | 61 blank | 59 comment | 90 complexity | b6606508f4e0caa63e33bacdc24bf407 MD5 | raw file
Possible License(s): CPL-1.0, GPL-2.0, CC-BY-SA-3.0, MPL-2.0-no-copyleft-exception, Apache-2.0
  1. /*
  2. Copyright (c) 2004-2006 Ladislav Prosek.
  3. The use and distribution terms for this software are contained in the file named License.txt,
  4. which can be found in the root of the Phalanger distribution. By using this software
  5. in any fashion, you are agreeing to be bound by the terms of this license.
  6. You must not remove this notice from this software.
  7. */
  8. //
  9. // ExtSupport - substitute for php4ts.dll/php5ts.dll
  10. //
  11. // WrapperTypeDef.cpp
  12. // - contains definition of FunctionTypeInfo class
  13. // - contains definition of OverloadTypeInfo class
  14. // - contains definition of WrapperTypeDef class
  15. //
  16. #include "stdafx.h"
  17. #include "WrapperTypeDef.h"
  18. using namespace System;
  19. using namespace System::IO;
  20. using namespace System::Xml;
  21. using namespace System::Xml::XPath;
  22. using namespace System::Text;
  23. using namespace System::Collections::Generic;
  24. using namespace PHP::Core;
  25. using namespace PHP::ExtManager;
  26. namespace PHP
  27. {
  28. namespace ExtManager
  29. {
  30. // FunctionTypeInfo implementation:
  31. /// <summary>
  32. /// Adds a parameter type information (left-to-right order).
  33. /// </summary>
  34. /// <param name="param">The parameter.</param>
  35. /// <exception cref="ArgumentException">A mandatory parameter is being added after an optional
  36. /// parameter or vararg parameter is not the last one.</exception>
  37. void FunctionTypeInfo::AddParameter(ParameterTypeInfo ^param)
  38. {
  39. if (VarargParamDefined)
  40. {
  41. throw gcnew ArgumentException(ExtResources::GetString("invalid_vararg_param", Name), "param");
  42. }
  43. switch (param->Optional)
  44. {
  45. case OptionalFlag::Vararg:
  46. VarargParamDefined = true;
  47. break;
  48. case OptionalFlag::Yes:
  49. if (FirstOptionalParamIndex == -1) FirstOptionalParamIndex = Params->Count;
  50. break;
  51. case OptionalFlag::No:
  52. if (FirstOptionalParamIndex >= 0)
  53. {
  54. throw gcnew ArgumentException(ExtResources::GetString("invalid_optional_param", Name));
  55. }
  56. break;
  57. }
  58. Params->Add(param);
  59. }
  60. // Converts this instance to argfull overload type info.
  61. FunctionTypeInfo ^FunctionTypeInfo::ToArgFullSignature()
  62. {
  63. FunctionTypeInfo ^result = Clone();
  64. result->ReturnType = Object::typeid;
  65. result->Params = gcnew scg::List<ParameterTypeInfo ^>(Params->Count);
  66. // convert parameters
  67. for (int i = 0; i < Params->Count; i++)
  68. {
  69. if (Params[i]->Optional != OptionalFlag::Vararg)
  70. {
  71. ParameterTypeInfo ^info = Params[i]->Clone();
  72. info->ParamType = (info->IsOut ? PHP::Core::PhpReference::typeid : Object::typeid);
  73. result->Params->Add(info);
  74. }
  75. }
  76. result->VarargParamDefined = false;
  77. return result;
  78. }
  79. // OverloadTypeInfo implementation:
  80. // Creates a new empty OverloadTypeInfo.
  81. OverloadTypeInfo::OverloadTypeInfo()
  82. {
  83. MarshalBoundVars = MarshalBoundVarsFlag::None;
  84. BindParamMap = gcnew BitArray(0);
  85. ByrefParamMap = gcnew BitArray(0);
  86. ByrefVarargPosition = -1;
  87. VarargPosition = -1;
  88. CastToFalse = false;
  89. IsStatic = false;
  90. ReturnType = Object::typeid;
  91. neverCombined = true;
  92. }
  93. /// Fills this OverloadTypeInfo with information contained in a given FunctionTypeInfo.
  94. void OverloadTypeInfo::Load(FunctionTypeInfo ^info)
  95. {
  96. Name = info->Name;
  97. MarshalBoundVars = info->MarshalBoundVars;
  98. CastToFalse = info->CastToFalse;
  99. ReturnType = info->ReturnType;
  100. IsStatic = info->Static;
  101. // process parameters
  102. for (int j = 0; j < info->Params->Count; j++)
  103. {
  104. ParameterTypeInfo ^param_info = info->GetParameterByIndex(j);
  105. if (param_info->Bind)
  106. {
  107. if (j >= BindParamMap->Count) BindParamMap->Length = j + 1;
  108. BindParamMap->Set(j, true);
  109. }
  110. if (param_info->IsOut)
  111. {
  112. if (j >= ByrefParamMap->Count) ByrefParamMap->Length = j + 1;
  113. ByrefParamMap->Set(j, true);
  114. if (param_info->Optional == OptionalFlag::Vararg)
  115. {
  116. ByrefVarargPosition = j;
  117. }
  118. }
  119. if (param_info->Optional == OptionalFlag::Vararg)
  120. {
  121. VarargPosition = j;
  122. }
  123. }
  124. }
  125. // Combines this OverloadTypeInfo with information contained in a given FunctionTypeInfo.
  126. void OverloadTypeInfo::Combine(FunctionTypeInfo ^info)
  127. {
  128. if (neverCombined)
  129. {
  130. // initialize the AND-combined properties
  131. IsStatic = true;
  132. CastToFalse = true;
  133. }
  134. Name = info->Name;
  135. MarshalBoundVars = MarshalBoundVars | info->MarshalBoundVars;
  136. CastToFalse &= info->CastToFalse;
  137. IsStatic &= info->Static;
  138. if (neverCombined) ReturnType = info->ReturnType;
  139. else
  140. {
  141. if (!ReturnType->Equals(info->ReturnType)) ReturnType = Object::typeid;
  142. }
  143. // process parameters
  144. for (int j = 0; j < info->Params->Count; j++)
  145. {
  146. ParameterTypeInfo ^param_info = info->GetParameterByIndex(j);
  147. if (param_info->Bind)
  148. {
  149. if (j >= BindParamMap->Count) BindParamMap->Length = j + 1;
  150. BindParamMap->Set(j, true);
  151. }
  152. if (param_info->IsOut)
  153. {
  154. if (j >= ByrefParamMap->Count) ByrefParamMap->Length = j + 1;
  155. ByrefParamMap->Set(j, true);
  156. if (param_info->Optional == OptionalFlag::Vararg &&
  157. (ByrefVarargPosition == -1 || ByrefVarargPosition > j)) ByrefVarargPosition = j;
  158. }
  159. if (param_info->Optional == OptionalFlag::Vararg &&
  160. (VarargPosition == -1 || VarargPosition > j)) VarargPosition = j;
  161. }
  162. neverCombined = false;
  163. }
  164. // WrapperTypeDef implementation:
  165. // Reads type information for the extension from the typedef XML file.
  166. ModuleTypeInfo WrapperTypeDef::GetModuleTypeInfo(String ^fileName, StringBuilder ^message,
  167. int estimatedFunctionCount, int estimatedClassCount)
  168. {
  169. String ^xml_file_name;
  170. try
  171. {
  172. xml_file_name = Path::Combine(PHP::Core::Configuration::Application->Paths->ExtTypeDefs,
  173. String::Concat(fileName, ".xml"));
  174. }
  175. catch (ArgumentException ^)
  176. {
  177. message->Append(ExtResources::GetString("invalid_typedef_path",
  178. PHP::Core::Configuration::Application->Paths->ExtTypeDefs));
  179. return ModuleTypeInfo();
  180. }
  181. // read the XML file into DOM
  182. ModuleTypeInfo type_info = ModuleTypeInfo(
  183. gcnew Dictionary<String ^, FunctionTypeInfo ^>(estimatedFunctionCount),
  184. gcnew Dictionary<String ^, ClassTypeInfo ^>(estimatedClassCount),
  185. false);
  186. XmlReader ^reader;
  187. try
  188. {
  189. XmlReaderSettings ^settings = gcnew XmlReaderSettings();
  190. settings->ProhibitDtd = false;
  191. settings->ValidationType = ValidationType::DTD;
  192. //reader = gcnew XmlValidatingReader(gcnew XmlTextReader(xml_file_name));
  193. reader = XmlReader::Create(gcnew XmlTextReader(xml_file_name), settings);
  194. try
  195. {
  196. XmlDocument ^xml_doc = gcnew XmlDocument();
  197. xml_doc->Load(reader);
  198. XPathNavigator ^navigator = xml_doc->CreateNavigator();
  199. // determine the earlyInit attribute
  200. XmlNode ^attr = xml_doc->DocumentElement->Attributes->GetNamedItem("earlyInit");
  201. type_info.EarlyInit = (attr != nullptr && attr->Value->CompareTo("true") == 0);
  202. // iterate over functions
  203. XPathNodeIterator ^iterator = navigator->Select("/module/function");
  204. while (iterator->MoveNext())
  205. {
  206. // get type information for this function
  207. GetFunctionTypeInfo(iterator->Current->Clone(), type_info.Functions);
  208. }
  209. // iterate over classes
  210. iterator = navigator->Select("/module/class");
  211. while (iterator->MoveNext())
  212. {
  213. XPathNavigator ^cls_nav = iterator->Current->Clone();
  214. ClassTypeInfo ^class_type_info = gcnew ClassTypeInfo();
  215. class_type_info->Name = cls_nav->GetAttribute("name", cls_nav->NamespaceURI);
  216. class_type_info->ArrayGetter = cls_nav->GetAttribute("arrayGetter", cls_nav->NamespaceURI);
  217. class_type_info->ArraySetter = cls_nav->GetAttribute("arraySetter", cls_nav->NamespaceURI);
  218. if (class_type_info->ArrayGetter->Length == 0) class_type_info->ArrayGetter = nullptr;
  219. if (class_type_info->ArraySetter->Length == 0) class_type_info->ArraySetter = nullptr;
  220. class_type_info->Methods = gcnew Dictionary<String ^, FunctionTypeInfo ^>();
  221. // iterate over methods
  222. if (cls_nav->MoveToFirstChild())
  223. {
  224. do
  225. {
  226. // get type information for this method
  227. GetFunctionTypeInfo(cls_nav->Clone(), class_type_info->Methods);
  228. }
  229. while (cls_nav->MoveToNext());
  230. }
  231. try
  232. {
  233. type_info.Classes->Add(class_type_info->Name->ToLower(), class_type_info);
  234. }
  235. catch (ArgumentException ^e)
  236. {
  237. throw gcnew Schema::XmlSchemaException(ExtResources::GetString("class_already_defined",
  238. class_type_info->Name, xml_file_name), e);
  239. }
  240. }
  241. }
  242. catch(Exception ^ex)
  243. {
  244. throw gcnew Exception("Unable to load XML typedef.", ex);
  245. }
  246. finally
  247. {
  248. reader->Close();
  249. }
  250. }
  251. catch (FileNotFoundException ^)
  252. {
  253. message->Append(ExtResources::GetString("typedef_not_found", xml_file_name));
  254. return ModuleTypeInfo();
  255. }
  256. catch (Schema::XmlSchemaException ^e)
  257. {
  258. message->Append(ExtResources::GetString("typedef_not_validated", xml_file_name, e->Message));
  259. return ModuleTypeInfo();
  260. }
  261. catch (Exception ^e)
  262. {
  263. message->Append(ExtResources::GetString("typedef_not_parsed", xml_file_name, e->Message));
  264. #ifdef DEBUG
  265. Debug::WriteLine("EXT SUP", e->ToString());
  266. #endif
  267. return ModuleTypeInfo();
  268. }
  269. return type_info;
  270. }
  271. // Adds function type info to the parent type info dictionary.
  272. void WrapperTypeDef::AddFunctionTypeInfo(FunctionTypeInfo ^functionInfo,
  273. Dictionary<String ^, FunctionTypeInfo ^> ^typeInfo)
  274. {
  275. String ^func_name_lower = functionInfo->Name->ToLower();
  276. FunctionTypeInfo ^orig_type_info;
  277. if (typeInfo->TryGetValue(func_name_lower, orig_type_info))
  278. {
  279. // we have more function nodes with the same name -> add this one to the linked list
  280. functionInfo->Next = orig_type_info->Next;
  281. orig_type_info->Next = functionInfo;
  282. }
  283. else typeInfo->Add(func_name_lower, functionInfo);
  284. }
  285. // Reads type information for a function or method from the typedef XML file.
  286. void WrapperTypeDef::GetFunctionTypeInfo(XPathNavigator ^funNav, Dictionary<String ^, FunctionTypeInfo ^> ^typeInfo)
  287. {
  288. FunctionTypeInfo ^func_descr = gcnew FunctionTypeInfo();
  289. String ^func_name;
  290. // get function attributes
  291. func_name = funNav->GetAttribute("name", funNav->NamespaceURI); //->ToLower();
  292. func_descr->Description = funNav->GetAttribute("description", funNav->NamespaceURI);
  293. // returnType
  294. TypeTriple ret_triple;
  295. if (!typeMapping->TryGetValue(funNav->GetAttribute("returnType", funNav->NamespaceURI), ret_triple))
  296. {
  297. ret_triple = typeMapping["mixed"];
  298. }
  299. func_descr->ReturnType = ret_triple.T;
  300. // convert "" into NULL
  301. if (String::Empty->CompareTo(func_name) == 0) func_name = nullptr;
  302. if (String::Empty->CompareTo(func_descr->Description) == 0) func_descr->Description = nullptr;
  303. // castToFalse
  304. String ^cast_false = funNav->GetAttribute("castToFalse", funNav->NamespaceURI);
  305. if (cast_false->CompareTo("true") == 0) func_descr->CastToFalse = true;
  306. // castToFalse
  307. String ^is_static = funNav->GetAttribute("static", funNav->NamespaceURI);
  308. if (is_static->CompareTo("true") == 0) func_descr->Static = true;
  309. // marshalBoundVars
  310. String ^marshal_vars = funNav->GetAttribute("marshalBoundVars", funNav->NamespaceURI);
  311. if (marshal_vars->CompareTo("in") == 0) func_descr->MarshalBoundVars = MarshalBoundVarsFlag::In;
  312. else if (marshal_vars->CompareTo("out") == 0) func_descr->MarshalBoundVars = MarshalBoundVarsFlag::Out;
  313. else if (marshal_vars->CompareTo("inout") == 0) func_descr->MarshalBoundVars = MarshalBoundVarsFlag::InOut;
  314. if (func_name != nullptr)
  315. {
  316. func_descr->Name = func_name;
  317. AddFunctionTypeInfo(func_descr, typeInfo);
  318. // iterate over this function's parameters
  319. if (funNav->MoveToFirstChild())
  320. {
  321. do
  322. {
  323. if (funNav->Name->CompareTo("alias") == 0)
  324. {
  325. // alias subelement
  326. func_descr = func_descr->Clone();
  327. func_descr->Name = funNav->GetAttribute("name", funNav->NamespaceURI);
  328. AddFunctionTypeInfo(func_descr, typeInfo);
  329. }
  330. else
  331. {
  332. // param subelement
  333. ParameterTypeInfo ^param_descr = gcnew ParameterTypeInfo();
  334. // get parameter attributes
  335. param_descr->ParamName = funNav->GetAttribute("name", funNav->NamespaceURI);
  336. String ^opt = funNav->GetAttribute("optional", funNav->NamespaceURI);
  337. if (opt->CompareTo("true") == 0) param_descr->Optional = OptionalFlag::Yes;
  338. else if (opt->CompareTo("vararg") == 0) param_descr->Optional = OptionalFlag::Vararg;
  339. String ^direction = funNav->GetAttribute("direction", funNav->NamespaceURI);
  340. if (direction->CompareTo("inout") == 0) param_descr->Direction = DirectionFlag::InOut;
  341. else if (direction->CompareTo("out") == 0) param_descr->Direction = DirectionFlag::Out;
  342. else param_descr->Direction = DirectionFlag::In;
  343. String ^bind = funNav->GetAttribute("bind", funNav->NamespaceURI);
  344. if (bind->CompareTo("true") == 0)
  345. {
  346. param_descr->Bind = true;
  347. if (param_descr->Optional == OptionalFlag::Vararg)
  348. {
  349. param_descr->ParamType = array<PhpReference ^>::typeid;
  350. }
  351. else param_descr->ParamType = PhpReference::typeid;
  352. }
  353. else
  354. {
  355. String ^type_name = funNav->GetAttribute("type", funNav->NamespaceURI);
  356. // pick the right type mapping from hashtable
  357. TypeTriple triple;
  358. if (!typeMapping->TryGetValue(type_name, triple)) triple = typeMapping["mixed"];
  359. if (param_descr->Optional == OptionalFlag::Vararg)
  360. {
  361. param_descr->ParamType = triple.Tarr;
  362. }
  363. else
  364. {
  365. if (param_descr->IsOut) param_descr->ParamType = triple.Tref;
  366. else param_descr->ParamType = triple.T;
  367. }
  368. }
  369. func_descr->AddParameter(param_descr);
  370. }
  371. }
  372. while (funNav->MoveToNext());
  373. }
  374. }
  375. }
  376. }
  377. }