Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 48aae61

Browse files
phkelleynulltoken
authored andcommitted
Improve perf and correctness of UTF-8 marshaling
1 parent 0a0d157 commit 48aae61

File tree

6 files changed

+245
-100
lines changed

6 files changed

+245
-100
lines changed

LibGit2Sharp/ContentChanges.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,15 @@ private int FileCallback(GitDiffDelta delta, float progress, IntPtr payload)
3939

4040
private int HunkCallback(GitDiffDelta delta, GitDiffRange range, IntPtr header, UIntPtr headerlen, IntPtr payload)
4141
{
42-
string decodedContent = Utf8Marshaler.FromNative(header, (uint)headerlen);
42+
string decodedContent = Utf8Marshaler.FromNative(header, (int)headerlen);
4343

4444
AppendToPatch(decodedContent);
4545
return 0;
4646
}
4747

4848
private int LineCallback(GitDiffDelta delta, GitDiffRange range, GitDiffLineOrigin lineorigin, IntPtr content, UIntPtr contentlen, IntPtr payload)
4949
{
50-
string decodedContent = Utf8Marshaler.FromNative(content, (uint)contentlen);
50+
string decodedContent = Utf8Marshaler.FromNative(content, (int)contentlen);
5151

5252
string prefix;
5353

LibGit2Sharp/Core/FilePathMarshaler.cs

Lines changed: 102 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,43 +3,132 @@
33

44
namespace LibGit2Sharp.Core
55
{
6-
internal class FilePathMarshaler : Utf8Marshaler
6+
/// <summary>
7+
/// This marshaler is to be used for capturing a UTF-8 string owned by libgit2 and
8+
/// converting it to a managed FilePath instance. The marshaler will not attempt to
9+
/// free the native pointer after conversion, because the memory is owned by libgit2.
10+
///
11+
/// Use this marshaler for return values, for example:
12+
/// [return: MarshalAs(UnmanagedType.CustomMarshaler,
13+
/// MarshalTypeRef = typeof(FilePathNoCleanupMarshaler))]
14+
/// </summary>
15+
internal class FilePathNoCleanupMarshaler : FilePathMarshaler
16+
{
17+
private static readonly FilePathNoCleanupMarshaler staticInstance = new FilePathNoCleanupMarshaler();
18+
19+
public static new ICustomMarshaler GetInstance(String cookie)
20+
{
21+
return staticInstance;
22+
}
23+
24+
#region ICustomMarshaler
25+
26+
public override void CleanUpNativeData(IntPtr pNativeData)
27+
{
28+
}
29+
30+
#endregion
31+
}
32+
33+
/// <summary>
34+
/// This marshaler is to be used for sending managed FilePath instances to libgit2.
35+
/// The marshaler will allocate a buffer in native memory to hold the UTF-8 string
36+
/// and perform the encoding conversion using that buffer as the target. The pointer
37+
/// received by libgit2 will be to this buffer. After the function call completes, the
38+
/// native buffer is freed.
39+
///
40+
/// Use this marshaler for function parameters, for example:
41+
/// [DllImport(libgit2)]
42+
/// internal static extern int git_index_open(out IndexSafeHandle index,
43+
/// [MarshalAs(UnmanagedType.CustomMarshaler,
44+
/// MarshalTypeRef = typeof(FilePathMarshaler))] FilePath indexpath);
45+
/// </summary>
46+
internal class FilePathMarshaler : ICustomMarshaler
747
{
848
private static readonly FilePathMarshaler staticInstance = new FilePathMarshaler();
949

10-
public override IntPtr MarshalManagedToNative(object managedObj)
50+
public static ICustomMarshaler GetInstance(String cookie)
51+
{
52+
return staticInstance;
53+
}
54+
55+
#region ICustomMarshaler
56+
57+
public void CleanUpManagedData(Object managedObj)
58+
{
59+
}
60+
61+
public virtual void CleanUpNativeData(IntPtr pNativeData)
62+
{
63+
if (IntPtr.Zero != pNativeData)
64+
{
65+
Marshal.FreeHGlobal(pNativeData);
66+
}
67+
}
68+
69+
public int GetNativeDataSize()
70+
{
71+
// Not a value type
72+
return -1;
73+
}
74+
75+
public IntPtr MarshalManagedToNative(Object managedObj)
1176
{
12-
if (managedObj == null)
77+
if (null == managedObj)
1378
{
1479
return IntPtr.Zero;
1580
}
1681

17-
if (!(managedObj is FilePath))
82+
FilePath filePath = managedObj as FilePath;
83+
84+
if (null == filePath)
1885
{
1986
throw new MarshalDirectiveException("FilePathMarshaler must be used on a FilePath.");
2087
}
2188

22-
return StringToNative(((FilePath)managedObj).Posix);
89+
return FilePathMarshaler.FromManaged(filePath);
2390
}
2491

25-
public override object MarshalNativeToManaged(IntPtr pNativeData)
92+
public Object MarshalNativeToManaged(IntPtr pNativeData)
2693
{
27-
return (FilePath)NativeToString(pNativeData);
94+
return FilePathMarshaler.FromNative(pNativeData);
2895
}
2996

30-
public static IntPtr FromManaged(FilePath managedObj)
97+
#endregion
98+
99+
public static unsafe IntPtr FromManaged(FilePath filePath)
31100
{
32-
return staticInstance.MarshalManagedToNative(managedObj);
101+
if (null == filePath)
102+
{
103+
return IntPtr.Zero;
104+
}
105+
106+
return Utf8Marshaler.FromManaged(filePath.Posix);
33107
}
34108

35-
public new static FilePath FromNative(IntPtr pNativeData)
109+
public static unsafe FilePath FromNative(IntPtr pNativeData)
36110
{
37-
return (FilePath)staticInstance.MarshalNativeToManaged(pNativeData);
111+
if (IntPtr.Zero == pNativeData)
112+
{
113+
return null;
114+
}
115+
116+
if (0 == Marshal.ReadByte(pNativeData))
117+
{
118+
return FilePath.Empty;
119+
}
120+
121+
return (FilePath)Utf8Marshaler.FromNative(pNativeData);
38122
}
39123

40-
public new static ICustomMarshaler GetInstance(string cookie)
124+
public static unsafe FilePath FromNative(IntPtr pNativeData, int length)
41125
{
42-
return staticInstance;
126+
if (0 == length)
127+
{
128+
return FilePath.Empty;
129+
}
130+
131+
return (FilePath)Utf8Marshaler.FromNative(pNativeData, length);
43132
}
44133
}
45134
}

LibGit2Sharp/Core/NativeMethods.cs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,11 @@ internal static extern int git_commit_create(
190190
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 7)] [In] IntPtr[] parents);
191191

