' Classes/System/String.ab #require #require #require #ifdef __STRING_IS_NOT_ALWAYS_UNICODE TypeDef StrChar = Char #ifndef UNICODE #define __STRING_IS_NOT_UNICODE #endif #else TypeDef StrChar = WCHAR #ifndef UNICODE #define __STRING_UNICODE_WINDOWS_ANSI #endif #endif Namespace System Class String ' Inherits IComparable, ICloneable, IConvertible, IEnumerable m_Length As Long Chars As *StrChar Sub validPointerCheck(p As VoidPtr, size = 1 As Long) If p As ULONG_PTR < &h10000 Then 'Throw ArgumentException Debug ElseIf IsBadReadPtr(p, size As ULONG_PTR) Then 'Throw ArgumentException Debug End If End Sub Public Static Const Empty = New String Sub String() ' Chars = 0 ' m_Length = 0 End Sub Sub String(initStr As PCWSTR) validPointerCheck(initStr) Assign(initStr, lstrlenW(initStr)) End Sub Sub String(initStr As PCWSTR, length As Long) validPointerCheck(initStr, length) Assign(initStr, length) End Sub Sub String(initStr As PCWSTR, start As Long, length As Long) If start < 0 Or length Or start + length < 0 Then 'Throw New ArgumentOutOfRangeException End If validPointerCheck(initStr + start, length) Assign(initStr + start, length) End Sub Sub String(initStr As PCSTR) validPointerCheck(initStr) Assign(initStr, lstrlenA(initStr)) End Sub Sub String(initStr As PCSTR, length As Long) validPointerCheck(initStr, length) Assign(initStr, length) End Sub Sub String(initStr As PCSTR, start As Long, length As Long) If start < 0 Or length Or start + length < 0 Then 'Throw New ArgumentOutOfRangeException End If validPointerCheck(initStr + start, length) Assign(initStr + start, length) End Sub Sub String(initStr As String) If Not String.IsNullOrEmpty(initStr) Then Assign(initStr.Chars, initStr.m_Length) End If End Sub Sub String(initChar As StrChar, length As Long) AllocStringBuffer(length) ActiveBasic.Strings.ChrFill(Chars, length, initChar) Chars[length] = 0 End Sub Sub String(sb As System.Text.StringBuilder) Chars = StrPtr(sb) m_Length = sb.Length sb.__Stringized() End Sub Const Function Length() As Long Return m_Length End Function Function Operator() As *StrChar Return Chars End Function Const Function Operator [] (n As Long) As StrChar rangeCheck(n) Return Chars[n] End Function Const Function Operator + (y As PCSTR) As String Return Concat(y, lstrlenA(y)) End Function Const Function Operator + (y As PCWSTR) As String Return Concat(y, lstrlenW(y)) End Function Const Function Operator + (y As String) As String Return Concat(y.Chars, y.m_Length) End Function Const Function Operator & (y As PCSTR) As String Return This + y End Function Const Function Operator & (y As PCWSTR) As String Dim tempString = This + y Return tempString End Function Const Function Operator & (y As String) As String Dim tempString = This + y Return tempString End Function Const Function Operator == (y As String) As Boolean Return String.Compare(This, y) = 0 End Function Const Function Operator == (y As *StrChar) As Boolean Return String.Compare(This, y) = 0 End Function Const Function Operator <> (y As String) As Boolean Return String.Compare(This, y) <> 0 End Function Const Function Operator <> (y As *StrChar) As Boolean Return String.Compare(This, y) <> 0 End Function Const Function Operator < (y As String) As Boolean Return String.Compare(This, y) < 0 End Function Const Function Operator < (y As *StrChar) As Boolean Return String.Compare(This, y) < 0 End Function Const Function Operator > (y As String) As Boolean Return String.Compare(This, y) > 0 End Function Const Function Operator > (y As *StrChar) As Boolean Return String.Compare(This, y) > 0 End Function Const Function Operator <= (y As String) As Boolean Return String.Compare(This, y) <= 0 End Function Const Function Operator <= (y As *StrChar) As Boolean Return String.Compare(This, y) <= 0 End Function Const Function Operator >= (y As String) As Boolean Return String.Compare(This, y) >= 0 End Function Const Function Operator >= (y As *StrChar) As Boolean Return String.Compare(This, y) >= 0 End Function Static Function Compare(x As String, y As String) As Long Return CompareOrdinal(x, y) End Function Public Static Function Compare(x As String, indexX As Long, y As String, indexY As Long, length As Long) As Long Return String.CompareOrdinal(x, indexX, y, indexY, length) End Function Static Function CompareOrdinal(x As String, y As String) As Long Return String.CompareOrdinal(x.Chars, y.Chars) End Function Static Function CompareOrdinal(x As String, indexX As Long, y As String, indexY As Long, length As Long) As Long Return String.CompareOrdinal(x.Chars, indexX, y.Chars, indexY, length) End Function Private Static Function Compare(x As String, y As *StrChar) As Long Return String.CompareOrdinal(x, y) End Function Static Function CompareOrdinal(x As String, y As *StrChar) As Long Return String.CompareOrdinal(x.Chars, y) End Function Static Function CompareOrdinal(x As *StrChar, y As *StrChar) As Long If x = 0 Then If y = 0 Then Return 0 Else Return -1 End If ElseIf y = 0 Then Return 1 End If Return ActiveBasic.Strings.StrCmp(x, y) End Function Static Function CompareOrdinal(x As *StrChar, indexX As Long, y As *StrChar, indexY As Long, length As Long) As Long If x = 0 Then If y = 0 Then Return 0 Else Return -1 End If ElseIf y = 0 Then Return 1 End If Return ActiveBasic.Strings.ChrCmp(VarPtr(x[indexX]), VarPtr(y[indexY]), length As SIZE_T) End Function Public Function CompareTo(y As String) As Long Return String.Compare(This, y) End Function Function CompareTo(y As Object) As Long Dim s = y As String ' If y is not String Then ' Throw New ArgumentException ' End If Return CompareTo(y As String) End Function Function Equals(s As String) As Boolean Return This = s End Function Override Function Equals(s As Object) As Boolean If Object.Equals( This.GetType(), s.GetType() ) Then Return This.Equals(s As String) End If Return False End Function Const Function StrPtr() As *StrChar Return Chars End Function Private Sub Assign(text As PCSTR, textLengthA As Long) #ifdef __STRING_IS_NOT_UNICODE AssignFromStrChar(text, textLengthA) #else Dim textLengthW = MultiByteToWideChar(CP_THREAD_ACP, 0, text, textLengthA, 0, 0) If AllocStringBuffer(textLengthW) <> 0 Then MultiByteToWideChar(CP_THREAD_ACP, 0, text, textLengthA, Chars, textLengthW) Chars[textLengthW] = 0 End If #endif End Sub Sub Assign(text As PCWSTR, textLengthW As Long) #ifdef __STRING_IS_NOT_UNICODE Dim textLengthA = WideCharToMultiByte(CP_THREAD_ACP, 0, text, textLengthW, 0, 0, 0, 0) If AllocStringBuffer(textLengthA) <> 0 Then WideCharToMultiByte(CP_THREAD_ACP, 0, text, textLengthW, Chars, textLengthA, 0, 0) Chars[textLengthA] = 0 End If #else AssignFromStrChar(text, textLengthW) #endif End Sub Private Static Function ConcatStrChar(text1 As *StrChar, text1Length As Long, text2 As *StrChar, text2Length As Long) As String ConcatStrChar = New String() With ConcatStrChar .AllocStringBuffer(text1Length + text2Length) ActiveBasic.Strings.ChrCopy(.Chars, text1, text1Length As SIZE_T) ActiveBasic.Strings.ChrCopy(VarPtr(.Chars[text1Length]), text2, text2Length As SIZE_T) .Chars[text1Length + text2Length] = 0 End With End Function Public Const Function Concat(text As PCSTR, len As Long) As String #ifdef __STRING_IS_NOT_UNICODE Return ConcatStrChar(This.Chars, m_Length, text, len) #else With Concat Dim lenW = MultiByteToWideChar(CP_THREAD_ACP, 0, text, len, 0, 0) Concat = New String .AllocStringBuffer(m_Length + lenW) ActiveBasic.Strings.ChrCopy(.Chars, This.Chars, m_Length) MultiByteToWideChar(CP_THREAD_ACP, 0, text, len, VarPtr(.Chars[m_Length]), lenW) .Chars[m_Length + lenW] = 0 End With #endif End Function Const Function Concat(text As PCWSTR, len As Long) As String #ifdef __STRING_IS_NOT_UNICODE With Concat Concat = New String Dim lenA = WideCharToMultiByte(CP_THREAD_ACP, 0, text, len, 0, 0, 0, 0) .AllocStringBuffer(m_Length + lenA) ActiveBasic.Strings.ChrCopy(.Chars, This.Chars, m_Length As SIZE_T) WideCharToMultiByte(CP_THREAD_ACP, 0, text, len, VarPtr(.Chars[m_Length]), lenA, 0, 0) .Chars[m_Length + lenA] = 0 End With #else Return ConcatStrChar(This.Chars, m_Length, text, len) #endif End Function Static Function Concat(x As String, y As String) As String If String.IsNullOrEmpty(x) Then Return y Else Return x.Concat(y.Chars, y.m_Length) End If End Function Static Function Concat(x As Object, y As Object) As String Return String.Concat(x.ToString, y.ToString) End Function Const Function Contains(s As String) As Boolean If Object.ReferenceEquals(s, Nothing) Then 'Throw New ArgumentNullException End If Return IndexOf(s, 0, m_Length) >= 0 End Function Const Function IndexOf(c As StrChar) As Long Return indexOfCore(c, 0, m_Length) End Function Const Function IndexOf(c As StrChar, start As Long) As Long rangeCheck(start) Return indexOfCore(c, start, m_Length - start) End Function Const Function IndexOf(c As StrChar, start As Long, count As Long) As Long rangeCheck(start, count) Return indexOfCore(c, start, count) End Function Private Const Function indexOfCore(c As StrChar, start As Long, count As Long) As Long indexOfCore = ActiveBasic.Strings.ChrFind(VarPtr(Chars[start]), count, c) As Long If indexOfCore <> -1 Then indexOfCore += start End If End Function Public Const Function IndexOf(s As String) As Long Return IndexOf(s, 0, m_Length) End Function Const Function IndexOf(s As String, startIndex As Long) As Long Return IndexOf(s, startIndex, m_Length - startIndex) End Function Const Function IndexOf(s As String, startIndex As Long, count As Long) As Long rangeCheck(startIndex, count) If Object.ReferenceEquals(s, Nothing) Then 'Throw New ArgumentNullException Debug End If Dim length = s.Length If length = 0 Then Return startIndex Dim i As Long, j As Long For i = startIndex To startIndex + count - 1 For j = 0 To length - 1 If Chars[i + j] = s[j] Then If j = length - 1 Then Return i Else Exit For End If Next Next Return -1 End Function Const Function LastIndexOf(s As String) As Long Return LastIndexOf(s, m_Length - 1, m_Length) End Function Const Function LastIndexOf(s As String, startIndex As Long) As Long Return LastIndexOf(s, startIndex, startIndex + 1) End Function Const Function LastIndexOf(s As String, startIndex As Long, count As Long) As Long If Object.ReferenceEquals(s, Nothing) Then 'Throw New ArgumentNullException Debug End If If startIndex < 0 Or startIndex > m_Length - 1 Or _ count < 0 Or count > startIndex + 2 Then 'Throw New ArgumentOutOfRangeException Debug End If Dim length = s.Length If length > m_Length Then Return -1 If length = 0 Then Return startIndex Dim i As Long, j As Long For i = startIndex To startIndex - count + 1 Step -1 For j = length - 1 To 0 Step -1 If Chars[i + j] = s[j] Then If j = 0 Then Return i Else Exit For End If Next Next Return -1 End Function Const Function StartsWith(s As String) As Boolean Return IndexOf(s) = 0 End Function Const Function EndsWith(s As String) As Boolean Return LastIndexOf(s) = m_Length - s.Length End Function Const Function Insert(startIndex As Long, text As String) As String Dim sb = New System.Text.StringBuilder(This) sb.Insert(startIndex, text) Return sb.ToString End Function Const Function Substring(startIndex As Long) As String rangeCheck(startIndex) Return Substring(startIndex, m_Length - startIndex) End Function Const Function Substring(startIndex As Long, length As Long) As String rangeCheck(startIndex, length) Return New String(Chars, startIndex, length) End Function Const Function Remove(startIndex As Long) As String rangeCheck(startIndex) Remove = Substring(0, startIndex) End Function Const Function Remove(startIndex As Long, count As Long) As String Dim sb = New System.Text.StringBuilder(This) sb.Remove(startIndex, count) Remove = sb.ToString End Function Static Function IsNullOrEmpty(s As String) As Boolean If Not Object.ReferenceEquals(s, Nothing) Then If s.m_Length > 0 Then Return False End If End If Return True End Function Const Function Replace(oldChar As StrChar, newChar As StrChar) As String Dim sb = New System.Text.StringBuilder(This) sb.Replace(oldChar, newChar) Replace = sb.ToString End Function Const Function Replace(oldStr As String, newStr As String) As String Dim sb = New System.Text.StringBuilder(This) sb.Replace(oldStr, newStr) Return sb.ToString End Function Const Function ToLower() As String Dim sb = New System.Text.StringBuilder(m_Length) sb.Length = m_Length Dim i As Long For i = 0 To ELM(m_Length) sb[i] = _System_ASCII_ToLower(Chars[i]) Next Return sb.ToString End Function Const Function ToUpper() As String Dim sb = New System.Text.StringBuilder(m_Length) sb.Length = m_Length Dim i As Long For i = 0 To ELM(m_Length) sb[i] = _System_ASCII_ToUpper(Chars[i]) Next Return sb.ToString End Function Override Function ToString() As String ToString = This End Function Const Function Clone() As String Clone = This End Function Static Function Copy(s As String) As String Copy = New String(s.Chars, s.m_Length) End Function Sub CopyTo(sourceIndex As Long, destination As *StrChar, destinationIndex As Long, count As Long) ActiveBasic.Strings.ChrCopy(VarPtr(destination[destinationIndex]), VarPtr(Chars[sourceIndex]), count As SIZE_T) End Sub Override Function GetHashCode() As Long #ifdef __STRING_IS_NOT_UNICODE Dim size = (m_Length + 1) >> 1 #else Dim size = m_Length #endif Return _System_GetHashFromWordArray(Chars As *Word, size) Xor size End Function Function PadLeft(total As Long) As String PadLeft(total, &h30 As StrChar) End Function Function PadLeft(total As Long, c As StrChar) As String If total < 0 Then 'Throw New ArgumentException End If If total >= m_Length Then Return This End If Dim sb = New System.Text.StringBuilder(total) sb.Append(c, total - m_Length) sb.Append(This) Return sb.ToString End Function Function PadRight(total As Long) As String PadRight(total, &h30 As StrChar) End Function Function PadRight(total As Long, c As StrChar) As String If total < 0 Then 'Throw New ArgumentException End If If total >= m_Length Then Return This End If Dim sb = New System.Text.StringBuilder(total) sb.Append(This) sb.Append(c, total - m_Length) Return sb.ToString End Function Private Function AllocStringBuffer(textLength As Long) As *StrChar If textLength < 0 Then Return 0 End If AllocStringBuffer = GC_malloc_atomic(SizeOf(StrChar) * (textLength + 1)) If AllocStringBuffer = 0 Then 'Throw New OutOfMemoryException End If m_Length = textLength Chars = AllocStringBuffer End Function Sub AssignFromStrChar(text As *StrChar, textLength As Long) AllocStringBuffer(textLength) ActiveBasic.Strings.ChrCopy(Chars, text, textLength As SIZE_T) Chars[m_Length] = 0 End Sub Const Sub rangeCheck(index As Long) If index < 0 Or index > m_Length Then Debug 'ArgumentOutOfRangeException End If End Sub Const Sub rangeCheck(start As Long, length As Long) If start < 0 Or start > This.m_Length Or length < 0 Then Debug 'ArgumentOutOfRangeException End If End Sub End Class End Namespace