Beispiel #1
0
 public TpmStruct(TpmStruct src)
     : base(src)
 {
     Fields      = src.Fields;
     DerivedFrom = src.DerivedFrom;
     Info        = src.Info;
 }
Beispiel #2
0
        string GetCommandReturnType(CommandFlavor gen, TpmStruct resp, string methodName,
                                    out string returnFieldName)
        {
            returnFieldName = null;
            if (gen == CommandFlavor.AsyncCommand)
            {
                return("void");
            }

            string returnType = "void";
            var    respFields = resp.NonTagFields;

            if (ForceJustOneReturnParm.Contains(methodName))
            {
                respFields = respFields.Take(1).ToArray();
            }

            if (respFields.Count() > 1)
            {
                return(resp.Name);
            }

            if (respFields.Count() == 1)
            {
                returnFieldName = respFields[0].Name;
                returnType      = TransType(respFields[0]);
            }
            return(returnType);
        }
Beispiel #3
0
        public void GenMarshalingMethod(bool dirTo, TpmStruct s)
        {
            var fields = s.MarshalFields;

            if (s.DerivedFrom != null || fields.Count() == 0)
            {
                return;
            }

            string dir   = dirTo ? "to" : "initFrom",
                   proto = $"{dir}Tpm(buf: TpmBuffer): void";

            var marshalOps = dirTo ? GetToTpmFieldsMarshalOps(fields)
                                   : GetFromTpmFieldsMarshalOps(fields);

            WriteComment("TpmMarshaller method");
            if (marshalOps.Count == 1)
            {
                // Lay it out in a single line
                Write($"{proto} {{ {marshalOps[0]}; }}");
            }
            else
            {
                Write(proto);
                TabIn("{");
                foreach (var op in marshalOps)
                {
                    Write($"{op};");
                }
                TabOut("}", false);
            }
        } // GenMarshalingMethod()
Beispiel #4
0
        } // GenUnions()

        void GenGetUnionSelector(TpmStruct s)
        {
            string selType = GetUnionMemberSelectorInfo(s, out string selVal);

            if (selType != null)
            {
                WriteComment("TpmUnion method");
                Write($"GetUnionSelector(): {selType} {{ return {selVal}; }}");
            }
        }
Beispiel #5
0
 public TpmStruct(string typeName, string comment,
                  TpmStruct derivedFrom = null, StructInfo info = null,
                  bool customizedImpl   = false)
     : base(typeName, comment)
 {
     Fields      = new List <StructField>();
     DerivedFrom = derivedFrom;
     Debug.Assert(DerivedFrom == null || TpmTypes.Contains(DerivedFrom.SpecName));
     Info = info ?? new TpmStructInfo();
 }
Beispiel #6
0
        void GenGetUnionSelector(TpmStruct s, bool implementsUnionInterfaces = true)
        {
            string selType = GetUnionMemberSelectorInfo(s, out string selVal);

            if (selType != null)
            {
                string overrideFlavor = implementsUnionInterfaces ? "virtual" : "override";
                Write("");
                Write($"public {overrideFlavor} {selType} GetUnionSelector() {{ return {selVal}; }}");
            }
        }
Beispiel #7
0
        public UnionMember GetMemberOfType(TpmStruct s)
        {
            UnionMember elt = null;

            do
            {
                elt = GetElementOfType(s);
                s   = s.DerivedFrom;
            } while (elt == null && s != null);
            return(elt);
        }
Beispiel #8
0
        void GenGetUnionSelector(TpmStruct s)
        {
            string selType = GetUnionMemberSelectorInfo(s, out string selVal);

            if (selType != null)
            {
                Write("");
                TabIn($"def GetUnionSelector({This}): # {selType}");
                WriteComment("TpmUnion method");
                Write($"return {selVal}");
                TabOut();
            }
        }
Beispiel #9
0
        static void FixEnumTypeCollisions()
        {
            List <TpmStruct> toAdd = new List <TpmStruct>();

            for (int j = 0; j < TpmTypes.TheTypes.Count; j++)
            {
                TpmType tp = TpmTypes.TheTypes[j];
                if (!(tp is TpmUnion &&
                      tp.SpecName.IsOneOf(new string[] { "TPMU_PUBLIC_ID", "TPMU_SIGNATURE" })))
                {
                    continue;
                }

                // See if we have collisions.
                // Collided member types are converted into derived types by adding selector name to the base
                // type name. Struct that became a base one inherits from all the union interfaces, while
                // a derived struct only inherits from the base one and implements interfaces of the unions,
                // of which it is a member.
                // Base class B provides a union interface implementation only if this union contains a member
                // of type B. If a union U contains members of types derived from B, then B's implementation
                // of U's interface methods just throws NotImplementedException exception.
                TpmUnion u    = (TpmUnion)tp;
                var      dict = new Dictionary <string, UnionMember>();
                foreach (UnionMember m in u.Members)
                {
                    string typeName     = m.Type.SpecName;
                    string selectorName = m.SelectorValue.Name;
                    if (dict.ContainsKey(typeName))
                    {
                        // Collision detected.
                        Debug.WriteLine("Collision in {0} [{1}] -- {2}", u.Name, selectorName, typeName);

                        TpmStruct baseStruct = (TpmStruct)TpmTypes.Lookup(typeName);
                        AddDerivedStruct(baseStruct, m, u,
                                         "Auto-derived from " + baseStruct.SpecName +
                                         " to provide unique GetUnionSelector() implementation");
                        if (dict[typeName] != null)
                        {
                            // Create the derived structure for the first occurrence.
                            AddDerivedStruct(baseStruct, dict[typeName], u);
                            // But do it only once...
                            dict[typeName] = null;
                        }
                    }
                    else
                    {
                        dict.Add(typeName, m);
                    }
                }
            }
        } // FixEnumTypeCollisions()
Beispiel #10
0
        /// <param name="unionField"> Name of the filed of a union interface type associated with the returned tag </param>
        /// <returns> Name of the union selector (tag) fieled or null </returns>
        public static string GetUnionSelectorFieldInfo(TpmStruct s, out string unionField)
        {
            unionField = null;
            var selectors = s.Fields.Where(f => f.MarshalType == MarshalType.UnionSelector);

            if (selectors.Count() == 0)
            {
                return(null);
            }

            // If a struct is a member of multiple unions, all of them are expected to use the same selector value
            unionField = selectors.First().Name;
            return(selectors.First().RelatedUnion.Name);
        }
