source: Include/Classes/System/String.ab@ 221

Last change on this file since 221 was 221, checked in by dai, 17 years ago

Stringクラスのコンストラクタに0バイトのChar配列を引き渡すとString.Charsへのメモリ確保が行われないバグを修正。
SimpleTestCaseプロジェクトをアップロード

File size: 17.3 KB
RevLine 
[132]1' Classes/System/String.ab
2
3#require <basic/function.sbp>
4
[139]5#ifdef __STRING_IS_NOT_ALWAYS_UNICODE
6TypeDef StrChar = Char
7#ifndef UNICODE
8#define __STRING_IS_NOT_UNICODE
9#endif
10#else
11TypeDef StrChar = WCHAR
[142]12#ifndef UNICODE
13#define __STRING_UNICODE_WINDOWS_ANSI
[139]14#endif
[142]15#endif
[139]16
[1]17Class String
[203]18' Inherits IComparable, ICloneable, IConvertible, IEnumerable
19
[30]20 m_Length As Long
[1]21Public
[139]22 Chars As *StrChar
[1]23
24 Sub String()
[203]25 Chars = _System_malloc(SizeOf (StrChar))
[193]26 Chars[0] = 0
[30]27 m_Length = 0
[1]28 End Sub
29
[139]30 Sub String(initStr As PCSTR)
[1]31 Assign(initStr)
32 End Sub
[30]33
[139]34 Sub String(initStr As PCSTR, length As Long)
[125]35 Assign(initStr, length)
36 End Sub
37
[139]38 Sub String(initStr As PCWSTR)
39 Assign(initStr)
40 End Sub
41
42 Sub String(initStr As PCWSTR, length As Long)
43 Assign(initStr, length)
44 End Sub
45
[49]46 Sub String(ByRef initStr As String)
[1]47 Assign(initStr)
48 End Sub
[49]49
[1]50 Sub String(length As Long)
51 ReSize(length)
52 End Sub
[121]53
[139]54 Sub String(initChar As StrChar, length As Long)
[1]55 ReSize(length, initChar)
56 End Sub
57
58 Sub ~String()
[123]59 _System_free(Chars)
[31]60 Chars = 0
[1]61#ifdef _DEBUG
[30]62 m_Length = 0
[1]63#endif
64 End Sub
65
[121]66 Const Function Length() As Long
[30]67 Return m_Length
68 End Function
69
[139]70 Function Operator() As *StrChar
[31]71 Return Chars
[1]72 End Function
73
[183]74/* Sub Operator = (ByRef objString As String)
[31]75 Assign(objString.Chars, objString.m_Length)
[1]76 End Sub
77
[139]78 Sub Operator = (text As *Byte)
79 Assign(text As PCTSTR)
80 End Sub
81
82 Sub Operator = (text As PCSTR)
[1]83 Assign(text)
84 End Sub
85
[139]86 Sub Operator = (text As PCWSTR)
87 Assign(text)
[183]88 End Sub*/
[139]89
90 Const Function Operator [] (n As Long) As StrChar
91#ifdef _DEBUG
92 If n > Length Then
93 'Throw ArgumentOutOfRangeException
94 Debug
95 End If
96#endif
[31]97 Return Chars[n]
[1]98 End Function
99
[139]100 Sub Operator []= (n As Long, c As StrChar)
101#ifdef _DEBUG
102 If n >= Length Then
103 'Throw ArgumentOutOfRangeException
104 Debug
105 End If
106#endif
[31]107 Chars[n] = c
[1]108 End Sub
109
[183]110/* Const Function Operator + (text As *Byte) As String
[139]111 Return Concat(text As PCTSTR, lstrlen(text))
[183]112 End Function*/
[1]113
[139]114 Const Function Operator + (text As PCSTR) As String
115 Return Concat(text, lstrlenA(text))
116 End Function
117
118 Const Function Operator + (text As PCWSTR) As String
119 Return Concat(text, lstrlenW(text))
120 End Function
121
[203]122 Const Function Operator + (objString As String) As String
[139]123 Return Concat(objString.Chars, objString.m_Length)
[1]124 End Function
125
[139]126 Const Function Operator & (text As PCSTR) As String
127 Dim tempString = This + text
[1]128 Return tempString
129 End Function
130
[139]131 Const Function Operator & (text As PCWSTR) As String
132 Dim tempString = This + text
133 Return tempString
134 End Function
135
[203]136 Const Function Operator & (objString As String) As String
[121]137 Dim tempString = This + objString
[1]138 Return tempString
139 End Function
140
[203]141 Const Function Operator == (objString As String) As Boolean
142 Return String.Compare(This, objString) = 0
[1]143 End Function
144
[139]145 Const Function Operator == (text As *StrChar) As Long
[182]146 Return _System_StrCmp(This.Chars, text) = 0
[1]147 End Function
148
[203]149 Const Function Operator <> (objString As String) As Boolean
150 Return String.Compare(This, objString) <> 0
[1]151 End Function
152
[139]153 Const Function Operator <> (text As *StrChar) As Boolean
[182]154 Return _System_StrCmp(This.Chars, text) <> 0
[1]155 End Function
156
[203]157 Const Function Operator < (objString As String) As Boolean
158 Return String.Compare(This, objString) < 0
[1]159 End Function
160
[139]161 Const Function Operator < (text As *StrChar) As Boolean
[182]162 Return _System_StrCmp(This.Chars, text) < 0
[1]163 End Function
164
[203]165 Const Function Operator > (objString As String) As Boolean
166 Return String.Compare(This, objString) > 0
[1]167 End Function
168
[139]169 Const Function Operator > (text As *StrChar) As Boolean
[182]170 Return _System_StrCmp(This.Chars, text) > 0
[1]171 End Function
172
[203]173 Const Function Operator <= (objString As String) As Boolean
174 Return String.Compare(This, objString) <= 0
[1]175 End Function
176
[139]177 Const Function Operator <= (text As *StrChar) As Boolean
[182]178 Return _System_StrCmp(This.Chars, text) <= 0
[1]179 End Function
180
[203]181 Const Function Operator >= (objString As String) As Boolean
182 Return String.Compare(This, objString) >= 0
[1]183 End Function
184
[139]185 Const Function Operator >= (text As *StrChar) As Boolean
[182]186 Return _System_StrCmp(This.Chars, text) >= 0
[1]187 End Function
188
[203]189 Static Function Compare(x As String, y As String) As Long
190 Return CompareOrdinal(x, y)
191 End Function
192
193 Static Function Compare(x As String, indexX As Long, y As String, indexY As Long, length As Long) As Long
194 Return CompareOrdinal(x, indexX, y, indexY, length)
195 End Function
196
197 Static Function CompareOrdinal(x As String, y As String) As Long
198 Return _System_StrCmp(x.Chars, y.Chars)
199 End Function
200
201 Static Function CompareOrdinal(x As String, indexX As Long, y As String, indexY As Long, length As Long) As Long
202 If x = Nothing Then
203 If y = Nothing Then
204 Return 0
205 Else
206 Return -1
207 End If
208 ElseIf y = Nothing Then
209 Return 1
210 End If
211 Return _System_StrCmpN(VarPtr(x.Chars[indexX]), VarPtr(y.Chars[indexY]), length)
212 End Function
213
214 Function CompareTo(y As String) As Long
215 Return String.Compare(This, y)
216 End Function
217
218 Function CompareTo(y As Object) As Long
219 Dim s = y As String
220' If y is not String Then
221' Throw New ArgumentException
222' End If
223 Return CompareTo(y)
224 End Function
225
[139]226 Const Function StrPtr() As *StrChar
[31]227 Return Chars
[1]228 End Function
229
230 Sub ReSize(allocLength As Long)
231 If allocLength < 0 Then Exit Sub
[30]232 If allocLength > m_Length Then
[1]233 Dim oldLength As Long
[30]234 oldLength = m_Length
[1]235 If AllocStringBuffer(allocLength) <> 0 Then
[139]236 ZeroMemory(VarPtr(Chars[oldLength]), SizeOf (StrChar) * (m_Length - oldLength + 1))
[1]237 End If
238 Else
[30]239 m_Length = allocLength
[31]240 Chars[m_Length] = 0
[1]241 End If
242 End Sub
243
[139]244 Sub ReSize(allocLength As Long, c As StrChar)
[1]245 If allocLength < 0 Then
246 Exit Sub
[30]247 ElseIf allocLength > m_Length Then
[1]248 Dim oldLength As Long
[30]249 oldLength = m_Length
[1]250 If AllocStringBuffer(allocLength) <> 0 Then
[139]251 Dim p = VarPtr(Chars[oldLength]) As *StrChar
[121]252 Dim fillLen = m_Length - oldLength
253 Dim i As Long
254 For i = 0 To ELM(fillLen)
255 p[i] = c
256 Next
[1]257 End If
258 Else
[30]259 m_Length = allocLength
[1]260 End If
[31]261 Chars[m_Length] = 0
[1]262 End Sub
263
[175]264 Sub Assign(text As PCSTR, textLengthA As Long)
265#ifdef __STRING_IS_NOT_UNICODE
266 AssignFromStrChar(text, textLengthA)
[139]267#else
268 Dim textLengthW = MultiByteToWideChar(CP_THREAD_ACP, 0, text, textLengthA, 0, 0)
269 If AllocStringBuffer(textLengthW) <> 0 Then
270 MultiByteToWideChar(CP_THREAD_ACP, 0, text, textLengthA, Chars, textLengthW)
[192]271 Chars[textLengthW] = 0
[139]272 End If
273#endif
274 End Sub
[1]275
[175]276 Sub Assign(text As PCWSTR, textLengthW As Long)
[139]277#ifdef __STRING_IS_NOT_UNICODE
[175]278 Dim textLengthA = WideCharToMultiByte(CP_THREAD_ACP, 0, text, textLengthW, 0, 0, 0, 0)
279 If AllocStringBuffer(textLengthA) <> 0 Then
280 WideCharToMultiByte(CP_THREAD_ACP, 0, text, textLengthW, Chars, textLengthA, 0, 0)
[192]281 Chars[textLengthA] = 0
[175]282 End If
[139]283#else
[175]284 AssignFromStrChar(text, textLengthW)
[139]285#endif
286 End Sub
287
[1]288 Sub Assign(ByRef objString As String)
[31]289 Assign(objString.Chars, objString.m_Length)
[1]290 End Sub
291
[139]292 Sub Assign(text As PCSTR)
[121]293 If text Then
[139]294 Assign(text, lstrlenA(text))
[1]295 Else
[139]296 If Chars <> 0 Then
297 Chars[0] = 0
298 End If
[30]299 m_Length = 0
[1]300 End If
301 End Sub
302
[139]303 Sub Assign(text As PCWSTR)
304 If text Then
305 Assign(text, lstrlenW(text))
306 Else
307 If Chars <> 0 Then
308 Chars[0] = 0
309 End If
310 m_Length = 0
311 End If
312 End Sub
313
314 Sub Append(text As *StrChar, textLength As Long)
[1]315 Dim prevLen As Long
[30]316 prevLen = m_Length
317 If AllocStringBuffer(m_Length + textLength) <> 0 Then
[139]318 memcpy(VarPtr(Chars[prevLen]), text, SizeOf (StrChar) * textLength)
[31]319 Chars[m_Length] = 0
[1]320 End If
321 End Sub
322
[139]323 Sub Append(text As *StrChar)
[1]324 Append(text, lstrlen(text))
325 End Sub
326
327 Sub Append(ByRef str As String)
[31]328 Append(str.Chars, str.m_Length)
[1]329 End Sub
330
[132]331 Const Function Clone() As String
332 Return This
333 End Function
[139]334Private
[193]335 Static Function ConcatStrChar(text1 As *StrChar, text1Length As Long, text2 As *StrChar, text2Length As Long) As String
[207]336 ConcatStrChar = New String()
[139]337 With ConcatStrChar
338 .AllocStringBuffer(text1Length + text2Length)
339 memcpy(.Chars, text1, SizeOf (StrChar) * text1Length)
340 memcpy(VarPtr(.Chars[text1Length]), text2, SizeOf (StrChar) * text2Length)
341 .Chars[text1Length + text2Length] = 0
342 End With
343 End Function
344Public
345 Const Function Concat(text As PCSTR, len As Long) As String
346#ifdef __STRING_IS_NOT_UNICODE
347 Return ConcatStrChar(This.Chars, m_Length, text, len)
348#else
349 With Concat
350 Dim lenW = MultiByteToWideChar(CP_THREAD_ACP, 0, text, len, 0, 0)
351 .AllocStringBuffer(m_Length + lenW)
352 memcpy(.Chars, This.Chars, m_Length)
353 MultiByteToWideChar(CP_THREAD_ACP, 0, text, len, VarPtr(.Chars[m_Length]), lenW)
354 .Chars[m_Length + lenW] = 0
355 End With
356#endif
357 End Function
[132]358
[139]359 Const Function Concat(text As PCWSTR, len As Long) As String
360#ifdef __STRING_IS_NOT_UNICODE
361 With Concat
362 Dim lenA = MultiByteToWideChar(CP_THREAD_ACP, 0, text, len, 0, 0, 0, 0)
363 .AllocStringBuffer(m_Length + lenA)
364 memcpy(.Chars, This.Chars, m_Length)
365 MultiByteToWideChar(CP_THREAD_ACP, 0, text, len, VarPtr(.Chars[m_Length]), lenA, 0, 0)
366 .Chars[m_Length + lenA] = 0
[1]367 End With
[139]368#else
369 Return ConcatStrChar(This.Chars, m_Length, text, len)
370#endif
[1]371 End Function
[203]372
373 Static Function Concat(x As String, y As String) As String
374 If x = Nothing Then
375 Return y
376 Else
377 Return x.Concat(objString.Chars, objString.m_Length)
378 End If
379 End Function
380
381 Static Function Concat(x As Object, y As Object) As String
382 Return String.Concat(x.ToString, y.ToString)
383 End Function
384
385 Const Function Contains(objString As String) As Boolean
[132]386 Return IndexOf(objString, 0, m_Length) >= 0
[1]387 End Function
388
[139]389 Const Function Contains(lpszText As *StrChar) As Boolean
[132]390 Return IndexOf(lpszText, 0, m_Length) >= 0
[1]391 End Function
392
[139]393 Const Function IndexOf(lpszText As *StrChar) As Long
[30]394 Return IndexOf(lpszText, 0, m_Length)
[1]395 End Function
396
[139]397 Const Function IndexOf(lpszText As *StrChar, startIndex As Long) As Long
[30]398 Return IndexOf(lpszText, startIndex, m_Length - startIndex)
[1]399 End Function
400
[139]401 Const Function IndexOf(lpszText As *StrChar, startIndex As Long, count As Long) As Long
[132]402 Dim length = lstrlen(lpszText)
[1]403
404 If startIndex < 0 Then Return -1
[30]405 If count < 1 Or count + startIndex > m_Length Then Return -1
406 If length > m_Length Then Return -1
[1]407
408 If length = 0 Then Return startIndex
409
410 Dim i As Long, j As Long
411 For i = startIndex To startIndex + count - 1
412 For j = 0 To length - 1
[31]413 If Chars[i + j] = lpszText[j] Then
[1]414 If j = length - 1 Then Return i
415 Else
416 Exit For
417 End If
418 Next
419 Next
420 Return -1
421 End Function
422
[139]423 Const Function LastIndexOf(lpszText As *StrChar) As Long
[30]424 Return LastIndexOf(lpszText, m_Length - 1, m_Length)
[1]425 End Function
426
[139]427 Const Function LastIndexOf(lpszText As *StrChar, startIndex As Long) As Long
428 Return LastIndexOf(lpszText As *StrChar, startIndex, startIndex + 1)
[1]429 End Function
430
[139]431 Const Function LastIndexOf(lpszText As *StrChar, startIndex As Long, count As Long) As Long
[132]432 Dim length = lstrlen(lpszText)
[1]433
[30]434 If startIndex < 0 Or startIndex > m_Length - 1 Then Return -1
[1]435 If count < 1 Or count > startIndex + 2 Then Return -1
[30]436 If length > m_Length Then Return -1
[1]437
438 If length = 0 Then Return startIndex
439
440 Dim i As Long, j As Long
441 For i = startIndex To startIndex - count + 1 Step -1
442 For j = length - 1 To 0 Step -1
[31]443 If Chars[i + j] = lpszText[j] Then
[1]444 If j = 0 Then Return i
445 Else
446 Exit For
447 End If
448 Next
449 Next
450 Return -1
451 End Function
452
[139]453 Const Function StartsWith(lpszText As *StrChar) As Boolean
[132]454 Return IndexOf(lpszText) = 0
[1]455 End Function
456
[139]457 Const Function EndsWith(lpszText As *StrChar) As Boolean
[132]458 Return LastIndexOf(lpszText) = m_Length - lstrlen(lpszText)
[1]459 End Function
460
[132]461 Const Function Insert(startIndex As Long, text As String) As String
462 Return Insert(startIndex, text.Chars, text.Length)
463 End Function
[1]464
[139]465 Const Function Insert(startIndex As Long, text As *StrChar) As String
[132]466 Return Insert(startIndex, text, lstrlen(text))
467 End Function
[1]468
[139]469 Const Function Insert(startIndex As Long, text As *StrChar, length As Long) As String
[132]470 If startIndex < 0 Or startIndex > m_Length Or length < 0 Then
471 Debug 'ArgumentOutOfRangeException
[1]472
[132]473 End If
474 Insert.ReSize(m_Length + length)
[139]475 memcpy(Insert.Chars, Chars, SizeOf (StrChar) * startIndex)
476 memcpy(VarPtr(Insert.Chars[startIndex]), text, SizeOf (StrChar) * length)
477 memcpy(VarPtr(Insert.Chars[startIndex + length]), VarPtr(Chars[startIndex]), SizeOf (StrChar) * (m_Length - startIndex + 1))
[1]478 End Function
479
[132]480 Const Function SubString(startIndex As Long) As String
[30]481 Return SubString(startIndex, m_Length - startIndex)
[1]482 End Function
483
[132]484 Const Function SubString(startIndex As Long, length As Long) As String
[1]485 If startIndex < 0 Or length <= 0 Then Return ""
[30]486 If startIndex + length > m_Length Then Return ""
[1]487
488 Dim temp As String
489 temp.AllocStringBuffer(length)
[139]490 memcpy(temp.Chars, VarPtr(Chars[startIndex]), SizeOf (StrChar) * length)
[31]491 Chars[m_Length] = 0
[1]492 Return temp
493 End Function
494
[132]495 Const Function Remove(startIndex As Long) As String
[135]496 If startIndex < 0 Or startIndex > m_Length Then
497 Debug 'ArgumentOutOfRangeException
498 End If
499
[132]500 Remove.ReSize(startIndex)
[139]501 memcpy(Remove.Chars, This.Chars, SizeOf (StrChar) * startIndex)
[1]502 End Function
503
[132]504 Const Function Remove(startIndex As Long, count As Long) As String
[135]505 If startIndex < 0 Or count < 0 Or startIndex + count > m_Length Then
506 Debug 'ArgumentOutOfRangeException
507 End If
508
[132]509 Remove.ReSize(m_Length - count)
[139]510 memcpy(Remove.Chars, This.Chars, SizeOf (StrChar) * startIndex)
511 memcpy(VarPtr(Remove.Chars[startIndex]), VarPtr(This.Chars[startIndex + count]), SizeOf (StrChar) * (m_Length - startIndex - count))
[132]512 End Function
[192]513
[132]514 Static Function IsNullOrEmpty(s As String) As Boolean
515 If s <> Nothing Then
516 If s.m_Length > 0 Then
517 Return True
518 End If
519 End If
520 Return False
521 End Function
[192]522
[139]523 Const Function Replace(oldChar As StrChar, newChar As StrChar) As String
[132]524 Replace = Copy(This)
525 With Replace
526 Dim i As Long
527 For i = 0 To ELM(.m_Length)
[142]528 If .Chars[i] = oldChar Then
529 .Chars[i] = newChar
[132]530 End If
531 Next
532 End With
533 End Function
[1]534
[132]535 Const Function Replace(ByRef oldStr As String, ByRef newStr As String) As String
536' If oldStr = Nothing Then Throw ArgumentNullException
537'
538' If newStr = Nothing Then
539' Return ReplaceCore(oldStr, oldStr.m_Length, "", 0)
540' Else
541 Return ReplaceCore(oldStr, oldStr.m_Length, newStr, newStr.m_Length)
542' End If
543 End Function
[1]544
[139]545 Const Function Replace(oldStr As *StrChar, newStr As *StrChar)
[132]546 If oldStr = 0 Then Debug 'Throw ArgumentNullException
547 If newStr = 0 Then newStr = ""
548 Return ReplaceCore(oldStr, lstrlen(oldStr), newStr, lstrlen(newStr)) As String
[1]549 End Function
550
[139]551 Const Function Replace(oldStr As *StrChar, oldLen As Long, newStr As *StrChar, newLen As Long) As String
[132]552 If oldStr = 0 Then Debug 'Throw ArgumentNullException
553 If newStr = 0 Then
554 newStr = ""
555 newLen = 0
[1]556 End If
[132]557 Return ReplaceCore(oldStr, oldLen, newStr, newLen)
[1]558 End Function
559
[134]560 Const Function ToLower() As String
561 ToLower.ReSize(m_Length)
[125]562 Dim i As Long
[134]563 For i = 0 To ELM(m_Length)
564 ToLower.Chars[i] = _System_ASCII_ToLower(Chars[i])
[125]565 Next
[134]566 End Function
[1]567
[134]568 Const Function ToUpper() As String
569 ToUpper.ReSize(m_Length)
[125]570 Dim i As Long
[134]571 For i = 0 To ELM(m_Length)
572 ToUpper.Chars[i] = _System_ASCII_ToUpper(Chars[i])
[125]573 Next
[134]574 End Function
[1]575
576 Sub Swap(ByRef x As String)
577 Dim tempLen As Long
[139]578 Dim tempChars As *StrChar
[30]579 tempLen = x.m_Length
[31]580 tempChars = x.Chars
[30]581 x.m_Length = This.m_Length
[31]582 x.Chars = This.Chars
[30]583 This.m_Length = tempLen
[31]584 This.Chars = tempChars
[1]585 End Sub
586
[119]587 Override Function ToString() As String
588 Return This
589 End Function
590
[132]591 Static Function Copy(s As String) As String
[142]592 Copy.ReSize(s.m_Length)
[139]593 memcpy(Copy.Chars, This.Chars, SizeOf (StrChar) * m_Length)
[132]594 End Function
595
[143]596 Override Function GetHashCode() As Long
597#ifdef __STRING_IS_NOT_UNICODE
598 Dim size = (m_Length + 1) >> 1
599#else
600 Dim size = m_Length
601#endif
[175]602 Return _System_GetHashFromWordArray(Chars As *Word, size)
[143]603 End Function
[1]604Private
605 ' メモリ確保に失敗すると元の文字列は失われない。(例外安全でいう強い保障)
[139]606 Function AllocStringBuffer(textLength As Long) As *StrChar
[1]607 If textLength < 0 Then
608 Return 0
[221]609 ElseIf textLength > m_Length or Chars = 0 Then
[139]610 AllocStringBuffer = _System_realloc(Chars, SizeOf(StrChar) * (textLength + 1))
[1]611 If AllocStringBuffer <> 0 Then
[30]612 m_Length = textLength
[31]613 Chars = AllocStringBuffer
[1]614 End If
615 Else
[30]616 m_Length = textLength
[31]617 AllocStringBuffer = Chars
[1]618 End If
619 End Function
620
[139]621 Function ReplaceCore(oldStr As *StrChar, oldLen As Long, newStr As *StrChar, newLen As Long) As String
[132]622 If oldLen = 0 Then
623 Debug 'Throw ArgumentException
624 End If
625 Dim tmp As String
626 With tmp
627 Dim current = 0 As Long
628 Do
629 Dim pos = IndexOf(oldStr, current)
630 If pos = -1 Then
631 Exit Do
632 End If
633 .Append(VarPtr(Chars[current]), pos - current)
634 .Append(newStr, newLen)
635 current = pos + oldLen
636 Loop
637 .Append(VarPtr(Chars[current]), m_Length - current)
638 End With
639 Return tmp
640 End Function
641
[175]642 Sub AssignFromStrChar(text As *StrChar, textLength As Long)
643 If text = Chars Then Exit Sub
644 If AllocStringBuffer(textLength) <> 0 Then
645 memcpy(Chars, text, SizeOf (StrChar) * textLength)
646 Chars[m_Length] = 0
647 End If
648 End Sub
[1]649End Class
Note: See TracBrowser for help on using the repository browser.