// -------------------------------------------------------------------------------------------------------------------- // // This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. // // // Helper utilities for native interop. // // -------------------------------------------------------------------------------------------------------------------- namespace HandBrake.Interop { using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using HandBrake.Interop.HbLib; /// /// Helper utilities for native interop. /// public static class InteropUtilities { /// /// Reads the given native structure pointer. /// /// The type to convert the structure to. /// The pointer to the native structure. /// The converted structure. public static T ReadStructure(IntPtr structPtr) { return (T)Marshal.PtrToStructure(structPtr, typeof(T)); } /// /// Reads the given native UTF-8 string. /// /// The pointer to the string. /// The resulting string. public static string ReadUtf8Ptr(IntPtr stringPtr) { var data = new List(); var ptr = stringPtr; var offset = 0; while (true) { byte ch = Marshal.ReadByte(ptr, offset++); if (ch == 0) { break; } data.Add(ch); } return Encoding.UTF8.GetString(data.ToArray()); } /// /// Creates a pointer to a UTF-8 null-terminated string. /// /// The string to encode. public static IntPtr CreateUtf8Ptr(string str) { byte[] bytes = Encoding.UTF8.GetBytes(str); IntPtr stringPtr = Marshal.AllocHGlobal(bytes.Length + 1); var offset = 0; foreach (byte b in bytes) { Marshal.WriteByte(stringPtr, offset, b); offset++; } Marshal.WriteByte(stringPtr, offset, 0); return stringPtr; } /// /// Converts the given native HandBrake list to a managed list. /// /// The type of structure in the list. /// The pointer to the native list. /// The converted managed list. public static List ToList(this IntPtr listPtr) { List returnList = new List(); hb_list_s itemList = ReadStructure(listPtr); for (int i = 0; i < itemList.items_count; i++) { IntPtr itemPtr = Marshal.ReadIntPtr(itemList.items, i * Marshal.SizeOf(typeof(IntPtr))); returnList.Add(ReadStructure(itemPtr)); } return returnList; } /// /// Converts the HB list to a managed list of pointers. /// /// The list to convert. /// The managed list of pointers. public static List ToIntPtrList(this IntPtr listPtr) { var returnList = new List(); hb_list_s itemList = ReadStructure(listPtr); for (int i = 0; i < itemList.items_count; i++) { IntPtr itemPtr = Marshal.ReadIntPtr(itemList.items, i * Marshal.SizeOf(typeof(IntPtr))); returnList.Add(itemPtr); } return returnList; } /// /// Converts the given native array to a managed collection. /// /// The type of item in the list. /// The pointer to the array. /// The number of items in the array. /// The converted collection. public static IEnumerable ConvertArray(IntPtr arrayPtr, int count) { IntPtr currentItem = arrayPtr; var result = new List(); for (int i = 0; i < count; i++) { T nativeEncoder = ReadStructure(currentItem); result.Add(nativeEncoder); currentItem = IntPtr.Add(currentItem, Marshal.SizeOf(typeof(T))); } return result; } /// /// Creats a new, empty native HandBrake list. /// /// The capacity of the new list. /// The new native list. public static NativeList CreateNativeList(int capacity) { NativeList returnList = new NativeList(); int intSize = Marshal.SizeOf(typeof(IntPtr)); IntPtr nativeListInternal = Marshal.AllocHGlobal(capacity * intSize); returnList.AllocatedMemory.Add(nativeListInternal); hb_list_s nativeListStruct = new hb_list_s { items = nativeListInternal, items_alloc = capacity, items_count = 0 }; IntPtr nativeListStructPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(hb_list_s))); Marshal.StructureToPtr(nativeListStruct, nativeListStructPtr, false); returnList.ListPtr = nativeListStructPtr; return returnList; } /// /// Creates a native HandBrake list from the given managed list of pointers. /// /// The managed list to convert. /// The converted native list. public static NativeList CreateIntPtrList(List list) { NativeList returnList = new NativeList(); int intSize = Marshal.SizeOf(typeof(IntPtr)); IntPtr nativeListInternal = Marshal.AllocHGlobal(list.Count * intSize); returnList.AllocatedMemory.Add(nativeListInternal); for (int i = 0; i < list.Count; i++) { Marshal.WriteIntPtr(nativeListInternal, i * intSize, list[i]); } hb_list_s nativeListStruct = new hb_list_s { items = nativeListInternal, items_alloc = list.Count, items_count = list.Count }; IntPtr nativeListStructPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(hb_list_s))); Marshal.StructureToPtr(nativeListStruct, nativeListStructPtr, false); returnList.ListPtr = nativeListStructPtr; return returnList; } /// /// Creates a native HandBrake list from the given managed list of structures. /// /// The type of structures in the list. /// The managed list to convert. /// The converted native list. public static NativeList ConvertListBack(List list) { NativeList returnList = new NativeList(); int intSize = Marshal.SizeOf(typeof(IntPtr)); IntPtr nativeListInternal = Marshal.AllocHGlobal(list.Count * intSize); returnList.AllocatedMemory.Add(nativeListInternal); for (int i = 0; i < list.Count; i++) { IntPtr itemPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(T))); returnList.AllocatedMemory.Add(itemPtr); Marshal.StructureToPtr(list[i], itemPtr, false); Marshal.WriteIntPtr(nativeListInternal, i * intSize, itemPtr); } hb_list_s nativeListStruct = new hb_list_s { items = nativeListInternal, items_alloc = list.Count, items_count = list.Count }; IntPtr nativeListStructPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(hb_list_s))); Marshal.StructureToPtr(nativeListStruct, nativeListStructPtr, false); returnList.ListPtr = nativeListStructPtr; return returnList; } /// /// Reads in a list of objects given an interator and a conversion function. /// /// The type of the struct given by the iterator. /// The object type to convert to. /// The iterator to use to build the list. /// The converter to convert from the struct to the object. /// The list of objects. public static List GetListFromIterator(Func iterator, Func converter) { return ReadStructureListFromIterator(iterator).Select(converter).ToList(); } /// /// Reads in a list of structs given an iterator. /// /// The type of the struct. /// The iterator to use to build the list. /// The list of structs. public static List ReadStructureListFromIterator(Func iterator) { var structureList = new List(); IntPtr current = IntPtr.Zero; current = iterator(current); while (current != IntPtr.Zero) { T encoder = ReadStructure(current); structureList.Add(encoder); current = iterator(current); } return structureList; } /// /// Closes the given job. /// /// The pointer to the job. public static void CloseJob(IntPtr nativeJobPtr) { // Create a point to the job pointer first. IntPtr nativeJobPtrPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr))); // Assign the new pointer to the job pointer and tell HB to clean the job up. Marshal.WriteIntPtr(nativeJobPtrPtr, nativeJobPtr); HBFunctions.hb_job_close(nativeJobPtrPtr); // Free the pointer we used. Marshal.FreeHGlobal(nativeJobPtrPtr); } /// /// Frees all the memory locations in the given list. /// /// The list of memory locations to free. public static void FreeMemory(List memoryList) { foreach (IntPtr memoryLocation in memoryList) { Marshal.FreeHGlobal(memoryLocation); } } } }