Beispiel #11
0
        /// <param name="selVal"> Upon return set to the value (qualified enum memeber) of the selector (or null). </param>
        /// <returns> Union selector type name if 's' is a member of a tagged union. Otherwise null. </returns>
        public static string GetUnionMemberSelectorInfo(TpmStruct s, out string selVal)
        {
            selVal = null;
            if (s.IsCmdStruct() || s.ContainingUnions.Count == 0)
            {
                return(null);
            }

            // If a struct is a member of multiple unions, all of them are expected to use the same selector value
            TpmUnion u = s.ContainingUnions.ElementAt(0);

            selVal = s.SpecName == TpmTypes.EmptyUnionBaseName ? TpmTypes.AlgNull
                   : u.GetMemberOfType(s).SelectorValue.QualifiedName;
            return(GetUnionSelectorType(u));
        }
Beispiel #12
0
        // The serializer needs hints when embedded structs or unions are serialized/deserialized.
        // This function returns the referenced structure types for simple embedded structs and
        // interface members.
        IEnumerable <TpmType> GetKnownTypes(TpmStruct s)
        {
            var containedTypes = new List <TpmType>();

            foreach (StructField f in s.Fields)
            {
                switch (f.MarshalType)
                {
                case MarshalType.Normal:
                case MarshalType.SizedStruct:
                case MarshalType.UnionSelector:
                    if (f.Type is TpmStruct)
                    {
                        containedTypes.Add(f.Type);
                    }
                    else if (f.Type is TpmTypedef)
                    {
                        var tdt = f.Type.StripTypedefs();
                        if (tdt.IsElementary() || tdt.Name == "KeyBits")
                        {
                            continue;
                        }
                        if (!containedTypes.Contains(tdt))
                        {
                            containedTypes.Add(tdt);
                        }
                    }
                    else if (f.Type is TpmEnum || f.Type is TpmBitfield)
                    {
                        if (!containedTypes.Contains(f.Type))
                        {
                            containedTypes.Add(f.Type);
                        }
                    }
                    break;

                case MarshalType.UnionObject:
                    var unionMembers = (f.Type as TpmUnion).Members.Select(um => um.Type);
                    containedTypes = containedTypes.Union(unionMembers).ToList();
                    break;

                default:
                    continue;
                }
            }
            return(containedTypes.OrderBy(t => t.SpecName));
        }
Beispiel #13
0
        void GenCommand(TpmStruct req, CommandFlavor gen)
        {
            var    resp    = GetRespStruct(req);
            string cmdName = GetCommandName(req);

            if (gen == CommandFlavor.AsyncResponse)
            {
                cmdName += "Complete";
            }

            string annotation = Helpers.WrapText(AsSummary(req.Comment)) + eol;
            var    reqFields  = new StructField[0];

            if (gen != CommandFlavor.AsyncResponse)
            {
                reqFields = req.NonTagFields;
                foreach (var f in reqFields)
                {
                    annotation += GetParamComment(f) + eol;
                }
            }
            WriteComment(annotation + (GetReturnComment(resp.NonTagFields)), false);

            string returnType = GetCommandReturnType(gen, resp, cmdName, out string returnFieldName);

            if (reqFields.Length > 1)
            {
                Write(returnType + " " + cmdName);
                TabIn("(");
                if (gen != CommandFlavor.AsyncResponse)
                {
                    foreach (var f in reqFields)
                    {
                        Write(CtorParamTypeFor(f) + " " + f.Name + Separator(f, reqFields, ", "));
                    }
                }
                TabOut(");");
                Write("");
            }
            else
            {
                string param = reqFields.Length == 1 ? CtorParamTypeFor(reqFields[0]) + " " + reqFields[0].Name : "";
                Write($"{returnType} {cmdName}({param});");
            }
        } // GenCommand()
Beispiel #14
0
        } // GetFieldsDeserializationOps()

        public void GenMarshalingMethod(bool dirTo, TpmStruct s,
                                        bool genPrototype = false, bool serialization = false)
        {
            var fields = serialization ? s.NonSizeFields : s.MarshalFields;

            if (s.DerivedFrom != null || fields.Count() == 0)
            {
                return;
            }

            string dir = serialization ? dirTo ? "Ser" : "Deser"
                                        : dirTo ? "to" : "initFrom",
                   cst         = dirTo ? " const" : "",
                   qual        = genPrototype ? "" : s.Name + "::",
                   protoAnchor = serialization ? "ialize(Serializer& buf)" : "Tpm(TpmBuffer& buf)",
                   proto       = $"void {qual}{dir}{protoAnchor}{cst}";

            if (genPrototype)
            {
                Write($"{proto};");
                return;
            }

            var marshalOps = serialization
                           ? dirTo ? GetFieldsSerializationOps(fields) : GetFieldsDeserializationOps(fields)
                           : dirTo?GetToTpmFieldsMarshalOps(fields) : GetFromTpmFieldsMarshalOps(fields);

            Write("");
            if (marshalOps.Count == 1)
            {
                // Lay it out in a single line
                Write($"{proto} {{ {marshalOps[0]}; }}");
            }
            else
            {
                Write(proto);
                TabIn("{");
                foreach (var marshalOp in marshalOps)
                {
                    Write($"{marshalOp};");
                }
                TabOut("}");
            }
        } // GenMarshalingMethod()
Beispiel #15
0
        public static void AddDerivedStruct(TpmStruct baseStruct, UnionMember curMember,
                                            TpmUnion curUnion, string comment = null)
        {
            string baseTypeName = baseStruct.SpecName;
            string newTypeName  = baseTypeName + "_" + RemoveEnumPrefix(curMember.SelectorValue.SpecName,
                                                                        curMember.SelectorValue.EnclosingEnum.SpecName);

            if (!TpmTypes.Contains(newTypeName))
            {
                var newStruct = new TpmStruct(newTypeName,
                                              comment ?? "Auto-derived from " + baseTypeName,
                                              baseStruct);
                TpmTypes.Add(newStruct);
            }

            var s = (TpmStruct)TpmTypes.Lookup(newTypeName);

            s.RegisterContainingUnion(curUnion);
            // Fix up the union field
            curMember.Type = s;
        }
Beispiel #16
0
        /// <summary> Adds fundamental type definitions and a couple of custom classes </summary>
        internal static void Init()
        {
            foreach (var et in TargetLang.GetElementaryTypes())
            {
                Add(et);
            }

            TpmStruct s = new TpmStruct("TPM_HANDLE", "Handle of a loaded TPM key or other object [TSS]", null, null, true);

            s.Add(new StructField("UINT32", "handle", "Handle value"));
            s.UnderlyingType = Lookup("UINT32");
            Add(s);

            // Create and register empty structs for unions
            string descr = "Base class for empty union elements.\n" +
                           "An empty union element does not contain any data to marshal.\n" +
                           "This data structure can be used in place of any other union\n" +
                           "initialized with its own empty element.";

            EmptyUnionBase = new TpmStruct(EmptyUnionBaseName, descr);
            Add(EmptyUnionBase);
        }