192192
[DllImport(libgit2)]
193-
[return : MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]
193+
[return : MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8NoCleanupMarshaler))]
194194
internal static extern string git_commit_message(GitObjectSafeHandle commit);
195195

196196
[DllImport(libgit2)]
197-
[return : MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]
197+
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8NoCleanupMarshaler))]
198198
internal static extern string git_commit_message_encoding(GitObjectSafeHandle commit);
199199

200200
[DllImport(libgit2)]
@@ -459,7 +459,7 @@ internal static extern int git_note_create(
459459
internal static extern void git_note_free(IntPtr note);
460460

461461
[DllImport(libgit2)]
462-
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]
462+
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8NoCleanupMarshaler))]
463463
internal static extern string git_note_message(NoteSafeHandle note);
464464

465465
[DllImport(libgit2)]
@@ -482,7 +482,7 @@ internal static extern int git_note_remove(
482482

483483
[DllImport(libgit2)]
484484
internal static extern int git_note_default_ref(
485-
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] out string notes_ref,
485+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8NoCleanupMarshaler))] out string notes_ref,
486486
RepositorySafeHandle repo);
487487

488488
internal delegate int git_note_foreach_cb(
@@ -572,7 +572,7 @@ internal static extern int git_reference_lookup(
572572
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string name);
573573

574574
[DllImport(libgit2)]
575-
[return : MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]
575+
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8NoCleanupMarshaler))]
576576
internal static extern string git_reference_name(ReferenceSafeHandle reference);
577577

578578
[DllImport(libgit2)]
@@ -596,7 +596,7 @@ internal static extern int git_reference_symbolic_set_target(
596596
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string target);
597597

598598
[DllImport(libgit2)]
599-
[return : MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]
599+
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8NoCleanupMarshaler))]
600600
internal static extern string git_reference_symbolic_target(ReferenceSafeHandle reference);
601601

602602
[DllImport(libgit2)]
@@ -612,7 +612,7 @@ internal static extern int git_remote_load(
612612
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string name);
613613

614614
[DllImport(libgit2)]
615-
[return : MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]
615+
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8NoCleanupMarshaler))]
616616
internal static extern string git_remote_name(RemoteSafeHandle remote);
617617

618618
[DllImport(libgit2)]
@@ -623,7 +623,7 @@ internal static extern int git_remote_create(
623623
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string url);
624624

625625
[DllImport(libgit2)]
626-
[return : MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]
626+
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8NoCleanupMarshaler))]
627627
internal static extern string git_remote_url(RemoteSafeHandle remote);
628628

629629
[DllImport(libgit2)]
@@ -708,7 +708,7 @@ internal static extern int git_repository_open(
708708
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(FilePathMarshaler))] FilePath path);
709709

710710
[DllImport(libgit2)]
711-
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(FilePathMarshaler))]
711+
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(FilePathNoCleanupMarshaler))]
712712
internal static extern FilePath git_repository_path(RepositorySafeHandle repository);
713713

714714
[DllImport(libgit2)]
@@ -732,7 +732,7 @@ internal static extern int git_repository_state(
732732
RepositorySafeHandle repository);
733733

734734
[DllImport(libgit2)]
735-
[return : MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(FilePathMarshaler))]
735+
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(FilePathNoCleanupMarshaler))]
736736
internal static extern FilePath git_repository_workdir(RepositorySafeHandle repository);
737737

738738
[DllImport(libgit2)]
@@ -819,11 +819,11 @@ internal static extern int git_tag_delete(
819819
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string tagName);
820820

821821
[DllImport(libgit2)]
822-
[return : MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]
822+
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8NoCleanupMarshaler))]
823823
internal static extern string git_tag_message(GitObjectSafeHandle tag);
824824

825825
[DllImport(libgit2)]
826-
[return : MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]
826+
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8NoCleanupMarshaler))]
827827
internal static extern string git_tag_name(GitObjectSafeHandle tag);
828828

829829
[DllImport(libgit2)]
@@ -862,7 +862,7 @@ internal static extern int git_tree_entry_bypath(
862862
internal static extern OidSafeHandle git_tree_entry_id(SafeHandle entry);
863863

864864
[DllImport(libgit2)]
865-
[return : MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]
865+
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8NoCleanupMarshaler))]
866866
internal static extern string git_tree_entry_name(SafeHandle entry);
867867

868868
[DllImport(libgit2)]

0 commit comments

Comments
 (0)