/// <summary> /// Decompresses data. Uses <see cref="BrotliDecoder"/>. /// </summary> /// <returns>Decompressed data.</returns> /// <param name="compressed">Compressed data.</param> /// <exception cref="ArgumentException">Invalid data.</exception> /// <exception cref="OutOfMemoryException"></exception> public static unsafe byte[] BrotliDecompress(ReadOnlySpan <byte> compressed) { int n = checked (compressed.Length * 4 + 8000); for (int i = 0; i < 3; i++) { if (n < 512_000) { n *= 2; } } //print.it(compressed.Length, n, n/compressed.Length); //usually ~ 80 KB for (; ; n = checked (n * 2)) { byte *b = null; try { b = MemoryUtil.Alloc(n); if (BrotliDecoder.TryDecompress(compressed, new(b, n), out int nw)) { return(new Span <byte>(b, nw).ToArray()); } if (nw == 0) { throw new ArgumentException("cannot decompress this data"); } //print.it(n); } finally { MemoryUtil.Free(b); } } }
string _exe; //for errors only /// <summary> /// Prepares parameters for API <msdn>CreateProcess</msdn> and similar. /// </summary> /// <param name="exe"> /// Full path of program file. If not full path, uses <see cref="folders.ThisApp"/>. Uses <see cref="pathname.normalize"/>. /// If <i>rawExe</i> true, does not use <b>Normalize</b>/<b>ThisApp</b>. /// </param> /// <param name="args">null or command line arguments.</param> /// <param name="curDir"> /// Initial current directory of the new process. /// - If null, uses <c>Directory.GetCurrentDirectory()</c>. /// - Else if <i>rawCurDir</i>==true, uses raw <i>curDir</i> value. /// - Else if "", calls <c>pathname.getDirectory(exe)</c>. /// - Else calls <see cref="pathname.expand"/>. /// </param> /// <param name="envVar">null or environment variables to pass to the new process together with variables of this process. Format: "var1=value1\0var2=value2\0". If ends with "\0\0", will pass only these variables.</param> /// <param name="rawExe">Don't normalize <i>exe</i>.</param> /// <param name="rawCurDir">Don't normalize <i>curDir</i>.</param> public ProcessStarter_(string exe, string args = null, string curDir = null, string envVar = null, bool rawExe = false, bool rawCurDir = false) : this() { if (!rawExe) { exe = pathname.normalize(exe, folders.ThisApp, PNFlags.DontExpandDosPath | PNFlags.DontPrefixLongPath); } _exe = exe; cl = (args == null ? ("\"" + exe + "\"" + "\0") : ("\"" + exe + "\" " + args + "\0")).ToCharArray(); if (curDir == null) { this.curDir = Directory.GetCurrentDirectory(); //if null passed to CreateProcessWithTokenW, the new process does not inherit current directory of this process } else { this.curDir = rawCurDir ? curDir : (curDir.Length == 0 ? pathname.getDirectory(exe) : pathname.expand(curDir)); } si.cb = Api.SizeOf <Api.STARTUPINFO>(); si.dwFlags = Api.STARTF_FORCEOFFFEEDBACK; flags = Api.CREATE_UNICODE_ENVIRONMENT; if (envVar != null && !envVar.Ends("\0\0")) { var es = Api.GetEnvironmentStrings(); int len1; for (var k = es; ; k++) { if (k[0] == 0 && k[1] == 0) { len1 = (int)(k - es) + 2; break; } } int len2 = envVar.Length; var t = new string('\0', len1 + len2); fixed(char *p = t) { MemoryUtil.Copy(es, p, --len1 * 2); for (int i = 0; i < envVar.Length; i++) { p[len1 + i] = envVar[i]; } } this.envVar = t; Api.FreeEnvironmentStrings(es); } else { this.envVar = null; } }
/// <summary> /// Compresses data. Uses <see cref="BrotliEncoder"/>. /// </summary> /// <param name="data">Data. See also: <see cref="MemoryMarshal.AsBytes"/>, <see cref="CollectionsMarshal.AsSpan"/>.</param> /// <param name="level">Compression level, 0 (no compression) to 11 (maximal compression). Default 6. Bigger levels don't make much smaller but can make much slower.</param> /// <exception cref="ArgumentOutOfRangeException">Invalid <i>level</i>.</exception> /// <exception cref="OutOfMemoryException"></exception> public static unsafe byte[] BrotliCompress(ReadOnlySpan <byte> data, int level = 6) { int n = BrotliEncoder.GetMaxCompressedLength(data.Length); var b = MemoryUtil.Alloc(n); try { if (!BrotliEncoder.TryCompress(data, new(b, n), out n, level, 22)) { throw new AuException(); } return(new Span <byte>(b, n).ToArray()); } finally { MemoryUtil.Free(b); } }