Beispiel #17
0
        void GenMarshalingMethod(bool dirTo, TpmStruct s)
        {
            var fields = s.MarshalFields;

            if (s.DerivedFrom != null || fields.Count() == 0)
            {
                return;
            }

            string dir   = dirTo ? "to" : "initFrom",
                   proto = $"def {dir}Tpm({This}, buf):";

            var marshalOps = dirTo ? GetToTpmFieldsMarshalOps(fields)
                                   : GetFromTpmFieldsMarshalOps(fields);

            Write("");
            TabIn(proto);
            WriteComment("TpmMarshaller method");
            foreach (var op in marshalOps)
            {
                Write($"{op}");
            }
            TabOut("", false);
        } // GenMarshalingMethod()
Beispiel #18
0
 public UnionMember GetElementOfType(TpmStruct s)
 {
     // First look for the exact type match ...
     foreach (UnionMember m in Members)
     {
         if (m.Type.SpecName == s.SpecName)
         {
             return(m);
         }
     }
     // ... then see if we have a matching typedef or derived type
     foreach (UnionMember m in Members)
     {
         if (m.Type is TpmTypedef)
         {
             TpmType underlyingType = m.Type.StripTypedefs();
             if (underlyingType.SpecName == s.SpecName)
             {
                 return(m);
             }
         }
         else if (m.Type is TpmStruct)
         {
             TpmStruct b = (m.Type as TpmStruct).DerivedFrom;
             while (b != null)
             {
                 if (b.SpecName == s.SpecName)
                 {
                     return(m);
                 }
                 b = b.DerivedFrom;
             }
         }
     }
     return(null);
 }
Beispiel #19
0
        void GenCommand(TpmStruct req)
        {
            var    resp       = GetRespStruct(req);
            var    cmdName    = GetCommandName(req);
            string respType   = resp.Name;
            string cmdCode    = "TPM_CC." + cmdName;
            var    reqFields  = req.NonTagFields;
            var    respFields = resp.NonTagFields;

            if (ForceJustOneReturnParm.Contains(cmdName))
            {
                respFields = respFields.Take(1).ToArray();
            }

            int    numOutParms = respFields.Count();
            string returnType  = numOutParms == 1 ? respFields[0].TypeName
                              : numOutParms == 0 ? "void" : respType;

            // javadoc annotation
            string annotation = req.Comment;

            if (reqFields.Count() != 0)
            {
                annotation += eol + eol + "Args:";
                foreach (var f in reqFields)
                {
                    annotation += eol + GetParamComment(f, "    ", "        ");
                }
            }
            if (respFields.Count() != 0)
            {
                annotation += eol + eol + "Returns:";
                annotation += eol + GetReturnComment(respFields);
            }

            // method definition
            string paramList         = This;
            string reqStructInitList = "";

            foreach (var f in reqFields)
            {
                paramList         += ", " + f.Name; // ": " + f.TypeName + ", ";
                reqStructInitList += (reqStructInitList.Length == 0 ? "" : ", ") + f.Name;
            }

            TabIn($"def {cmdName}({paramList}):");
            WriteComment(annotation);

            Write($"req = {req.Name}({reqStructInitList})");
            Write($"respBuf = {ThisMember}dispatchCommand({cmdCode}, req)");
            respType = numOutParms > 0 ? ", " + respType : "";
            if (numOutParms == 1)
            {
                Write($"res = {ThisMember}processResponse(respBuf{respType})");
                Write($"return res.{respFields[0].Name} if res else None");
            }
            else
            {
                Write($"return {ThisMember}processResponse(respBuf{respType})");
            }

            TabOut();
            Write($"# {cmdName}()");
            Write("");
        } // GenCommand()
Beispiel #20
0
        } // GenMarshalingMethod()

        /// <summary>
        /// Structures in C are classes in TypeScript
        /// </summary>
        /// <param name="s"></param>
        void GenStruct(TpmStruct s)
        {
            bool   hasBase    = s.DerivedFrom != null;
            string className  = s.Name;
            string classBases = hasBase ? s.DerivedFrom.Name
                              : !s.IsCmdStruct() ? "TpmStructure"
                              : s.Info.IsRequest() ? "ReqStructure" : "RespStructure";

            // If this struct is not derived from another one and is a member of one or more unions,
            // it must implement the corresponding union interfaces
            if (!s.IsCmdStruct() && !hasBase)
            {
                string unionInterfaces = string.Join(", ", s.ContainingUnions.Select(u => u.Name));
                if (unionInterfaces != "")
                {
                    classBases += ", " + unionInterfaces;
                }
            }

            // Class header
            TabIn($"class {className} ({classBases}):");

            // Javadoc comment for the data structure
            string annotation = s.Comment + eol;
            var    fields     = s.FieldHolder.NonTagFields;

            if (fields.Length != 0)
            {
                annotation += eol + "Attributes:" + eol;
                foreach (var f in fields)
                {
                    annotation += GetParamComment(f, "    ", "        ") + eol;
                }
            }

            //
            // Field defining constructor
            //

            if (fields.Count() == 0)
            {
                TabIn($"def __init__({This}):");
                WriteComment(annotation);
                Write("pass");
                TabOut();
            }
            else
            {
                string ctorParams = string.Join(", ", fields.Select(f => f.Name + $" = {f.GetInitVal()}"));
                TabIn($"def __init__({This}, {ctorParams}):");
                WriteComment(annotation);

                // If a non-trivial base class is present, all member fields are contained there,
                // so just pass through the initialization parameters
                if (hasBase)
                {
                    string baseInitParams = string.Join(", ", fields.Select(f => f.Name));
                    //Write($"{s.DerivedFrom}.__init__({baseInitParams})");
                    Write($"super({className}, {This}).__init__({baseInitParams})");
                }
                else
                {
                    foreach (var f in fields)
                    {
                        Write($"{ThisMember}{f.Name} = {f.Name}");
                    }
                }
                TabOut();

                //
                // Named union tag getters (instead of the corresponding fields in the TPM 2.0 spec)
                //
                foreach (var sel in s.TagFields)
                {
                    if (sel.MarshalType != MarshalType.UnionSelector)
                    {
                        continue;
                    }

                    var unionField = sel.RelatedUnion;
                    var u          = (TpmUnion)unionField.Type;
                    Write("");
                    Write("@property");
                    TabIn($"def {sel.Name}({This}): # {sel.TypeName}");
                    WriteComment(sel.Comment);
                    if (u.NullSelector == null)
                    {
                        Write($"return {unionField.Name}.GetUnionSelector()");
                    }
                    else
                    {
                        Write($"return {unionField.Name}.GetUnionSelector() if {unionField.Name}" +
                              $" else {u.NullSelector.QualifiedName}");
                    }
                    TabOut();
                }

                foreach (var f in fields)
                {
                    if (f.MarshalType != MarshalType.UnionObject)
                    {
                        continue;
                    }

                    var u   = (TpmUnion)f.Type;
                    var sel = (f as UnionField).UnionSelector;
                }
            }

            GenGetUnionSelector(s);

            //
            // Marshaling
            //
            GenMarshalingMethod(true, s);
            GenMarshalingMethod(false, s);

            Write("");
            Write($"@staticmethod");
            TabIn("def fromTpm(buf):");
            WriteComment($"Returns new {className} object constructed from its marshaled representation in the given TpmBuffer buffer");
            Write($"return buf.createObj({className})");
            TabOut("");

            Write($"@staticmethod");
            TabIn("def fromBytes(buffer):");
            WriteComment($"Returns new {className} object constructed from its marshaled representation in the given byte buffer");
            Write($"return TpmBuffer(buffer).createObj({className})");
            TabOut();

            var info = s.IsCmdStruct() ? s.Info as CmdStructInfo : null;

            if (info != null && (info.NumHandles != 0 || info.SessEncSizeLen != 0))
            {
                if (info.NumHandles != 0)
                {
                    Write("");
                    Write($"def numHandles({This}): return {info.NumHandles}");
                    if (info.IsRequest())
                    {
                        string handles = string.Join(", ", s.Fields.Take(info.NumHandles).Select(f => ThisMember + f.Name));
                        Write("");
                        Write($"def numAuthHandles({This}): return {info.NumAuthHandles}");
                        Write("");
                        Write($"def getHandles({This}): return [{handles}]");
                    }
                    else
                    {
                        Debug.Assert(info.NumHandles == 1 && info.NumAuthHandles == 0);
                        Write("");
                        Write($"def getHandle({This}): return {ThisMember}{s.Fields[0].Name}");
                        Write("");
                        Write($"def setHandle({This}, h): {ThisMember}{s.Fields[0].Name} = h");
                    }
                }
                if (info.SessEncSizeLen != 0)
                {
                    Debug.Assert(info.SessEncValLen != 0);
                    Write("");
                    Write($"def sessEncInfo({This}): return SessEncInfo({info.SessEncSizeLen}, {info.SessEncValLen})");
                }
            }

            //
            // Custom members
            //
            InsertSnip(s.Name);

            TabOut($"# {className}");
        } // GenStruct()
