// -------------------------------------------------------------------------------------------------------------------- // // 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.Interop.Helpers { using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using HandBrake.Interop.Interop.HbLib; using HandBrake.Interop.Interop.HbLib.Wrappers.Interfaces; using HandBrake.Interop.Interop.Providers; using HandBrake.Interop.Interop.Providers.Interfaces; /// /// Helper utilities for native interop. /// internal static class InteropUtilities { private static IHbFunctions hbFunctions; static InteropUtilities() { IHbFunctionsProvider hbFunctionsProvider = new HbFunctionsProvider(); hbFunctions = hbFunctionsProvider.GetHbFunctionsWrapper(); } /// /// 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 ToStructureFromPtr(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 ToStringFromUtf8Ptr(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. /// /// /// The . /// public static IntPtr ToUtf8PtrFromString(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 ToListFromHandBrakeList(this IntPtr listPtr) { List returnList = new List(); NativeList nativeList = new NativeList(listPtr); for (int i = 0; i < nativeList.Count; i++) { IntPtr itemPtr = nativeList[i]; returnList.Add(ToStructureFromPtr(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(); NativeList nativeList = new NativeList(listPtr); for (int i = 0; i < nativeList.Count; i++) { IntPtr itemPtr = nativeList[i]; 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 List ToListFromNativeArray(IntPtr arrayPtr, int count) { IntPtr currentItem = arrayPtr; var result = new List(); for (int i = 0; i < count; i++) { T nativeEncoder = ToStructureFromPtr(currentItem); result.Add(nativeEncoder); currentItem = IntPtr.Add(currentItem, Marshal.SizeOf(typeof(T))); } return result; } /// /// Takes an array pointer and converts it into a list of strings. /// /// A pointer to a raw list of strings. /// The list of strings. public static List ToStringListFromArrayPtr(IntPtr arrayPtr) { if (arrayPtr == IntPtr.Zero) { return null; } return ToPtrListFromPtr(arrayPtr).Select(ptr => Marshal.PtrToStringAnsi(ptr)).ToList(); } /// /// Finds all the pointers starting at the given location and puts them in a list. Stops when it finds zero for a pointer. /// /// The address of the list of pointers. /// The list of pointers. public static List ToPtrListFromPtr(IntPtr arrayPtr) { var result = new List(); int ptrSize = Marshal.SizeOf(typeof(IntPtr)); IntPtr currentPtr = Marshal.ReadIntPtr(arrayPtr); for (int i = 0; currentPtr != IntPtr.Zero; i++) { result.Add(currentPtr); currentPtr = Marshal.ReadIntPtr(arrayPtr, (i + 1) * ptrSize); } return result; } /// /// Creates a native HandBrake list from the given managed list of pointers. /// /// The managed list to convert. /// The converted native list. public static NativeList ToHandBrakeListFromPtrList(List list) { NativeList returnList = NativeList.CreateList(); foreach (IntPtr ptr in list) { returnList.Add(ptr); } 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 ToHandBrakeListFromList(List list) { NativeList returnList = NativeList.CreateList(); foreach (T item in list) { IntPtr itemPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(T))); returnList.AllocatedMemory.Add(itemPtr); Marshal.StructureToPtr(item, itemPtr, false); returnList.Add(itemPtr); } return returnList; } /// /// Reads in a list of objects given an iterator 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 ToListFromIterator(Func iterator, Func converter) { return ToListFromIterator(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 ToListFromIterator(Func iterator) { var structureList = new List(); IntPtr current = IntPtr.Zero; current = iterator(current); while (current != IntPtr.Zero) { T encoder = ToStructureFromPtr(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); } } } }