using System; using System.Text; namespace Raylib_cs; #region LICENSE // ** -- TAKEN FROM SQLitePCL.raw -- ** \\ /* https://github.com/ericsink/SQLitePCL.raw */ /* Copyright 2014-2021 SourceGear, LLC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ // CHANGES: // - Update Method Names // - Implicit Conversion From string #endregion /// /// A raw string representation suitable for passing into many core SQLite apis. These will normally be pointers to /// utf8 encoded bytes, with a trailing \0 terminator. strings can be represented as /// well as empty strings. /// public readonly ref struct Utf8String { // this span will contain a zero terminator byte // if sp.Length is 0, it represents a null string // if sp.Length is 1, the only byte must be zero, and it is an empty string readonly ReadOnlySpan sp; public ref readonly byte GetPinnableReference() { return ref sp.GetPinnableReference(); } private Utf8String(ReadOnlySpan a) { // no check here. anything that calls this // constructor must make assurances about the // zero terminator. sp = a; } /// /// Creates a new instance of which directly points at the memory pointed to by . The span must contain a valid encoded block of memory that /// terminates with a \0 byte. The span passed in must include the \0 terminator. /// /// Both and empty strings can be created here. To create a string, /// pass in an empty . To create an empty string, pass in a span with length 1, that /// only contains a \0 /// /// /// Thrown if span.Length > 0 and span[^1] is not \0. /// public static Utf8String FromSpan(ReadOnlySpan span) { if ( (span.Length > 0) && (span[^1] != 0) ) { throw new ArgumentException("zero terminator required"); } return new Utf8String(span); } public static Utf8String FromString(string s) { if (s == null) { return new Utf8String(ReadOnlySpan.Empty); } else { return new Utf8String(s.ToUtf8String()); } } static unsafe long GetLength(byte* p) { var q = p; while (*q != 0) { q++; } return q - p; } static unsafe ReadOnlySpan FindZeroTerminator(byte* p) { var len = (int)GetLength(p); return new ReadOnlySpan(p, len + 1); } /// /// Creates a new instance of which directly points at the memory pointed to by . The pointer must either be or point to a valid encoded block of memory that terminates with a \0 byte. /// public static unsafe Utf8String FromPtr(byte* p) { if (p == null) { return new Utf8String(ReadOnlySpan.Empty); } else { return new Utf8String(FindZeroTerminator(p)); } } // TODO maybe remove this and just use FromSpan? /// /// Creates a new instance of which directly points at the memory pointed to by with length . The pointer must be to a valid /// encoded block of memory that terminates with a \0 byte. The value refers to /// the number of bytes in the utf8 encoded value not including the \0 byte terminator. /// /// can be , in which case is ignored /// and a new instance is created that represents . Note that this /// different from a pointer to a single \0 byte and a length of one. That would represent an empty string. /// /// /// Thrown if is not and p[len] is not \0. /// public static unsafe Utf8String FromPtrLen(byte* p, int len) { if (p == null) { return new Utf8String(ReadOnlySpan.Empty); } else { // the given len does NOT include the zero terminator var sp = new ReadOnlySpan(p, len + 1); return FromSpan(sp); } } public static unsafe Utf8String FromIntPtr(IntPtr p) { if (p == IntPtr.Zero) { return new Utf8String(ReadOnlySpan.Empty); } else { return new Utf8String(FindZeroTerminator((byte*)(p.ToPointer()))); } } public override string ToString() { if (sp.Length == 0) { return "NUL"; } unsafe { fixed (byte* q = sp) { return Encoding.UTF8.GetString(q, sp.Length - 1); } } } /// /// Gets the encoded bytes for the provided . The array /// will include a trailing \0 character. The length of the array will 's /// +1 (for the trailing \0 byte). These bytes are /// suitable to use with using the extension or or . Note that for the length provided should not include the /// trailing \0 terminator. /// public static byte[] GetZeroTerminatedUTF8Bytes(string value) { return value.ToUtf8String(); } public static implicit operator Utf8String(string s) { return FromString(s); } } public static class Utf8StringUtils { public static byte[] ToUtf8String(this string sourceText) { if (sourceText == null) { return null; } var length = Encoding.UTF8.GetByteCount(sourceText); var byteArray = new byte[length + 1]; var wrote = Encoding.UTF8.GetBytes(sourceText, 0, sourceText.Length, byteArray, 0); byteArray[wrote] = 0; return byteArray; } }