Beispiel #21
0
        } // GenMarshalingMethod()

        void GenStruct(TpmStruct s)
        {
            bool   hasBase    = s.DerivedFrom != null;
            string className  = s.Name;
            string classBases = hasBase ? s.DerivedFrom.Name
                              : !s.IsCmdStruct() ? "TpmStructure"
                              : s.Info.IsRequest() ? "ReqStructure" : "RespStructure";

            // If this struct is not derived from another one and is a member of one or more unions,
            // it must implement the corresponding union interfaces
            if (!s.IsCmdStruct() && !hasBase)
            {
                string unionInterfaces = string.Join(", ", s.ContainingUnions.Select(u => u.Name));
                if (unionInterfaces != "")
                {
                    classBases += " implements " + unionInterfaces;
                }
            }

            // Javadoc comment for the data structure
            WriteComment(s);

            // Class header
            Write($"public class {className} extends {classBases}");
            TabIn("{");

            //
            // Fields
            //
            Debug.Assert(s.Fields.Count == 0 || !hasBase);
            foreach (var f in s.NonSizeFields)
            {
                if (f.MarshalType == MarshalType.ConstantValue)
                {
                    continue;
                }

                WriteComment(f);
                if (f.MarshalType == MarshalType.UnionSelector)
                {
                    var unionField = f.RelatedUnion;
                    var u          = (TpmUnion)unionField.Type;
                    Write($"public {f.TypeName} {f.Name}() {{ ", false);
                    if (u.NullSelector == null)
                    {
                        Write($"return {unionField.Name}.GetUnionSelector(); }}");
                    }
                    else
                    {
                        Write($"return {unionField.Name} != null ? {unionField.Name}.GetUnionSelector()" +
                              $" : {u.NullSelector.QualifiedName}; }}");
                    }
                }
                else
                {
                    Write($"public {f.TypeName} {f.Name};");
                }
            }

            //
            // Default constructor
            //
            var fieldsToInit = s.NonDefaultInitFields;

            Write("");
            Write($"public {className}()", false);
            if (fieldsToInit.Count() == 0)
            {
                Write(" {}");
            }
            else if (fieldsToInit.Count() == 1)
            {
                var f = fieldsToInit[0];
                Write($" {{ {f.Name} = {f.GetInitVal()}; }}");
            }
            else
            {
                TabIn("{");
                foreach (StructField f in fieldsToInit)
                {
                    Write($"{f.Name} = {f.GetInitVal()};");
                }
                TabOut("}");
            }

            //
            // Member-wise constructor
            //
            var ctorParams = s.FieldHolder.NonTagFields;

            if (!s.Info.IsResponse() && ctorParams.Count() != 0)
            {
                // Javadoc comments (note that we provide a bit more info for union parameters)
                string javaDocComment = "";
                foreach (var p in ctorParams)
                {
                    javaDocComment += GetParamComment(p, "_") + eol;
                }
                WriteComment(javaDocComment);

                string ctorOpen      = $"public {className}(";
                string ctorParamList = string.Join(", ", ctorParams.Select(p => p.TypeName + " _" + p.Name));
                Write(ctorOpen + ctorParamList + ")", false);
                if (hasBase)
                {
                    if (ctorParams.Length == 1)
                    {
                        Write($" {{ super(_{ctorParams[0].Name}); }}");
                    }
                    else
                    {
                        string ctorParamNamesList = string.Join(", ", ctorParams.Select(p => "_" + p.Name));
                        TabIn("{");
                        Write($"super({ctorParamNamesList});");
                        TabOut("}");
                    }
                }
                else if (ctorParams.Length == 1)
                {
                    var p = ctorParams[0];
                    Write($" {{ {p.Name} = _{p.Name}; }}");
                }
                else
                {
                    TabIn("{");
                    foreach (var p in ctorParams)
                    {
                        // We turn shorts into ints in constructor args, to allow external API users
                        // avoid incessant casting. Instead the cast is hidden in the constructor body.
                        // Note that we cannot change the type of the corresponding members, as it is
                        // dictated by the TPM 2.0 spec.
                        Write($"{p.Name} = _{p.Name};");
                    }
                    TabOut("}");
                }
            }

            //
            // Union interface: TpmUnion.GetUnionSelector()
            //
            GenGetUnionSelector(s);

            //
            // Marshaling
            //
            GenMarshalingMethod(true, s);
            GenMarshalingMethod(false, s);

            WriteComment("@deprecated Use {@link #toBytes()} instead\n" +
                         "@return Wire (marshaled) representation of this object");
            Write("public byte[] toTpm () { return toBytes(); }");

            WriteComment("Static marshaling helper\n" +
                         "@param byteBuf Wire representation of the object\n" +
                         "@return New object constructed from its wire representation");
            Write($"public static {className} fromBytes (byte[] byteBuf) ");
            TabIn("{");
            Write($"return new TpmBuffer(byteBuf).createObj({className}.class);");
            TabOut("}");

            WriteComment("@deprecated Use {@link #fromBytes(byte[])} instead\n" +
                         "@param byteBuf Wire representation of the object\n" +
                         "@return New object constructed from its wire representation");
            Write($"public static {className} fromTpm (byte[] byteBuf)  {{ return fromBytes(byteBuf); }}");

            WriteComment("Static marshaling helper\n" +
                         "@param buf Wire representation of the object\n" +
                         "@return New object constructed from its wire representation");
            Write($"public static {className} fromTpm (TpmBuffer buf) ");
            TabIn("{");
            Write($"return buf.createObj({className}.class);");
            TabOut("}");

            Write("@Override");
            Write("public String toString()");
            TabIn("{");
            Write($"TpmStructurePrinter _p = new TpmStructurePrinter(\"{s.Name}\");");
            Write("toStringInternal(_p, 1);");
            Write("_p.endStruct();");
            Write("return _p.toString();");
            TabOut("}", false);

            if (s.Fields.Count() > 0)
            {
                Write("@Override");
                Write("public void toStringInternal(TpmStructurePrinter _p, int d)");
                TabIn("{");
                foreach (StructField f in ctorParams)
                {
                    Write($"_p.add(d, \"{f.TypeName}\", \"{f.Name}\", {f.Name});");
                }
                TabOut("}", false);
            }

            var info = s.IsCmdStruct() ? s.Info as CmdStructInfo : null;

            if (info != null && (info.NumHandles != 0 || info.SessEncSizeLen != 0))
            {
                if (info.NumHandles != 0)
                {
                    Write("@Override");
                    Write($"public int numHandles() {{ return {info.NumHandles}; }}");
                    if (info.IsRequest())
                    {
                        string handles = string.Join(", ", s.Fields.Take(info.NumHandles).Select(f => ThisMember + f.Name));
                        Write("@Override");
                        Write($"public int numAuthHandles() {{ return {info.NumAuthHandles}; }}");
                        Write("@Override");
                        Write($"public TPM_HANDLE[] getHandles() {{ return new TPM_HANDLE[] {{{handles}}}; }}");
                    }
                    else
                    {
                        Debug.Assert(info.NumHandles == 1 && info.NumAuthHandles == 0);
                        Write("@Override");
                        Write($"public TPM_HANDLE getHandle() {{ return {ThisMember}{s.Fields[0].Name}; }}");
                        Write("@Override");
                        Write($"public void setHandle(TPM_HANDLE h) {{ {ThisMember}{s.Fields[0].Name} = h; }}");
                    }
                }
                if (info.SessEncSizeLen != 0)
                {
                    Debug.Assert(info.SessEncValLen != 0);
                    Write("@Override");
                    Write($"public SessEncInfo sessEncInfo() {{ return new SessEncInfo({info.SessEncSizeLen}, {info.SessEncValLen}); }}");
                }
            }

            InsertSnip(s.Name);
            TabOut("}", false);
        } // GenStruct()
