Skip to content

Commit cf3adfd

Browse files
irsltyranid
authored andcommitted
CPP style NDR formatting (#21)
* initial support for cpp style NDR formatting * simple types are now adjusted to standard c++ types names by the formatter
1 parent 3beeb4f commit cf3adfd

12 files changed

Lines changed: 271 additions & 47 deletions

NtApiDotNet/Ndr/NdrArrayTypes.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public override int GetSize()
6464
return ElementCount * ElementSize;
6565
}
6666

67-
internal override string FormatType(NdrFormatter context)
67+
internal override string FormatType(INdrFormatterInternal context)
6868
{
6969
return string.Format("{0}[{1}]", ElementType.FormatType(context), ElementCount == 0 ? string.Empty : ElementCount.ToString());
7070
}
@@ -149,7 +149,7 @@ protected override int GetElementCount()
149149
return 0;
150150
}
151151

152-
internal override string FormatType(NdrFormatter context)
152+
internal override string FormatType(INdrFormatterInternal context)
153153
{
154154
StringBuilder builder = new StringBuilder();
155155
if (ConformanceDescriptor.IsValid)
@@ -205,7 +205,7 @@ protected override int GetElementCount()
205205
return 0;
206206
}
207207

208-
internal override string FormatType(NdrFormatter context)
208+
internal override string FormatType(INdrFormatterInternal context)
209209
{
210210
StringBuilder builder = new StringBuilder();
211211
if (ConformanceDescriptor != null && ConformanceDescriptor.IsValid)
@@ -274,7 +274,7 @@ protected override int GetElementCount()
274274
return 0;
275275
}
276276

