X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Ftools%2Fmdoc%2FMono.Documentation%2Fmonodocer.cs;h=7d54a28947b1f8da02de4832e9b490b9df27175a;hb=bc9d5d113ab7064fc199a2f430751643466cb477;hp=09763096e5592bb4d1ab98594760c1f2d95e9bea;hpb=84ab6a7833d8af7702e0359791ce8c4f754991a5;p=mono.git diff --git a/mcs/tools/mdoc/Mono.Documentation/monodocer.cs b/mcs/tools/mdoc/Mono.Documentation/monodocer.cs index 09763096e55..7d54a28947b 100644 --- a/mcs/tools/mdoc/Mono.Documentation/monodocer.cs +++ b/mcs/tools/mdoc/Mono.Documentation/monodocer.cs @@ -187,6 +187,11 @@ class MDocUpdater : MDocCommand return !string.IsNullOrWhiteSpace (droppedNamespace) && droppedAssemblies.Any(da => da == forModule.Name); } + public static bool HasDroppedAnyNamespace () + { + return !string.IsNullOrWhiteSpace (droppedNamespace); + } + static List droppedAssemblies = new List(); @@ -444,8 +449,10 @@ class MDocUpdater : MDocCommand } if (r == null) continue; - c.Remove (n); - c.InsertBefore (n, r); + if (c [n.Name] != null) { + c.RemoveNamedItem (n.Name); + c.InsertBefore (n, r); + } } } @@ -671,12 +678,6 @@ class MDocUpdater : MDocCommand XmlElement td = StubType(type, output); if (td == null) return null; - - System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo (DocUtils.PathCombine (dest, type.Namespace)); - if (!dir.Exists) { - dir.Create(); - Console.WriteLine("Namespace Directory Created: " + type.Namespace); - } } return reltypefile; } @@ -980,7 +981,7 @@ class MDocUpdater : MDocCommand throw new ArgumentException ("Unknown kind for type: " + type.FullName); } - private static bool IsPublic (TypeDefinition type) + public static bool IsPublic (TypeDefinition type) { TypeDefinition decl = type; while (decl != null) { @@ -1005,18 +1006,64 @@ class MDocUpdater : MDocCommand XmlElement e = doc.SelectSingleNode("/Type") as XmlElement; string assemblyName = doc.SelectSingleNode ("/Type/AssemblyInfo/AssemblyName").InnerText; AssemblyDefinition assembly = assemblies.FirstOrDefault (a => a.Name.Name == assemblyName); - if (e != null && !no_assembly_versions && assembly != null && assemblyName != null && UpdateAssemblyVersions(e, assembly, GetAssemblyVersions(assemblyName), false)) { + + Action saveDoc = () => { using (TextWriter writer = OpenWrite (typefile.FullName, FileMode.Truncate)) WriteXml(doc.DocumentElement, writer); + }; + + if (e != null && !no_assembly_versions && assembly != null && assemblyName != null && UpdateAssemblyVersions (e, assembly, GetAssemblyVersions(assemblyName), false)) { + saveDoc (); goodfiles.Add (relTypeFile); continue; } - if (string.IsNullOrWhiteSpace (PreserveTag)) { // only do this if there was no -preserve + Action actuallyDelete = () => { string newname = typefile.FullName + ".remove"; - try { System.IO.File.Delete(newname); } catch (Exception) { } - try { typefile.MoveTo(newname); } catch (Exception) { } - Console.WriteLine("Class no longer present; file renamed: " + Path.Combine(nsdir.Name, typefile.Name)); + try { System.IO.File.Delete (newname); } catch (Exception) { Warning ("Unable to delete existing file: {0}", newname); } + try { typefile.MoveTo (newname); } catch (Exception) { Warning ("Unable to rename to: {0}", newname); } + Console.WriteLine ("Class no longer present; file renamed: " + Path.Combine (nsdir.Name, typefile.Name)); + }; + + if (string.IsNullOrWhiteSpace (PreserveTag)) { // only do this if there was not a -preserve + saveDoc (); + + var unifiedAssemblyNode = doc.SelectSingleNode ("/Type/AssemblyInfo[@apistyle='unified']"); + var classicAssemblyNode = doc.SelectSingleNode ("/Type/AssemblyInfo[@apistyle='classic']"); + var unifiedMembers = doc.SelectNodes ("//Member[@apistyle='unified']|//Member/AssemblyInfo[@apistyle='unified']"); + var classicMembers = doc.SelectNodes ("//Member[@apistyle='classic']|//Member/AssemblyInfo[@apistyle='classic']"); + bool isUnifiedRun = HasDroppedAnyNamespace (); + bool isClassicOrNormalRun = !isUnifiedRun; + + Action removeStyles = (x, style) => { + var styledNodes = doc.SelectNodes("//*[@apistyle='"+ style.ToString ().ToLowerInvariant () +"']"); + if (styledNodes != null && styledNodes.Count > 0) { + foreach(var node in styledNodes.Cast ()) { + node.ParentNode.RemoveChild (node); + } + } + saveDoc (); + }; + if (isClassicOrNormalRun) { + if (unifiedAssemblyNode != null || unifiedMembers.Count > 0) { + Warning ("*** this type is marked as unified, not deleting during this run: {0}", typefile.FullName); + // if truly removed from both assemblies, it will be removed fully during the unified run + removeStyles (doc, ApiStyle.Classic); + continue; + } else { + // we should be safe to delete here because it was not marked as a unified assembly + actuallyDelete (); + } + } + if (isUnifiedRun) { + if (classicAssemblyNode != null || classicMembers.Count > 0) { + Warning ("*** this type is marked as classic, not deleting {0}", typefile.FullName); + continue; + } else { + // safe to delete because it wasn't marked as a classic assembly, so the type is gone in both. + actuallyDelete (); + } + } } } } @@ -1112,6 +1159,16 @@ class MDocUpdater : MDocCommand foreach (DocsNodeInfo info in docEnum.GetDocumentationMembers (basefile, type)) { XmlElement oldmember = info.Node; MemberReference oldmember2 = info.Member; + + if (info.Member != null && info.Node != null) { + // Check for an error condition where the xml MemberName doesn't match the matched member + var memberName = GetMemberName (info.Member); + var memberAttribute = info.Node.Attributes ["MemberName"]; + if (memberAttribute == null || (memberAttribute.Value != memberName && memberAttribute.Value.Split (',').Length != memberName.Split (',').Length)) { + oldmember.SetAttribute ("MemberName", memberName); + } + } + string sig = oldmember2 != null ? memberFormatters [0].GetDeclaration (oldmember2) : null; // Interface implementations and overrides are deleted from the docs @@ -1164,6 +1221,27 @@ class MDocUpdater : MDocCommand string sig = memberFormatters [0].GetDeclaration (m); if (sig == null) return false; if (seenmembers.ContainsKey(sig)) return false; + + // Verify that the member isn't an explicitly implemented + // member of an internal interface, in which case we shouldn't return true. + MethodDefinition methdef = null; + if (m is MethodDefinition) + methdef = m as MethodDefinition; + else if (m is PropertyDefinition) { + var prop = m as PropertyDefinition; + methdef = prop.GetMethod ?? prop.SetMethod; + } + + if (methdef != null) { + TypeReference iface; + MethodReference imethod; + + if (methdef.Overrides.Count == 1) { + DocUtils.GetInfoForExplicitlyImplementedMethod (methdef, out iface, out imethod); + if (!IsPublic (iface.Resolve ())) return false; + } + } + return true; }) .ToArray(); @@ -1270,34 +1348,54 @@ class MDocUpdater : MDocCommand string format = output != null ? "{0}: File='{1}'; Signature='{4}'" : "{0}: XPath='/Type[@FullName=\"{2}\"]/Members/Member[@MemberName=\"{3}\"]'; Signature='{4}'"; + string signature = member.SelectSingleNode ("MemberSignature[@Language='C#']/@Value").Value; Warning (format, reason, output, member.OwnerDocument.DocumentElement.GetAttribute ("FullName"), member.Attributes ["MemberName"].Value, - member.SelectSingleNode ("MemberSignature[@Language='C#']/@Value").Value); - if (!delete && MemberDocsHaveUserContent (member)) { - Warning ("Member deletions must be enabled with the --delete option."); - } else if (HasDroppedNamespace (type)) { - // if we're dropping the namespace, add the "classic style" - var existingAttribute = member.Attributes ["apistyle"]; - if (existingAttribute != null) { - existingAttribute.Value = "classic"; - } else { - // add the attribute and do not remove - XmlAttribute apistyleAttr = member.OwnerDocument.CreateAttribute ("apistyle"); + signature); - apistyleAttr.Value = "classic"; + // Identify all of the different states that could affect our decision to delete the member + bool shouldPreserve = !string.IsNullOrWhiteSpace (PreserveTag); + bool hasContent = MemberDocsHaveUserContent (member); + bool shouldDelete = !shouldPreserve && (delete || !hasContent); - member.Attributes.Append (apistyleAttr); - } - } else if (!HasDroppedNamespace (type) && member.Attributes ["apistyle"] != null && member.Attributes ["apistyle"].Value == "unified") { - // do nothing if there's an apistyle=new attribute and we haven't dropped the namespace - } else if (!string.IsNullOrWhiteSpace (PreserveTag)) { - // do nothing - } else { + bool unifiedRun = HasDroppedNamespace (type); + + var classicAssemblyInfo = member.SelectSingleNode ("AssemblyInfo[@apistyle='classic']"); + bool nodeIsClassic = classicAssemblyInfo != null || member.HasApiStyle (ApiStyle.Classic); + var unifiedAssemblyInfo = member.SelectSingleNode ("AssemblyInfo[@apistyle='unified']"); + bool nodeIsUnified = unifiedAssemblyInfo != null || member.HasApiStyle (ApiStyle.Unified); + + Action actuallyDelete = () => { todelete.Add (member); deletions++; + }; + + if (!shouldDelete) { + // explicitly not deleting + string message = shouldPreserve ? + "Not deleting '{0}' due to --preserve." : + "Not deleting '{0}'; must be enabled with the --delete option"; + Warning (message, signature); + } else if (unifiedRun && nodeIsClassic) { + // this is a unified run, and the member doesn't exist, but is marked as being in the classic assembly. + member.RemoveApiStyle (ApiStyle.Unified); + Warning ("Not removing '{0}' since it's still in the classic assembly.", signature); + } else if (unifiedRun && !nodeIsClassic) { + // unified run, and the node is not classic, which means it doesn't exist anywhere. + actuallyDelete (); + } else { + if (!nodeIsClassic && !nodeIsUnified) { // regular codepath (ie. not classic/unified) + actuallyDelete (); + } else { // this is a classic run + Warning ("Removing classic from '{0}' ... will be removed in the unified run if not present there.", signature); + member.RemoveApiStyle (ApiStyle.Classic); + if (classicAssemblyInfo != null) { + member.RemoveChild (classicAssemblyInfo); + } + } } } @@ -2326,40 +2424,27 @@ class MDocUpdater : MDocCommand public static string MakeAttributesValueString (object v, TypeReference valueType) { - if (v == null) - return "null"; - if (valueType.FullName == "System.Type") { - var vTypeRef = v as TypeReference; - if (vTypeRef != null) - return "typeof(" + NativeTypeManager.GetTranslatedName (vTypeRef) + ")"; // TODO: drop NS handling - else - return "typeof(" + v.ToString () + ")"; + var formatters = new [] { + new AttributeValueFormatter (), + new ApplePlatformEnumFormatter (), + new StandardFlagsEnumFormatter (), + new DefaultAttributeValueFormatter (), + }; + + ResolvedTypeInfo type = new ResolvedTypeInfo (valueType); + foreach (var formatter in formatters) { + string formattedValue; + if (formatter.TryFormatValue (v, type, out formattedValue)) { + return formattedValue; } - if (valueType.FullName == "System.String") - return "\"" + v.ToString () + "\""; - if (valueType.FullName == "System.Char") - return "'" + v.ToString () + "'"; - if (v is Boolean) - return (bool)v ? "true" : "false"; - TypeDefinition valueDef = valueType.Resolve (); - if (valueDef == null || !valueDef.IsEnum) - return v.ToString (); - string typename = GetDocTypeFullName (valueType); - var values = GetEnumerationValues (valueDef); - long c = ToInt64 (v); - if (values.ContainsKey (c)) - return typename + "." + values [c]; - if (valueDef.CustomAttributes.Any (ca => ca.AttributeType.FullName == "System.FlagsAttribute")) { - return string.Join (" | ", - (from i in values.Keys - where (c & i) != 0 - select typename + "." + values [i]) - .DefaultIfEmpty (v.ToString ()).ToArray ()); } - return "(" + GetDocTypeFullName (valueType) + ") " + v.ToString (); + + // this should never occur because the DefaultAttributeValueFormatter will always + // successfully format the value ... but this is needed to satisfy the compiler :) + throw new InvalidDataException (string.Format ("Unable to format attribute value ({0})", v.ToString ())); } - private static Dictionary GetEnumerationValues (TypeDefinition type) + internal static IDictionary GetEnumerationValues (TypeDefinition type) { var values = new Dictionary (); foreach (var f in @@ -2371,7 +2456,7 @@ class MDocUpdater : MDocCommand return values; } - static long ToInt64 (object value) + internal static long ToInt64 (object value) { if (value is ulong) return (long) (ulong) value; @@ -2874,21 +2959,41 @@ enum ApiStyle { static class DocUtils { public static bool DoesNotHaveApiStyle(this XmlElement element, ApiStyle style) { - string styleString = style.ToString ().ToLower (); + string styleString = style.ToString ().ToLowerInvariant (); string apistylevalue = element.GetAttribute ("apistyle"); return apistylevalue != styleString || string.IsNullOrWhiteSpace(apistylevalue); } public static bool HasApiStyle(this XmlElement element, ApiStyle style) { - string styleString = style.ToString ().ToLower (); + string styleString = style.ToString ().ToLowerInvariant (); return element.GetAttribute ("apistyle") == styleString; } + public static bool HasApiStyle(this XmlNode node, ApiStyle style) + { + var attribute = node.Attributes ["apistyle"]; + return attribute != null && attribute.Value == style.ToString ().ToLowerInvariant (); + } public static void AddApiStyle(this XmlElement element, ApiStyle style) { - string styleString = style.ToString ().ToLower (); + string styleString = style.ToString ().ToLowerInvariant (); var existingValue = element.GetAttribute ("apistyle"); if (string.IsNullOrWhiteSpace (existingValue) || existingValue != styleString) { element.SetAttribute ("apistyle", styleString); } } + public static void RemoveApiStyle (this XmlElement element, ApiStyle style) + { + string styleString = style.ToString ().ToLowerInvariant (); + string existingValue = element.GetAttribute ("apistyle"); + if (string.IsNullOrWhiteSpace (existingValue) || existingValue == styleString) { + element.RemoveAttribute ("apistyle"); + } + } + public static void RemoveApiStyle (this XmlNode node, ApiStyle style) + { + var styleAttribute = node.Attributes ["apistyle"]; + if (styleAttribute != null && styleAttribute.Value == style.ToString ().ToLowerInvariant ()) { + node.Attributes.Remove (styleAttribute); + } + } public static bool IsExplicitlyImplemented (MethodDefinition method) { @@ -3023,7 +3128,7 @@ static class DocUtils { if (!inheritedInterfaces.Contains (GetQualifiedTypeName (lookup))) userInterfaces.Add (iface); } - return userInterfaces; + return userInterfaces.Where (i => MDocUpdater.IsPublic (i.Resolve ())); } private static string GetQualifiedTypeName (TypeReference type) @@ -3189,7 +3294,7 @@ class DocumentationEnumerator { string docName = member.MemberName; - string[] docTypeParams = GetTypeParameters (docName); + string[] docTypeParams = GetTypeParameters (docName, member.TypeParameters); // If we're using 'magic types', then we might get false positives ... in those cases, we keep searching MemberReference likelyCandidate = null; @@ -3209,16 +3314,21 @@ class DocumentationEnumerator { if (mi is MethodDefinition) { MethodDefinition mb = (MethodDefinition) mi; pis = mb.Parameters; - if (docTypeParams != null && mb.IsGenericMethod ()) { + if (mb.IsGenericMethod ()) { IList args = mb.GenericParameters; - if (args.Count == docTypeParams.Length) { - typeParams = args.Select (p => p.Name).ToArray (); - } + typeParams = args.Select (p => p.Name).ToArray (); } } else if (mi is PropertyDefinition) pis = ((PropertyDefinition)mi).Parameters; - + + // check type parameters + int methodTcount = member.TypeParameters == null ? 0 : member.TypeParameters.Count; + int reflectionTcount = typeParams == null ? 0 : typeParams.Length; + if (methodTcount != reflectionTcount) + continue; + + // check member parameters int mcount = member.Parameters == null ? 0 : member.Parameters.Count; int pcount = pis == null ? 0 : pis.Count; if (mcount != pcount) @@ -3294,7 +3404,7 @@ class DocumentationEnumerator { return likelyCandidate; } - static string[] GetTypeParameters (string docName) + static string[] GetTypeParameters (string docName, IEnumerable knownParameters) { if (docName [docName.Length-1] != '>') return null; @@ -3311,7 +3421,12 @@ class DocumentationEnumerator { } while (--i >= 0); types.Reverse (); - return types.ToArray (); + var arrayTypes = types.ToArray (); + + if (knownParameters != null && knownParameters.Any () && arrayTypes.Length != knownParameters.Count ()) + return knownParameters.ToArray (); + else + return arrayTypes; } protected static IEnumerable GetReflectionMembers (TypeDefinition type, string docName) @@ -3772,6 +3887,7 @@ class DocumentationMember { public StringToStringMap MemberSignatures = new StringToStringMap (); public string ReturnType; public StringList Parameters; + public StringList TypeParameters; public string MemberName; public string MemberType; @@ -3781,6 +3897,7 @@ class DocumentationMember { int depth = reader.Depth; bool go = true; StringList p = new StringList (); + StringList tp = new StringList (); do { if (reader.NodeType != XmlNodeType.Element) continue; @@ -3808,6 +3925,10 @@ class DocumentationMember { if (reader.Depth == depth + 2 && shouldUse) p.Add (reader.GetAttribute ("Type")); break; + case "TypeParameter": + if (reader.Depth == depth + 2 && shouldUse) + tp.Add (reader.GetAttribute ("Name")); + break; case "Docs": if (reader.Depth == depth + 1) go = false; @@ -3817,6 +3938,11 @@ class DocumentationMember { if (p.Count > 0) { Parameters = p; } + if (tp.Count > 0) { + TypeParameters = tp; + } else { + DiscernTypeParameters (); + } } public DocumentationMember (XmlNode node) @@ -3840,6 +3966,27 @@ class DocumentationMember { for (int i = 0; i < p.Count; ++i) Parameters.Add (p [i].Attributes ["Type"].Value); } + XmlNodeList tp = node.SelectNodes ("TypeParameters/TypeParameter[not(@apistyle) or @apistyle='classic']"); + if (tp.Count > 0) { + TypeParameters = new StringList (tp.Count); + for (int i = 0; i < tp.Count; ++i) + TypeParameters.Add (tp [i].Attributes ["Name"].Value); + } + else { + DiscernTypeParameters (); + } + } + + void DiscernTypeParameters () + { + // see if we can discern the param list from the name + if (MemberName.Contains ("<") && MemberName.EndsWith (">")) { + var starti = MemberName.IndexOf ("<") + 1; + var endi = MemberName.LastIndexOf (">"); + var paramlist = MemberName.Substring (starti, endi - starti); + var tparams = paramlist.Split (new char[] {','}, StringSplitOptions.RemoveEmptyEntries); + TypeParameters = new StringList (tparams); + } } } @@ -4351,7 +4498,7 @@ class ILFullMemberFormatter : MemberFormatter { buf.Append (full.GetName (type.BaseType).Substring ("class ".Length)); } bool first = true; - foreach (var name in type.Interfaces + foreach (var name in type.Interfaces.Where (i => MDocUpdater.IsPublic (i.Resolve ())) .Select (i => full.GetName (i)) .OrderBy (n => n)) { if (first) { @@ -5604,4 +5751,190 @@ class FileNameMemberFormatter : SlashDocMemberFormatter { } } +class ResolvedTypeInfo { + TypeDefinition typeDef; + + public ResolvedTypeInfo (TypeReference value) { + Reference = value; + } + + public TypeReference Reference { get; private set; } + + public TypeDefinition Definition { + get { + if (typeDef == null) { + typeDef = Reference.Resolve (); + } + return typeDef; + } + } +} + +/// Formats attribute values. Should return true if it is able to format the value. +class AttributeValueFormatter { + public virtual bool TryFormatValue (object v, ResolvedTypeInfo type, out string returnvalue) + { + TypeReference valueType = type.Reference; + if (v == null) { + returnvalue = "null"; + return true; + } + if (valueType.FullName == "System.Type") { + var vTypeRef = v as TypeReference; + if (vTypeRef != null) + returnvalue = "typeof(" + NativeTypeManager.GetTranslatedName (vTypeRef) + ")"; // TODO: drop NS handling + else + returnvalue = "typeof(" + v.ToString () + ")"; + + return true; + } + if (valueType.FullName == "System.String") { + returnvalue = "\"" + v.ToString () + "\""; + return true; + } + if (valueType.FullName == "System.Char") { + returnvalue = "'" + v.ToString () + "'"; + return true; + } + if (v is Boolean) { + returnvalue = (bool)v ? "true" : "false"; + return true; + } + + TypeDefinition valueDef = type.Definition; + if (valueDef == null || !valueDef.IsEnum) { + returnvalue = v.ToString (); + return true; + } + + string typename = MDocUpdater.GetDocTypeFullName (valueType); + var values = MDocUpdater.GetEnumerationValues (valueDef); + long c = MDocUpdater.ToInt64 (v); + if (values.ContainsKey (c)) { + returnvalue = typename + "." + values [c]; + return true; + } + + returnvalue = null; + return false; + } +} + +/// The final value formatter in the pipeline ... if no other formatter formats the value, +/// then this one will serve as the default implementation. +class DefaultAttributeValueFormatter : AttributeValueFormatter { + public override bool TryFormatValue (object v, ResolvedTypeInfo type, out string returnvalue) + { + returnvalue = "(" + MDocUpdater.GetDocTypeFullName (type.Reference) + ") " + v.ToString (); + return true; + } +} + +/// Flags enum formatter that assumes powers of two values. +/// As described here: https://msdn.microsoft.com/en-us/library/vstudio/ms229062(v=vs.100).aspx +class StandardFlagsEnumFormatter : AttributeValueFormatter { + public override bool TryFormatValue (object v, ResolvedTypeInfo type, out string returnvalue) + { + TypeReference valueType = type.Reference; + TypeDefinition valueDef = type.Definition; + if (valueDef.CustomAttributes.Any (ca => ca.AttributeType.FullName == "System.FlagsAttribute")) { + + string typename = MDocUpdater.GetDocTypeFullName (valueType); + var values = MDocUpdater.GetEnumerationValues (valueDef); + long c = MDocUpdater.ToInt64 (v); + returnvalue = string.Join (" | ", + (from i in values.Keys + where (c & i) == i && i != 0 + select typename + "." + values [i]) + .DefaultIfEmpty (c.ToString ()).ToArray ()); + + return true; + } + + returnvalue = null; + return false; + } +} + +/// A custom formatter for the ObjCRuntime.Platform enumeration. +class ApplePlatformEnumFormatter : AttributeValueFormatter { + public override bool TryFormatValue (object v, ResolvedTypeInfo type, out string returnvalue) + { + TypeReference valueType = type.Reference; + string typename = MDocUpdater.GetDocTypeFullName (valueType); + TypeDefinition valueDef = type.Definition; + if (typename.Contains ("ObjCRuntime.Platform") && valueDef.CustomAttributes.Any (ca => ca.AttributeType.FullName == "System.FlagsAttribute")) { + + var values = MDocUpdater.GetEnumerationValues (valueDef); + long c = MDocUpdater.ToInt64 (v); + + returnvalue = Format (c, values, typename); + return true; + } + + returnvalue = null; + return false; + } + + string Format (long c, IDictionary values, string typename) + { + int iosarch, iosmajor, iosminor, iossubminor; + int macarch, macmajor, macminor, macsubminor; + GetEncodingiOS (c, out iosarch, out iosmajor, out iosminor, out iossubminor); + GetEncodingMac ((ulong)c, out macarch, out macmajor, out macminor, out macsubminor); + + if (iosmajor == 0 & iosminor == 0 && iossubminor == 0) { + return FormatValues ("Mac", macarch, macmajor, macminor, macsubminor); + } + + if (macmajor == 0 & macminor == 0 && macsubminor == 0) { + return FormatValues ("iOS", iosarch, iosmajor, iosminor, iossubminor); + } + + return string.Format ("(Platform){0}", c); + } + + string FormatValues (string plat, int arch, int major, int minor, int subminor) + { + string archstring = ""; + switch (arch) { + case 1: + archstring = "32"; + break; + case 2: + archstring = "64"; + break; + } + return string.Format ("Platform.{4}_{0}_{1}{2} | Platform.{4}_Arch{3}", + major, + minor, + subminor == 0 ? "" : "_" + subminor.ToString (), + archstring, + plat + ); + } + + void GetEncodingiOS (long entireLong, out int archindex, out int major, out int minor, out int subminor) + { + long lowerBits = entireLong & 0xffffffff; + int lowerBitsAsInt = (int) lowerBits; + GetEncoding (lowerBitsAsInt, out archindex, out major, out minor, out subminor); + } + + void GetEncodingMac (ulong entireLong, out int archindex, out int major, out int minor, out int subminor) + { + ulong higherBits = entireLong & 0xffffffff00000000; + int higherBitsAsInt = (int) ((higherBits) >> 32); + GetEncoding (higherBitsAsInt, out archindex, out major, out minor, out subminor); + } + + void GetEncoding (Int32 encodedBits, out int archindex, out int major, out int minor, out int subminor) + { + // format is AAJJNNSS + archindex = (int)((encodedBits & 0xFF000000) >> 24); + major = (int)((encodedBits & 0x00FF0000) >> 16); + minor = (int)((encodedBits & 0x0000FF00) >> 8); + subminor = (int)((encodedBits & 0x000000FF) >> 0); + } +} }