Beispiel #22
0
        } // GenCommands()

        void GenCommand(TpmStruct req)
        {
            var    resp       = GetRespStruct(req);
            var    cmdName    = GetCommandName(req);
            string respType   = resp.Name;
            string cmdCode    = "TPM_CC." + cmdName;
            var    fields     = req.NonTagFields;
            var    respFields = resp.NonTagFields;

            if (ForceJustOneReturnParm.Contains(cmdName))
            {
                respFields = respFields.Take(1).ToArray();
            }

            int    numOutParms = respFields.Count();
            string returnType  = numOutParms == 1 ? respFields[0].TypeName
                              : numOutParms == 0 ? "void" : respType;

            // javadoc annotation
            string annotation = req.Comment + eol + eol;

            foreach (var f in fields)
            {
                annotation += GetParamComment(f) + eol;
            }
            annotation += GetReturnComment(respFields);
            WriteComment(annotation);

            // method definition
            string paramList         = "";
            string reqStructInitList = "";

            foreach (var f in fields)
            {
                string comma = Separator(f, fields, ", ");
                paramList         += f.TypeName + " " + f.Name + comma;
                reqStructInitList += f.Name + comma;
            }

            Write($"public {returnType} {cmdName}({paramList})");
            TabIn("{");
            Write($"{req.Name} req = new {req.Name}({reqStructInitList});");

            string outParm = "null";

            if (numOutParms != 0)
            {
                Write($"{respType} resp = new {respType}();");
                outParm = "resp";
            }

            Write($"DispatchCommand({cmdCode}, req, {outParm});");
            if (numOutParms == 0)
            {
                Write("return;");
            }
            else if (numOutParms == 1)
            {
                Write("return resp." + respFields[0].Name + ";");
            }
            else
            {
                Write("return resp;");
            }

            TabOut("}");
        } // GenCommand()
Beispiel #23
0
 internal static string GetCommandName(TpmStruct req)
 {
     return(req.SpecName.Replace("TPM2_", "").Replace("_REQUEST", ""));
 }