277-
internal override string FormatType(NdrFormatter context)
277+
internal override string FormatType(INdrFormatterInternal context)
278278
{
279279
StringBuilder builder = new StringBuilder();
280280
if (VarianceDescriptor != null && VarianceDescriptor.IsValid)

NtApiDotNet/Ndr/NdrComProxyDefinition.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public static NdrComProxyDefinition FromProcedures(string name, Guid iid, Guid b
7373
return new NdrComProxyDefinition(name, iid, base_iid, dispatch_count, procedures.ToList().AsReadOnly());
7474
}
7575

76-
internal string Format(NdrFormatter context)
76+
internal string Format(INdrFormatterInternal context)
7777
{
7878
NdrStringBuilder builder = new NdrStringBuilder();
7979
builder.AppendLine("[Guid(\"{0}\")]", Iid);

NtApiDotNet/Ndr/NdrFormatter.cs

Lines changed: 239 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
using System;
1616
using System.Collections.Generic;
17+
using System.Linq;
1718

1819
namespace NtApiDotNet.Ndr
1920
{
@@ -51,23 +52,39 @@ public interface INdrFormatter
5152
string FormatRpcServerInterface(NdrRpcServerInterface rpc_server);
5253
}
5354

55+
internal interface INdrFormatterInternal : INdrFormatter
56+
{
57+
string SimpleTypeToName(NdrFormatCharacter format);
58+
string FormatComment(string comment);
59+
string FormatComment(string comment, params object[] args);
60+
string FormatPointer(string base_type);
61+
string IidToName(Guid iid);
62+
string DemangleComName(string name);
63+
bool ShowProcedureParameterAttributes { get; }
64+
}
65+
5466
/// <summary>
5567
/// An base class which describes a text formatter for NDR data.
5668
/// </summary>
57-
internal class NdrFormatter : INdrFormatter
69+
internal class NdrFormatter : INdrFormatterInternal
5870
{
5971
private readonly IDictionary<Guid, string> _iids_to_name;
6072
private readonly Func<string, string> _demangle_com_name;
6173
private DefaultNdrFormatterFlags _flags;
6274

75+
bool INdrFormatterInternal.ShowProcedureParameterAttributes { get { return true; } }
76+
6377
internal NdrFormatter(IDictionary<Guid, string> iids_to_names, Func<string, string> demangle_com_name, DefaultNdrFormatterFlags flags)
6478
{
6579
_iids_to_name = iids_to_names;
66-
_demangle_com_name = demangle_com_name;
80+
_demangle_com_name = demangle_com_name ?? (s => s);
6781
_flags = flags;
6882
}
69-
70-
internal string IidToName(Guid iid)
83+
string INdrFormatterInternal.IidToName(Guid iid)
84+
{
85+
return IidToName(iid);
86+
}
87+
protected string IidToName(Guid iid)
7188
{
7289
if (_iids_to_name.ContainsKey(iid))
7390
{
@@ -76,12 +93,12 @@ internal string IidToName(Guid iid)
7693
return null;
7794
}
7895

79-
internal string DemangleComName(string name)
96+
string INdrFormatterInternal.DemangleComName(string name)
8097
{
8198
return _demangle_com_name(name);
8299
}
83100

84-
internal string SimpleTypeToName(NdrFormatCharacter format)
101+
string INdrFormatterInternal.SimpleTypeToName(NdrFormatCharacter format)
85102
{
86103
switch (format)
87104
{
@@ -136,12 +153,21 @@ internal string SimpleTypeToName(NdrFormatCharacter format)
136153
return string.Format("{0}", format);
137154
}
138155

139-
internal string FormatPointer(string base_type)
156+
string INdrFormatterInternal.FormatPointer(string base_type)
140157
{
141158
return $"{base_type}*";
142159
}
143160

144-
internal string FormatComment(string comment)
161+
string INdrFormatterInternal.FormatComment(string comment)
162+
{
163+
return FormatComment(comment);
164+
}
165+
string INdrFormatterInternal.FormatComment(string comment, params object[] args)
166+
{
167+
return FormatComment(string.Format(comment, args));
168+
}
169+
170+
private string FormatComment(string comment)
145171
{
146172
if ((_flags & DefaultNdrFormatterFlags.RemoveComments) == DefaultNdrFormatterFlags.RemoveComments)
147173
{
@@ -150,11 +176,6 @@ internal string FormatComment(string comment)
150176
return $"/* {comment} */";
151177
}
152178

153-
internal string FormatComment(string comment, params object[] args)
154-
{
155-
return FormatComment(string.Format(comment, args));
156-
}
157-
158179
string INdrFormatter.FormatComplexType(NdrComplexTypeReference complex_type)
159180
{
160181
return complex_type.FormatComplexType(this);
@@ -176,6 +197,139 @@ string INdrFormatter.FormatRpcServerInterface(NdrRpcServerInterface rpc_server)
176197
}
177198
}
178199

200+
201+
/**
202+
* This formatter generates data that the CPP compiler can (hopefully) understand,
203+
* at least it will serve as a good skeleton to support spinning up new projects easily.
204+
* */
205+
internal class CppNdrFormatterInternal : NdrFormatter, INdrFormatterInternal
206+
{
207+
internal CppNdrFormatterInternal(IDictionary<Guid, string> iids_to_names, Func<string, string> demangle_com_name, DefaultNdrFormatterFlags flags)
208+
: base(iids_to_names, demangle_com_name, flags)
209+
{
210+
211+
}
212+
213+
bool INdrFormatterInternal.ShowProcedureParameterAttributes { get { return false; } }
214+
215+
string INdrFormatterInternal.SimpleTypeToName(NdrFormatCharacter format)
216+
{
217+
switch (format)
218+
{
219+
case NdrFormatCharacter.FC_BYTE:
220+
case NdrFormatCharacter.FC_USMALL:
221+
return "uint8_t";
222+
case NdrFormatCharacter.FC_SMALL:
223+
case NdrFormatCharacter.FC_CHAR:
224+
return "int8_t";
225+
case NdrFormatCharacter.FC_WCHAR:
226+
return "wchar_t";
227+
case NdrFormatCharacter.FC_SHORT:
228+
return "int16_t";
229+
case NdrFormatCharacter.FC_USHORT:
230+
return "uint16_t";
231+
case NdrFormatCharacter.FC_LONG:
232+
return "int64_t";
233+
case NdrFormatCharacter.FC_ULONG:
234+
return "uint64_t";
235+
case NdrFormatCharacter.FC_FLOAT:
236+
return "float";
237+
case NdrFormatCharacter.FC_HYPER:
238+
return "int64_t";
239+
case NdrFormatCharacter.FC_DOUBLE:
240+
return "double";
241+
case NdrFormatCharacter.FC_INT3264:
242+
return "intptr_t";
243+
case NdrFormatCharacter.FC_UINT3264:
244+
return "uintptr_t";
245+
case NdrFormatCharacter.FC_C_WSTRING:
246+
case NdrFormatCharacter.FC_WSTRING:
247+
return "wchar_t";
248+
case NdrFormatCharacter.FC_C_CSTRING:
249+
case NdrFormatCharacter.FC_CSTRING:
250+
return "char";
251+
case NdrFormatCharacter.FC_ENUM16:
252+
return "/* ENUM16 */ uint16_t";
253+
case NdrFormatCharacter.FC_ENUM32:
254+
return "/* ENUM32 */ uint32_t";
255+
case NdrFormatCharacter.FC_SYSTEM_HANDLE:
256+
return "HANDLE";
257+
case NdrFormatCharacter.FC_AUTO_HANDLE:
258+
case NdrFormatCharacter.FC_CALLBACK_HANDLE:
259+
case NdrFormatCharacter.FC_BIND_CONTEXT:
260+
case NdrFormatCharacter.FC_BIND_PRIMITIVE:
261+
case NdrFormatCharacter.FC_BIND_GENERIC:
262+
return "handle_t";
263+
case NdrFormatCharacter.FC_ERROR_STATUS_T:
264+
return "uint";
265+
}
266+
267+
return string.Format("{0}", format);
268+
}
269+
270+
string INdrFormatter.FormatProcedure(NdrProcedureDefinition procedure)
271+
{
272+
return FormatProcedure(procedure);
273+
}
274+
private string FormatProcedure(NdrProcedureDefinition procedure)
275+
{
276+
string return_value;
277+
278+
if (procedure.ReturnValue == null)
279+
{
280+
return_value = "void";
281+
}
282+
else if (procedure.ReturnValue.Type.Format == NdrFormatCharacter.FC_LONG)
283+
{
284+
return_value = "HRESULT";
285+
}
286+
else
287+
{
288+
return_value = procedure.ReturnValue.Type.FormatType(this);
289+
}
290+
291+
string procedureParameters = string.Join(", ", procedure.Params.Select(
292+
(p, i) => string.Format(
293+
"{0} {1} {2}",
294+
(this as INdrFormatterInternal).FormatComment("Stack Offset: {0}", p.Offset),
295+
p.Format(this),
296+
p.FormatName(i)
297+
)
298+
));
299+
return string.Format("virtual {0} __stdcall {1}({2});", return_value,
300+
procedure.Name, procedureParameters);
301+
}
302+
303+
string INdrFormatter.FormatComProxy(NdrComProxyDefinition com_proxy)
304+
{
305+
NdrStringBuilder builder = new NdrStringBuilder();
306+
307+
string base_name = this.IidToName(com_proxy.BaseIid);
308+
if (base_name == null)
309+
{
310+
string unknown_iid = $"Unknown IID {com_proxy.BaseIid}";
311+
string comment = (this as INdrFormatterInternal).FormatComment(unknown_iid);
312+
base_name = $"{comment} IUnknown";
313+
}
314+
315+
builder.AppendLine(
316+
"class __declspec(uuid(\"{0}\")) {1} : public {2} {{\npublic:",
317+
com_proxy.Iid,
318+
(this as INdrFormatterInternal).DemangleComName(com_proxy.Name),
319+
base_name
320+
);
321+
322+
builder.PushIndent(' ', 4);
323+
foreach (NdrProcedureDefinition proc in com_proxy.Procedures)
324+
{
325+
builder.AppendLine(this.FormatProcedure(proc));
326+
}
327+
builder.PopIndent();
328+
builder.AppendLine("}").AppendLine();
329+
return builder.ToString();
330+
}
331+
}
332+
179333
/// <summary>
180334
/// Flags for the NDR formatter.
181335
/// </summary>
@@ -228,7 +382,7 @@ public static INdrFormatter Create(IDictionary<Guid, string> iids_to_names, Func
228382
/// <returns>The default formatter.</returns>
229383
public static INdrFormatter Create(IDictionary<Guid, string> iids_to_names, DefaultNdrFormatterFlags flags)
230384
{
231-
return Create(iids_to_names, s => s, flags);
385+
return Create(iids_to_names, null, flags);
232386
}
233387

234388
/// <summary>
@@ -238,7 +392,7 @@ public static INdrFormatter Create(IDictionary<Guid, string> iids_to_names, Defa
238392
/// <returns>The default formatter.</returns>
239393
public static INdrFormatter Create(IDictionary<Guid, string> iids_to_names)
240394
{
241-
return Create(iids_to_names, s => s);
395+
return Create(iids_to_names, null);
242396
}
243397

244398
/// <summary>
@@ -260,4 +414,74 @@ public static INdrFormatter Create()
260414
return Create(new Dictionary<Guid, string>());
261415
}
262416
}
417+
418+
419+
/// <summary>
420+
/// NDR formatter constructor for CPP style output.
421+
/// </summary>
422+
public static class CppNdrFormatter
423+
{
424+
/// <summary>
425+
/// Create the CPP formatter.
426+
/// </summary>
427+
/// <param name="iids_to_names">Specify a dictionary of IIDs to names.</param>
428+
/// <param name="demangle_com_name">Function to demangle COM interface names during formatting.</param>
429+
/// <param name="flags">Formatter flags.</param>
430+
/// <returns>The CPP formatter.</returns>
431+
public static INdrFormatter Create(IDictionary<Guid, string> iids_to_names, Func<string, string> demangle_com_name, DefaultNdrFormatterFlags flags)
432+
{
433+
return new CppNdrFormatterInternal(iids_to_names, demangle_com_name, flags);
434+
}
435+
436+
/// <summary>
437+
/// Create the CPP formatter.
438+
/// </summary>
439+
/// <param name="iids_to_names">Specify a dictionary of IIDs to names.</param>
440+
/// <param name="demangle_com_name">Function to demangle COM interface names during formatting.</param>
441+
/// <returns>The CPPformatter.</returns>
442+
public static INdrFormatter Create(IDictionary<Guid, string> iids_to_names, Func<string, string> demangle_com_name)
443+
{
444+
return Create(iids_to_names, demangle_com_name, DefaultNdrFormatterFlags.None);
445+
}
446+
447+
/// <summary>
448+
/// Create the CPP formatter.
449+
/// </summary>
450+
/// <param name="iids_to_names">Specify a dictionary of IIDs to names.</param>
451+
/// <param name="flags">Formatter flags.</param>
452+
/// <returns>The CPP formatter.</returns>
453+
public static INdrFormatter Create(IDictionary<Guid, string> iids_to_names, DefaultNdrFormatterFlags flags)
454+
{
455+
return Create(iids_to_names, null, flags);
456+
}
457+
458+
/// <summary>
459+
/// Create the CPP formatter.
460+
/// </summary>
461+
/// <param name="iids_to_names">Specify a dictionary of IIDs to names.</param>
462+
/// <returns>The CPP formatter.</returns>
463+
public static INdrFormatter Create(IDictionary<Guid, string> iids_to_names)
464+
{
465+
return Create(iids_to_names, null);
466+
}
467+
468+
/// <summary>
469+
/// Create the default formatter.
470+
/// </summary>
471+
/// <param name="flags">Formatter flags.</param>
472+
/// <returns>The CPP formatter.</returns>
473+
public static INdrFormatter Create(DefaultNdrFormatterFlags flags)
474+
{
475+
return Create(new Dictionary<Guid, string>(), flags);
476+
}
477+
478+
/// <summary>
479+
/// Create the default formatter.
480+
/// </summary>
481+
/// <returns>The CPP formatter.</returns>
482+
public static INdrFormatter Create()
483+
{
484+
return Create(new Dictionary<Guid, string>());
485+
}
486+
}
263487
}

NtApiDotNet/Ndr/NdrHandleTypes.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ internal NdrSystemHandleTypeReference(BinaryReader reader)
5656
AccessMask = reader.ReadUInt32();
5757
}
5858

59-
internal override string FormatType(NdrFormatter context)
59+
internal override string FormatType(INdrFormatterInternal context)
6060
{
6161
if (AccessMask != 0)
6262
{
@@ -118,7 +118,7 @@ internal NdrHandleTypeReference(NdrFormatCharacter format)
118118
{
119119
}
120120

121-
internal override string FormatType(NdrFormatter context)
121+
internal override string FormatType(INdrFormatterInternal context)
122122
{
123123
return $"{context.FormatComment(Format.ToString())} {context.SimpleTypeToName(Format)}";
124124
}

0 commit comments

Comments
 (0)