/// <summary> /// Returns array of objects read from va_list with help of printf format string. /// </summary> /// <param name="msg"> printf format string. </param> /// <param name="args"> va_list of function parameters. </param> public static unsafe object[] GetObjectsByFormat(string format, va_list va_list) { string[] formatSpecifiers = Printf.GetFormatSpecifiers(format); if (formatSpecifiers == null || va_list == null || va_list.GetPointer() == IntPtr.Zero) return null; IntPtr args = va_list.GetPointer(); List<object> objects = new List<object>(formatSpecifiers.Length); int offset = 0; foreach (string spec in formatSpecifiers) { var info = Printf.GetFormatSpecifierInfo(spec); if (info.type == '\0') continue; // dynamic width and precision arguments // these are stored in stack before the actual value if (info.flags.HasFlag(Printf.FormatFlags.DynamicWidth)) { int widthArg = Marshal.ReadInt32(args, offset); objects.Add(widthArg); offset += Marshal.SizeOf(typeof(IntPtr)); } if (info.flags.HasFlag(Printf.FormatFlags.DynamicPrecision)) { int precArg = Marshal.ReadInt32(args, offset); objects.Add(precArg); offset += Marshal.SizeOf(typeof(IntPtr)); } int iSize = info.flags.HasFlag(Printf.FormatFlags.IsLongLong) ? Marshal.SizeOf(typeof(Int64)) : Marshal.SizeOf(typeof(IntPtr)); // marshal objects from pointer switch (info.type) { // 8/16-bit integers // char / wchar_t (promoted to int) case 'c': char c = (char)Marshal.ReadByte(args, offset); objects.Add(c); offset += Marshal.SizeOf(typeof(Int32)); break; // signed integers case 'd': case 'i': { if (info.flags.HasFlag(Printf.FormatFlags.IsShort)) // h { short sh = (short)Marshal.ReadInt32(args, offset); objects.Add(sh); offset += Marshal.SizeOf(typeof(Int32)); } else if (info.flags.HasFlag(Printf.FormatFlags.IsLongLong)) // ll { long l = Marshal.ReadInt64(args, offset); objects.Add(l); offset += iSize; } else // int and long types { int i = Marshal.ReadInt32(args, offset); objects.Add(i); offset += iSize; } } break; // unsigned integers case 'u': case 'o': case 'x': case 'X': { if (info.flags.HasFlag(Printf.FormatFlags.IsShort)) // h { ushort su = (ushort)Marshal.ReadInt32(args, offset); objects.Add(su); offset += Marshal.SizeOf(typeof(Int32)); } else if (info.flags.HasFlag(Printf.FormatFlags.IsLongLong)) // ll { ulong lu = (ulong)(long)Marshal.ReadInt64(args, offset); objects.Add(lu); offset += iSize; } else // uint and ulong types { uint u = (uint)Marshal.ReadInt32(args, offset); objects.Add(u); offset += iSize; } } break; // floating-point types case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': { if (info.flags.HasFlag(Printf.FormatFlags.IsLongDouble)) // L { // not really supported but read it as long long lfi = Marshal.ReadInt64(args, offset); double d = *(double*)(void*)&lfi; objects.Add(d); offset += Marshal.SizeOf(typeof(double)); } else // double { long lfi = Marshal.ReadInt64(args, offset); double d = *(double*)(void*)&lfi; objects.Add(d); offset += Marshal.SizeOf(typeof(double)); } } break; // string case 's': { string s = null; if (info.flags.HasFlag(Printf.FormatFlags.IsLong)) s = Marshal.PtrToStringUni(Marshal.ReadIntPtr(args, offset)); else s = Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(args, offset)); objects.Add(s); offset += Marshal.SizeOf(typeof(IntPtr)); } break; // pointer case 'p': IntPtr ptr = Marshal.ReadIntPtr(args, offset); objects.Add(ptr); offset += Marshal.SizeOf(typeof(IntPtr)); break; // non-marshallable types, ignored case ' ': case '%': case 'n': break; default: throw new ApplicationException("printf specifier '%" + info.type + "' not supported"); } } return objects.ToArray(); }
/// <summary> Wraps, parses and formats the variable arguments of the real delegate. </summary> private static void LogHandlerWrapper(libobs.log_error_level lvl, string format, IntPtr args, IntPtr p) { using (va_list arglist = new va_list(args)) { object[] objs = arglist.GetObjectsByFormat(format); string formattedMsg = Printf.sprintf(format, objs); realHandler((LogErrorLevel)lvl, formattedMsg, p); } }
/// <summary> /// Returns array of objects read from va_list with help of printf format string. /// </summary> /// <param name="msg"> printf format string. </param> /// <param name="args"> va_list of function parameters. </param> public static unsafe object[] GetObjectsByFormat(string format, va_list va_list) { string[] formatSpecifiers = Printf.GetFormatSpecifiers(format); if (formatSpecifiers == null || va_list == null || va_list.GetPointer() == IntPtr.Zero) { return(null); } IntPtr args = va_list.GetPointer(); List <object> objects = new List <object>(formatSpecifiers.Length); int offset = 0; foreach (string spec in formatSpecifiers) { var info = Printf.GetFormatSpecifierInfo(spec); if (info.type == '\0') { continue; } // dynamic width and precision arguments // these are stored in stack before the actual value if (info.flags.HasFlag(Printf.FormatFlags.DynamicWidth)) { int widthArg = Marshal.ReadInt32(args, offset); objects.Add(widthArg); offset += Marshal.SizeOf(typeof(IntPtr)); } if (info.flags.HasFlag(Printf.FormatFlags.DynamicPrecision)) { int precArg = Marshal.ReadInt32(args, offset); objects.Add(precArg); offset += Marshal.SizeOf(typeof(IntPtr)); } int iSize = info.flags.HasFlag(Printf.FormatFlags.IsLongLong) ? Marshal.SizeOf(typeof(Int64)) : Marshal.SizeOf(typeof(IntPtr)); // marshal objects from pointer switch (info.type) { // 8/16-bit integers // char / wchar_t (promoted to int) case 'c': char c = (char)Marshal.ReadByte(args, offset); objects.Add(c); offset += Marshal.SizeOf(typeof(Int32)); break; // signed integers case 'd': case 'i': { if (info.flags.HasFlag(Printf.FormatFlags.IsShort)) // h { short sh = (short)Marshal.ReadInt32(args, offset); objects.Add(sh); offset += Marshal.SizeOf(typeof(Int32)); } else if (info.flags.HasFlag(Printf.FormatFlags.IsLongLong)) // ll { long l = Marshal.ReadInt64(args, offset); objects.Add(l); offset += iSize; } else // int and long types { int i = Marshal.ReadInt32(args, offset); objects.Add(i); offset += iSize; } } break; // unsigned integers case 'u': case 'o': case 'x': case 'X': { if (info.flags.HasFlag(Printf.FormatFlags.IsShort)) // h { ushort su = (ushort)Marshal.ReadInt32(args, offset); objects.Add(su); offset += Marshal.SizeOf(typeof(Int32)); } else if (info.flags.HasFlag(Printf.FormatFlags.IsLongLong)) // ll { ulong lu = (ulong)(long)Marshal.ReadInt64(args, offset); objects.Add(lu); offset += iSize; } else // uint and ulong types { uint u = (uint)Marshal.ReadInt32(args, offset); objects.Add(u); offset += iSize; } } break; // floating-point types case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': { if (info.flags.HasFlag(Printf.FormatFlags.IsLongDouble)) // L { // not really supported but read it as long long lfi = Marshal.ReadInt64(args, offset); double d = *(double *)(void *)&lfi; objects.Add(d); offset += Marshal.SizeOf(typeof(double)); } else // double { long lfi = Marshal.ReadInt64(args, offset); double d = *(double *)(void *)&lfi; objects.Add(d); offset += Marshal.SizeOf(typeof(double)); } } break; // string case 's': { string s = null; if (info.flags.HasFlag(Printf.FormatFlags.IsLong)) { s = Marshal.PtrToStringUni(Marshal.ReadIntPtr(args, offset)); } else { s = Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(args, offset)); } objects.Add(s); offset += Marshal.SizeOf(typeof(IntPtr)); } break; // pointer case 'p': IntPtr ptr = Marshal.ReadIntPtr(args, offset); objects.Add(ptr); offset += Marshal.SizeOf(typeof(IntPtr)); break; // non-marshallable types, ignored case ' ': case '%': case 'n': break; default: throw new ApplicationException("printf specifier '%" + info.type + "' not supported"); } } return(objects.ToArray()); }