Beispiel #24
0
        // The spec uses these two sorts of tagged structure commonly
        //     { len, array[len] }   and
        //     { selector, [select]union }
        // This routine changes references to these sorts of structure to an embedded form.
        public static void FlattenTaggedStructures()
        {
            // Build the list of tagged structures
            List <TpmStruct> taggedStructs = new List <TpmStruct>();

            foreach (TpmType tp in TpmTypes.TheTypes)
            {
                var s = tp as TpmStruct;
                if (s == null)
                {
                    continue;
                }
                var t = s;
                while (t != null && t.Fields.Count != 2)
                {
                    t = t.DerivedFrom;
                }
                if (t == null || s.SpecName.IsOneOf(DontFlatten))
                {
                    continue;
                }
                if ((t.Fields[0].MarshalType == MarshalType.ArrayCount) ||
                    (t.Fields[0].MarshalType == MarshalType.UnionSelector) ||
                    (t.Fields[0].MarshalType == MarshalType.LengthOfStruct)
                    )
                {
                    taggedStructs.Add(s);
                }
            }

            // find references to the tagged structures and replace them
            foreach (TpmType tp in TpmTypes.TheTypes)
            {
                if (!(tp is TpmStruct))
                {
                    continue;
                }
                TpmStruct t = (TpmStruct)tp;

                for (int j = 0; j < t.Fields.Count; j++)
                {
                    StructField origField = t.Fields[j];

                    if (origField.IsArray())
                    {
                        continue;   // Don't flatten arrays
                    }
                    var toEmbed = origField.Type as TpmStruct;
                    if (taggedStructs.Contains(toEmbed))
                    {
                        // If a structure to flatten is one without fields of its own,
                        // but is derived from a flattenable one, unwind the inheritance chain.
                        while (toEmbed != null && toEmbed.Fields.Count != 2)
                        {
                            toEmbed = toEmbed.DerivedFrom;
                        }

                        StructField tagToEmbed = toEmbed.Fields[0];
                        Debug.Assert(origField.MinVal == null || origField.MinVal == tagToEmbed.MinVal);
                        Debug.Assert(origField.MaxVal == null || origField.MaxVal == tagToEmbed.MaxVal);

                        var    bufToEmbed     = toEmbed.Fields[1];
                        string newTagName     = origField.Name + Helpers.Capitalize(tagToEmbed.Name);
                        string newBufTypeName = bufToEmbed.Type.SpecName;
                        var    newTagField    = new StructField(tagToEmbed, newTagName);
                        t.Fields[j] = newTagField;

                        switch (tagToEmbed.MarshalType)
                        {
                        case MarshalType.UnionSelector:
                        {
                            var newField = new UnionField(newBufTypeName, origField.Name,
                                                          origField.Comment, newTagName, t);
                            t.Fields.Insert(j + 1, newField);
                            break;
                        }

                        case MarshalType.ArrayCount:
                        {
                            var newField = new VariableLengthArray(newBufTypeName, origField.Name,
                                                                   origField.Comment, newTagName, t);
                            t.Fields.Insert(j + 1, newField);
                            break;
                        }

                        case MarshalType.LengthOfStruct:
                        {
                            var newField = new StructField(newBufTypeName, origField.Name,
                                                           origField.Comment);
                            t.Fields.Insert(j + 1, newField);
                            newTagField.MarshalType = MarshalType.LengthOfStruct;
                            newTagField.SizedField  = newField;
                            newField.MarshalType    = MarshalType.SizedStruct;
                            newField.SizeTagField   = newTagField;
                            break;
                        }

                        default:
                            throw new Exception("");
                        }
                    } // j-loop
                }
            }
        }
Beispiel #25
0
 internal static TpmStruct GetRespStruct(TpmStruct req)
 {
     return((TpmStruct)TpmTypes.Lookup(req.SpecName.Replace("_REQUEST", "Response").Substring(5)));
 }
Beispiel #26
0
        void GenStructDecl(TpmStruct s)
        {
            bool   hasBase   = s.DerivedFrom != null; // Has a non-trivial base class?
            string className = s.Name;

            if (IsTypedefStruct(s))
            {
                Debug.Assert(s.Fields.Count == 0);
                WriteComment(s);
                Write($"typedef {s.DerivedFrom.Name} {className};");
                Write("");
                return;
            }

            string classBases = hasBase ? s.DerivedFrom.Name
                              : !s.IsCmdStruct() ? "TpmStructure"
                              : s.Info.IsRequest() ? "ReqStructure" : "RespStructure";
            string virt = "";

            // If this struct is not derived from another one and is a member of one or more unions,
            // it must implement the corresponding union interfaces
            if (!s.IsCmdStruct() && !hasBase && s.ContainingUnions.Count > 0)
            {
                foreach (var u in s.ContainingUnions)
                {
                    classBases += ", public " + u.Name;
                }
                virt = "virtual ";
            }

            WriteComment(s);
            Write($"class _DLLEXP_ {className} : public {virt}{classBases}");
            Write("{");
            TabIn("public:");

            //
            // Fields
            //
            TpmField conversionSource = null;

            foreach (var f in s.NonSizeFields)
            {
                if (f.MarshalType == MarshalType.ConstantValue)
                {
                    // No member field for a constant tag
                    continue;
                }

                WriteComment(f);
                if (f.MarshalType == MarshalType.UnionSelector)
                {
                    var unionField = f.RelatedUnion;
                    var u          = (TpmUnion)unionField.Type;
                    Write($"public: {f.TypeName} {f.Name}() const {{ ", false);
                    if (u.NullSelector == null)
                    {
                        Write($"return {unionField.Name}->GetUnionSelector(); }}");
                    }
                    else
                    {
                        Write($"return {unionField.Name} ? {unionField.Name}->GetUnionSelector()" +
                              $" : {u.NullSelector.QualifiedName}; }}");
                    }
                    continue;
                }

                Write($"{TransType(f)} {f.Name};");
            }

            TabOut("");
            TabIn("public:");

            //
            // Default constructor
            //
            var fieldsToInit = s.NonDefaultInitFields;

            Write($"{className}()", false);
            if (fieldsToInit.Count() == 0)
            {
                Write(" {}");
            }
            else if (fieldsToInit.Count() == 1)
            {
                Write($" {{ {fieldsToInit[0].Name} = {fieldsToInit[0].GetInitVal()}; }}");
            }
            else
            {
                TabIn("{");
                foreach (StructField f in fieldsToInit)
                {
                    Write($"{f.Name} = {f.GetInitVal()};");
                }
                TabOut("}");
            }

            //
            // Member-wise constructor
            //
            var ctorParams = s.FieldHolder.NonTagFields;

            if (!s.Info.IsResponse() && ctorParams.Count() != 0)
            {
                string baseClass     = hasBase ? s.DerivedFrom.Name : "TpmStructure";
                string ctorParamList = string.Join(", ", ctorParams.Select(p => $"{CtorParamTypeFor(p)} _{p.Name}"));

                Write($"{className}({ctorParamList})");
                if (hasBase)
                {
                    string ctorParamNamesList = string.Join(", ", ctorParams.Select(p => "_" + p.Name));
                    Write($"  : {baseClass}({ctorParamNamesList})");
                }
                else
                {
                    string memInitList = string.Join(", ", ctorParams.Select(p => p.Type is TpmUnion
                                ? $"{p.Name}(dynamic_cast<{p.Type.Name}*>(_{p.Name}.Clone()))"
                                : $"{p.Name}(_{p.Name})"
                                                                             ));
                    Write($"  : {memInitList}");
                }
                Write("{}");
            }

            if (conversionSource != null)
            {
                Write("");
                Write($"operator ByteVec&() {{ return {conversionSource.Name}; }}");
                Write($"operator const ByteVec&() const {{ return {conversionSource.Name}; }}");
            }

            //
            // Union interface: TpmUnion.GetUnionSelector()
            //
            GenGetUnionSelector(s);

            //
            // Marshaling
            //
            Write("");
            GenMarshalingMethod(true, s, true);
            GenMarshalingMethod(false, s, true);

            string comment = AsSummary("Static marshaling helper");

            WriteComment(comment);
            Write($"static {className} fromTpm(TpmBuffer& buf) {{ return buf.createObj<{className}>(); }}");

            WriteComment(comment);
            Write($"static {className} fromBytes(const ByteVec& buf) {{ return TpmStructure::fromBytes<{className}>(buf); }}");

            //
            // Serialization
            //
            Write("");
            Write($"virtual const char* TypeName () const {{ return \"{className}\"; }}");
            Write("");
            Write("using TpmStructure::Serialize;");
            Write("using TpmStructure::Deserialize;");
            GenMarshalingMethod(true, s, true, true);
            GenMarshalingMethod(false, s, true, true);

            //
            // Cloning and metadata
            //
            Write("");
            Write($"virtual TpmStructure* Clone() const {{ return new {className}(*this); }}");

            var info = s.IsCmdStruct() ? s.Info as CmdStructInfo : null;

            if (info != null && (info.NumHandles != 0 || info.SessEncSizeLen != 0))
            {
                TabOut("");
                TabIn("protected:");

                if (info.NumHandles != 0)
                {
                    Write($"virtual uint16_t numHandles() const {{ return {info.NumHandles}; }}");
                    if (info.IsRequest())
                    {
                        string handles = string.Join(", ", s.Fields.Take(info.NumHandles).Select(f => f.Name));
                        Write($"virtual uint16_t numAuthHandles() const {{ return {info.NumAuthHandles}; }}");
                        Write($"virtual vector<TPM_HANDLE> getHandles() const {{ return {{{handles}}}; }}");
                    }
                    else
                    {
                        Debug.Assert(info.NumHandles == 1 && info.NumAuthHandles == 0);
                        Write($"virtual TPM_HANDLE getHandle() const {{ return {s.Fields[0].Name}; }}");
                        Write($"virtual void setHandle(const TPM_HANDLE& h) {{ {s.Fields[0].Name} = h; }}");
                    }
                }
                if (info.SessEncSizeLen != 0)
                {
                    Debug.Assert(info.SessEncValLen != 0);
                    Write("");
                    Write($"virtual SessEncInfo sessEncInfo() const {{ return {{{info.SessEncSizeLen}, {info.SessEncValLen}}}; }}");
                }
            }

            InsertSnip(s.Name);
            TabOut($"}}; // class {className}");
        } // GenStruct()
