/CSPspEmu/Utils/CSharpUtils/PointerUtils.cs

https://github.com/soywiz/cspspemu · C# · 368 lines · 266 code · 42 blank · 60 comment · 44 complexity · 89c19564c20cb96d4431f808b3fb50bf MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Runtime.InteropServices;
  4. using System.Text;
  5. namespace CSharpUtils
  6. {
  7. public unsafe class PointerUtils
  8. {
  9. public static string PtrToStringUtf8(byte* pointer) => PtrToString(pointer, Encoding.UTF8);
  10. public static string PtrToString(byte* pointer, Encoding encoding)
  11. {
  12. if (pointer == null) return null;
  13. var bytes = new List<byte>();
  14. for (; *pointer != 0; pointer++) bytes.Add(*pointer);
  15. return encoding.GetString(bytes.ToArray());
  16. }
  17. public static ushort PtrToShort_BE(void* ptr)
  18. {
  19. var bytes = (byte*) ptr;
  20. //return (ushort)((bytes[1] << 8) | (bytes[0] << 8));
  21. return (ushort) ((bytes[0] << 8) | (bytes[1] << 0));
  22. }
  23. public static string PtrToString(byte* pointer, int length, Encoding encoding)
  24. {
  25. if (pointer == null) return null;
  26. var bytes = new List<byte>();
  27. for (var n = 0; n < length; n++)
  28. {
  29. if (pointer[n] == 0) break;
  30. bytes.Add(pointer[n]);
  31. }
  32. return encoding.GetString(bytes.ToArray());
  33. }
  34. public static void StoreStringOnPtr(string String, Encoding encoding, byte* pointer,
  35. int pointerMaxLength = 0x10000)
  36. {
  37. if (pointer == null) return;
  38. //if (String == null) return;
  39. if (String != null)
  40. {
  41. var bytes = encoding.GetBytes(String);
  42. foreach (var Byte in bytes)
  43. {
  44. *pointer++ = Byte;
  45. }
  46. }
  47. *pointer = 0;
  48. }
  49. public static void Memset(byte[] array, byte value, int count) => Memset(array, value, 0, count);
  50. public static void Memset(byte[] array, byte value, int offset, int count)
  51. {
  52. if (count <= 0) return;
  53. if (offset + count > array.Length)
  54. throw new InvalidOperationException("Array out of bounts");
  55. fixed (byte* arrayPointer = &array[offset])
  56. {
  57. Memset(arrayPointer, value, count);
  58. }
  59. }
  60. public static readonly bool Is64 = Environment.Is64BitProcess;
  61. public static void Memset(byte* pointer, byte value, int count) => new Span<byte>(pointer, count).Fill(value);
  62. public static void Memcpy(byte* destination, ArraySegment<byte> source)
  63. {
  64. if (source.Count > 0)
  65. {
  66. fixed (byte* sourcePtr = &source.Array[source.Offset])
  67. {
  68. Memcpy(destination, sourcePtr, source.Count);
  69. }
  70. }
  71. }
  72. public static void Memcpy(byte* destination, byte[] source, int count)
  73. {
  74. fixed (byte* sourcePtr = source)
  75. {
  76. Memcpy(destination, sourcePtr, count);
  77. }
  78. }
  79. public static void Memcpy(ArraySegment<byte> destination, byte* source)
  80. {
  81. //var Pin = GCHandle.Alloc(Destination.Array, GCHandleType.Pinned);
  82. //Pin.Free();
  83. if (destination.Count > 0)
  84. {
  85. fixed (byte* destinationPtr = &destination.Array[destination.Offset])
  86. {
  87. //Marshal.UnsafeAddrOfPinnedArrayElement(
  88. Memcpy(destinationPtr, source, destination.Count);
  89. }
  90. }
  91. }
  92. public static void Memcpy(byte[] destination, byte* source, int count)
  93. {
  94. fixed (byte* destinationPtr = destination)
  95. {
  96. Memcpy(destinationPtr, source, count);
  97. }
  98. }
  99. public static int FindLargestMatch(byte* haystack, byte* needle, int maxLength)
  100. {
  101. var match = 0;
  102. if (Is64)
  103. {
  104. while (maxLength >= 8 && *(ulong*) haystack == *(ulong*) needle)
  105. {
  106. match += 8;
  107. haystack += 8;
  108. needle += 8;
  109. maxLength -= 8;
  110. }
  111. }
  112. while (maxLength >= 4 && *(uint*) haystack == *(uint*) needle)
  113. {
  114. match += 4;
  115. haystack += 4;
  116. needle += 4;
  117. maxLength -= 4;
  118. }
  119. while (maxLength >= 1 && *haystack == *needle)
  120. {
  121. match += 1;
  122. haystack += 1;
  123. needle += 1;
  124. maxLength -= 1;
  125. }
  126. return match;
  127. }
  128. /// <summary>
  129. ///
  130. /// </summary>
  131. /// <param name="haystack"></param>
  132. /// <param name="value1"></param>
  133. /// <param name="maxLength"></param>
  134. /// <returns></returns>
  135. public static int FindLargestMatchByte(byte* haystack, byte value1, int maxLength)
  136. {
  137. var match = 0;
  138. if (maxLength >= 4)
  139. {
  140. var value2 = (ushort) ((value1 << 0) | (value1 << 8));
  141. var value4 = ((uint) value2 << 0) | ((uint) value2 << 16);
  142. if (maxLength >= 8 && Is64)
  143. {
  144. var value8 = ((ulong) value4 << 0) | ((ulong) value4 << 32);
  145. while (maxLength >= 8 && *(ulong*) haystack == value8)
  146. {
  147. match += 8;
  148. haystack += 8;
  149. maxLength -= 8;
  150. }
  151. }
  152. while (maxLength >= 4 && *(uint*) haystack == value4)
  153. {
  154. match += 4;
  155. haystack += 4;
  156. maxLength -= 4;
  157. }
  158. }
  159. while (maxLength >= 1 && *haystack == value1)
  160. {
  161. match += 1;
  162. haystack += 1;
  163. maxLength -= 1;
  164. }
  165. return match;
  166. }
  167. public static void Memcpy(byte* destination, byte* source, int size) {
  168. //Buffer.MemoryCopy(source, destination, size, size);
  169. new Span<byte>(source, size).CopyTo(new Span<byte>(destination, size));
  170. }
  171. public static byte[] PointerToByteArray(byte* pointer, int size)
  172. {
  173. var data = new byte[size];
  174. fixed (byte* dataPtr = data)
  175. {
  176. Memcpy(dataPtr, pointer, size);
  177. }
  178. return data;
  179. }
  180. /// <summary>
  181. ///
  182. /// </summary>
  183. /// <param name="array"></param>
  184. /// <param name="action"></param>
  185. /// <typeparam name="TType"></typeparam>
  186. public static void GetArrayPointer<TType>(TType[] array, Action<IntPtr> action)
  187. {
  188. var dataGc = GCHandle.Alloc(array, GCHandleType.Pinned);
  189. var dataPointer = dataGc.AddrOfPinnedObject();
  190. try
  191. {
  192. action(dataPointer);
  193. }
  194. finally
  195. {
  196. dataGc.Free();
  197. }
  198. }
  199. /// <summary>
  200. ///
  201. /// </summary>
  202. /// <param name="inputArray"></param>
  203. /// <typeparam name="TType"></typeparam>
  204. /// <returns></returns>
  205. public static byte[] ArrayToByteArray<TType>(TType[] inputArray)
  206. {
  207. var outputArray = new byte[inputArray.Length * Marshal.SizeOf(typeof(TType))];
  208. GetArrayPointer(inputArray,
  209. (inputPointer) =>
  210. {
  211. GetArrayPointer(outputArray,
  212. (outputPointer) =>
  213. {
  214. Memcpy((byte*) outputPointer.ToPointer(), (byte*) inputPointer.ToPointer(),
  215. outputArray.Length);
  216. });
  217. });
  218. return outputArray;
  219. }
  220. /// <summary>
  221. ///
  222. /// </summary>
  223. /// <param name="inputArray"></param>
  224. /// <typeparam name="TType"></typeparam>
  225. /// <returns></returns>
  226. public static TType[] ByteArrayToArray<TType>(byte[] inputArray)
  227. {
  228. var outputArray = new TType[inputArray.Length / Marshal.SizeOf(typeof(TType))];
  229. GetArrayPointer(inputArray,
  230. (inputPointer) =>
  231. {
  232. GetArrayPointer(outputArray,
  233. (outputPointer) =>
  234. {
  235. Memcpy((byte*) outputPointer.ToPointer(), (byte*) inputPointer.ToPointer(),
  236. inputArray.Length);
  237. });
  238. });
  239. return outputArray;
  240. }
  241. /// <summary>
  242. ///
  243. /// </summary>
  244. /// <param name="pointer"></param>
  245. /// <param name="arrayLength"></param>
  246. /// <typeparam name="TType"></typeparam>
  247. /// <returns></returns>
  248. public static TType[] PointerToArray<TType>(void* pointer, int arrayLength)
  249. {
  250. var array = new TType[arrayLength];
  251. GetArrayPointer(array,
  252. (dataPointer) =>
  253. {
  254. Memcpy((byte*) dataPointer.ToPointer(), (byte*) pointer,
  255. arrayLength * Marshal.SizeOf(typeof(TType)));
  256. });
  257. return array;
  258. }
  259. public static void ByteArrayToPointer(byte[] array, byte* output) => Memcpy(output, array, array.Length);
  260. public static string FixedByteGet(int size, byte* ptr) => PtrToStringUtf8(ptr);
  261. public static void FixedByteSet(int size, byte* ptr, string value) => StoreStringOnPtr(value, Encoding.UTF8, ptr, size);
  262. public static int Sizeof<T>() => Marshal.SizeOf(typeof(T));
  263. public static int Memcmp(byte* left, byte* right, int count)
  264. {
  265. for (var n = 0; n < count; n++)
  266. {
  267. var dif = left[n] - right[n];
  268. if (dif != 0) return dif;
  269. }
  270. return 0;
  271. }
  272. /// <summary>
  273. ///
  274. /// </summary>
  275. /// <param name="ptr"></param>
  276. /// <param name="len"></param>
  277. /// <returns></returns>
  278. public static int FastHash(byte* ptr, int len) => FastHash(new Span<byte>(ptr, len));
  279. public static int FastHash(Span<byte> data)
  280. {
  281. switch (data.Length)
  282. {
  283. case 0: return 0;
  284. case 1: return data[0] << 0;
  285. case 2: return (data[0] << 0) | (data[1] << 8);
  286. case 3: return (data[0] << 0) | (data[1] << 8) | (data[2] << 16);
  287. default:
  288. var hash = data.Length;
  289. for (var n = 0; n < data.Length; n++)
  290. {
  291. hash ^= n << 28;
  292. hash += data[n];
  293. }
  294. return hash;
  295. }
  296. }
  297. /// <summary>
  298. ///
  299. /// </summary>
  300. /// <param name="Object"></param>
  301. /// <param name="callback"></param>
  302. /// <typeparam name="TType"></typeparam>
  303. public static void SafeFixed<TType>(TType Object, Action<IntPtr> callback)
  304. {
  305. var handle = GCHandle.Alloc(Object, GCHandleType.Pinned);
  306. try
  307. {
  308. callback(handle.AddrOfPinnedObject());
  309. }
  310. finally
  311. {
  312. handle.Free();
  313. }
  314. }
  315. //public static unsafe void CopyStructWithSize<TType>(ref TType Destination, ref TType Source, int Size)
  316. //{
  317. // SafeFixed(ref Destination, (DestinationPtr) =>
  318. // {
  319. // SafeFixed(ref Source, (SourcePtr) =>
  320. // {
  321. // });
  322. // });
  323. // //Destination = Source;
  324. //}
  325. }
  326. }