Beispiel #27
0
 /// <summary> Determines whether this struct is represented as a typedef in C++ </summary>
 static bool IsTypedefStruct(TpmStruct s)
 {
     return(s.DerivedFrom != null && s.ContainingUnions.Count == 0);
 }
Beispiel #28
0
        } // GenCommandDispatchers()

        void GenCommandDispatcher(TpmStruct req, CommandFlavor gen)
        {
            var    resp    = GetRespStruct(req);
            string cmdName = GetCommandName(req);
            string cmdCode = "TPM_CC::" + cmdName;

            string inStructId  = req.Name + "_ID";
            string outStructId = resp.Name + "_ID";

            switch (gen)
            {
            case CommandFlavor.AsyncCommand: cmdName += ""; break;

            case CommandFlavor.AsyncResponse: cmdName += "Complete"; break;

            default: break;
            }

            string returnFieldName;
            string returnType = GetCommandReturnType(gen, resp, cmdName, out returnFieldName);

            string      className      = " Tpm2::" + (gen != CommandFlavor.Synch ? "AsyncMethods::" : "");
            bool        paramsPresent  = gen != CommandFlavor.AsyncResponse;
            var         cmdParamFields = paramsPresent ? req.NonTagFields : new StructField[0];
            bool        multiline      = cmdParamFields.Count() > 1;
            StructField lastParm       = cmdParamFields.Count() > 0 ? lastParm = cmdParamFields.Last() : null;

            Write(returnType + className + cmdName + "(" +
                  (cmdParamFields.Count() == 0 ? ")"
                  : (multiline ? ""
                  : CtorParamTypeFor(cmdParamFields[0]) + " " + cmdParamFields[0].Name + ")")));
            if (multiline)
            {
                TabIn();
                foreach (var f in cmdParamFields)
                {
                    Write(CtorParamTypeFor(f) + " " + f.Name + (f == lastParm ? ")" : ", "));
                }
                TabOut();
            }
            TabIn("{");

            string reqParams = "";

            if (paramsPresent && req.Fields.Count() != 0)
            {
                string ctorInitList = string.Join(", ", cmdParamFields.Select(f => f.Name));
                Write($"{req.Name} req({ctorInitList});");
                reqParams = ", req";
            }

            string respParam = "";

            if (returnType != "void")
            {
                Debug.Assert(resp.Fields.Count() != 0);
                Write($"{resp.Name} resp;");
                respParam = ", resp";
            }

            string dispatchCall = gen == CommandFlavor.AsyncCommand ? "theTpm.DispatchOut"
                                : gen == CommandFlavor.AsyncResponse ? "theTpm.DispatchIn"
                                : "Dispatch";

            Write(dispatchCall + $"({cmdCode}{reqParams}{respParam});");

            if (gen != CommandFlavor.AsyncCommand)
            {
                if (returnFieldName != null)
                {
                    Write($"return resp.{returnFieldName};");
                }
                else if (returnType != "void")
                {
                    Write("return resp;");
                }
            }
            TabOut("}");
        } // GenCommandDispatcher()
Beispiel #29
0
        } // GenCommands()

        void GenCommand(TpmStruct req)
        {
            const string NS         = "tt.";
            var          resp       = GetRespStruct(req);
            var          cmdName    = GetCommandName(req);
            string       respType   = NS + resp.Name;
            string       cmdCode    = NS + "TPM_CC." + cmdName;
            var          fields     = req.NonTagFields;
            var          respFields = resp.NonTagFields;

            if (ForceJustOneReturnParm.Contains(cmdName))
            {
                respFields = respFields.Take(1).ToArray();
            }

            int    numOutParms = respFields.Count();
            string returnType  = numOutParms == 1 ? NsQualifiedType(respFields[0], NS)
                              : numOutParms == 0 ? "void" : respType;

            // javadoc annotation
            string annotation = req.Comment + eol + eol;

            foreach (var f in fields)
            {
                annotation += GetParamComment(f) + eol;
            }
            annotation += GetReturnComment(respFields);
            WriteComment(annotation);

            // method definition
            string paramList         = "";
            string reqStructInitList = "";

            foreach (var f in fields)
            {
                string parmTypeName = NsQualifiedType(f, NS);
                string comma        = Separator(f, fields, ", ");
                paramList         += f.Name + ": " + parmTypeName + ", ";
                reqStructInitList += f.Name + comma;
            }

            var    indent     = new string(' ', cmdName.Length + 2);
            string respParams = returnType == null ? "" : "res?: " + returnType;

            if (paramList != "")
            {
                Write($"{cmdName}({paramList}");
                Write($"{indent}continuation: (err: TpmError, {respParams}) => void)");
            }
            else
            {
                Write($"{cmdName}(continuation: (err: TpmError, {respParams}) => void)");
            }
            Write("{");

            TabIn();
            Write($"let req = new {NS}{req.Name}({reqStructInitList});");
            Write($"{ThisMember}dispatchCommand({cmdCode}, req, (respBuf: TpmBuffer): void => {{");
            respType = numOutParms > 0 ? ", " + respType : "";
            Write($"let res = {ThisMember}processResponse(respBuf{respType});");
            string res      = "",
                   resField = "";

            if (numOutParms > 0)
            {
                res = ", res";
                if (numOutParms == 1)
                {
                    resField = $"?.{respFields[0].Name}";
                }
            }
            Write($"setImmediate(continuation, {ThisMember}lastError{res}{resField});  }});");

            TabOut($"}} // {cmdName}()");
        } // GenCommand()
Beispiel #30
0
        } // GenMarshalingMethod()

        /// <summary>
        /// Structures in C are classes in TypeScript
        /// </summary>
        /// <param name="s"></param>
        void GenStruct(TpmStruct s)
        {
            bool   hasBase    = s.DerivedFrom != null;
            string className  = s.Name;
            string classBases = hasBase ? s.DerivedFrom.Name
                              : !s.IsCmdStruct() ? "TpmStructure"
                              : s.Info.IsRequest() ? "ReqStructure" : "RespStructure";

            // If this struct is not derived from another one and is a member of one or more unions,
            // it must implement the corresponding union interfaces
            if (!s.IsCmdStruct() && !hasBase)
            {
                string unionInterfaces = string.Join(", ", s.ContainingUnions.Select(u => u.Name));
                if (unionInterfaces != "")
                {
                    classBases += " implements " + unionInterfaces;
                }
            }

            // Javadoc comment for the data structure
            WriteComment(s);

            // Class header
            Write($"export class {className} extends {classBases}");
            TabIn("{");

            // In TypeScript, member fields declaration is melded with member-wise constructor
            // that also playe the role of the default one

            //
            // Field defining constructor
            //
            var fields = s.FieldHolder.NonTagFields;

            if (fields.Count() == 0)
            {
                Write("constructor() { super(); }");
            }
            else
            {
                Write("constructor(");
                TabIn();

                // If a non-trivial base class is present, all member fields are contained there,
                // so just pass through the initialization parameters
                string ctrParamQualifier = hasBase ? "" : "public ";
                string baseIntializers   = "";
                foreach (var f in fields)
                {
                    // Javadoc comment for the member/constructor parameter.
                    // Add a list of data structures implementing the interface of a union parameters.
                    WriteComment(f);

                    string comma = Separator(f, fields, ", ");
                    Write($"{ctrParamQualifier}{f.Name}: {f.TypeName} = {f.GetInitVal()}{comma}");
                    if (hasBase)
                    {
                        baseIntializers += f.Name + comma;
                    }
                }
                TabOut($") {{ super({baseIntializers}); }}");

                //
                // Named union tag getters (instead of the corresponding fields in the TPM 2.0 spec)
                //
                foreach (var sel in s.TagFields)
                {
                    if (sel.MarshalType != MarshalType.UnionSelector)
                    {
                        continue;
                    }

                    var    u          = (TpmUnion)sel.RelatedUnion.Type;
                    string unionField = ThisMember + sel.RelatedUnion.Name;
                    WriteComment(sel);
                    Write($"get {sel.Name}(): {sel.TypeName} {{ ", false);
                    if (u.NullSelector == null)
                    {
                        Write($"return {unionField}.GetUnionSelector(); }}");
                    }
                    else
                    {
                        Write($"return {unionField} ? {unionField}.GetUnionSelector()" +
                              $" : {u.NullSelector.QualifiedName}; }}");
                    }
                }
            }

            //
            // Union interface: TpmUnion.GetUnionSelector()
            //
            GenGetUnionSelector(s);

            //
            // Marshaling
            //
            GenMarshalingMethod(true, s);
            GenMarshalingMethod(false, s);

            WriteComment("Static marshaling helper");
            Write($"public static fromTpm(buf: TpmBuffer) : {className}");
            TabIn("{");
            Write($"return buf.createObj({className});");
            TabOut("}");

            WriteComment("Static marshaling helper");
            Write($"public static fromBytes(buffer: any) : {className}");
            TabIn("{");
            Write($"return new TpmBuffer(buffer).createObj({className});");
            TabOut("}");

            var info = s.IsCmdStruct() ? s.Info as CmdStructInfo : null;

            if (info != null && (info.NumHandles != 0 || info.SessEncSizeLen != 0))
            {
                if (info.NumHandles != 0)
                {
                    Write($"numHandles(): number {{ return {info.NumHandles}; }}");
                    if (info.IsRequest())
                    {
                        string handles = string.Join(", ", s.Fields.Take(info.NumHandles).Select(f => ThisMember + f.Name));
                        Write($"numAuthHandles(): number {{ return {info.NumAuthHandles}; }}");
                        Write($"getHandles(): TPM_HANDLE[] {{ return [{handles}]; }}");
                    }
                    else
                    {
                        Debug.Assert(info.NumHandles == 1 && info.NumAuthHandles == 0);
                        Write($"getHandle(): TPM_HANDLE {{ return {ThisMember}{s.Fields[0].Name}; }}");
                        Write($"setHandle(h: TPM_HANDLE): void {{ {ThisMember}{s.Fields[0].Name} = h; }}");
                    }
                }
                if (info.SessEncSizeLen != 0)
                {
                    Debug.Assert(info.SessEncValLen != 0);
                    Write("");
                    Write($"sessEncInfo(): SessEncInfo {{ return new SessEncInfo({info.SessEncSizeLen}, {info.SessEncValLen}); }}");
                }
            }

            //
            // Custom members
            //
            InsertSnip(s.Name);

            TabOut($"}} // {className}");
        } // GenStruct()