2 * Copyright 2001-2006, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
6 * Marc Flerackers (mflerackers@androme.be)
7 * Stefano Ceccherini (stefano.ceccherini@gmail.com)
15 #include <utf8_functions.h>
18 #include <InterfaceDefs.h> // for B_UTF8_BULLET
20 #include "TextGapBuffer.h"
26 static const int32 kTextGapBufferBlockSize
= 2048;
29 TextGapBuffer::TextGapBuffer()
33 fBufferCount(kTextGapBufferBlockSize
+ fItemCount
),
34 fGapIndex(fItemCount
),
35 fGapCount(fBufferCount
- fGapIndex
),
40 fBuffer
= (char*)malloc(kTextGapBufferBlockSize
+ fItemCount
);
41 fScratchBuffer
= NULL
;
45 TextGapBuffer::~TextGapBuffer()
53 TextGapBuffer::InsertText(const char* inText
, int32 inNumItems
, int32 inAtIndex
)
58 inAtIndex
= (inAtIndex
> fItemCount
) ? fItemCount
: inAtIndex
;
59 inAtIndex
= (inAtIndex
< 0) ? 0 : inAtIndex
;
61 if (inAtIndex
!= fGapIndex
)
62 _MoveGapTo(inAtIndex
);
64 if (fGapCount
< inNumItems
)
65 _EnlargeGapTo(inNumItems
+ kTextGapBufferBlockSize
);
67 memcpy(fBuffer
+ fGapIndex
, inText
, inNumItems
);
69 fGapCount
-= inNumItems
;
70 fGapIndex
+= inNumItems
;
71 fItemCount
+= inNumItems
;
76 TextGapBuffer::InsertText(BFile
* file
, int32 fileOffset
, int32 inNumItems
,
81 if (file
->GetSize(&fileSize
) != B_OK
82 || !file
->IsReadable())
85 // Clamp the text length to the file size
86 fileSize
-= fileOffset
;
88 if (fileSize
< inNumItems
)
89 inNumItems
= fileSize
;
94 inAtIndex
= (inAtIndex
> fItemCount
) ? fItemCount
: inAtIndex
;
95 inAtIndex
= (inAtIndex
< 0) ? 0 : inAtIndex
;
97 if (inAtIndex
!= fGapIndex
)
98 _MoveGapTo(inAtIndex
);
100 if (fGapCount
< inNumItems
)
101 _EnlargeGapTo(inNumItems
+ kTextGapBufferBlockSize
);
103 // Finally, read the data and put it into the buffer
104 if (file
->ReadAt(fileOffset
, fBuffer
+ fGapIndex
, inNumItems
) > 0) {
105 fGapCount
-= inNumItems
;
106 fGapIndex
+= inNumItems
;
107 fItemCount
+= inNumItems
;
115 TextGapBuffer::RemoveRange(int32 start
, int32 end
)
117 int32 inAtIndex
= start
;
118 int32 inNumItems
= end
- start
;
123 inAtIndex
= (inAtIndex
> fItemCount
- 1) ? (fItemCount
- 1) : inAtIndex
;
124 inAtIndex
= (inAtIndex
< 0) ? 0 : inAtIndex
;
126 _MoveGapTo(inAtIndex
);
128 fGapCount
+= inNumItems
;
129 fItemCount
-= inNumItems
;
131 if (fGapCount
> kTextGapBufferBlockSize
)
132 _ShrinkGapTo(kTextGapBufferBlockSize
/ 2);
137 TextGapBuffer::GetString(int32 fromOffset
, int32
* _numBytes
)
139 const char* result
= "";
140 if (_numBytes
== NULL
)
143 int32 numBytes
= *_numBytes
;
147 bool isStartBeforeGap
= fromOffset
< fGapIndex
;
148 bool isEndBeforeGap
= (fromOffset
+ numBytes
- 1) < fGapIndex
;
150 if (isStartBeforeGap
== isEndBeforeGap
) {
151 result
= fBuffer
+ fromOffset
;
152 if (!isStartBeforeGap
)
155 if (fScratchSize
< numBytes
) {
156 fScratchBuffer
= (char*)realloc(fScratchBuffer
, numBytes
);
157 fScratchSize
= numBytes
;
160 for (int32 i
= 0; i
< numBytes
; i
++)
161 fScratchBuffer
[i
] = RealCharAt(fromOffset
+ i
);
163 result
= fScratchBuffer
;
166 // TODO: this could be improved. We are overwriting what we did some lines
167 // ago, we could just avoid to do that.
169 uint32 numChars
= UTF8CountChars(result
, numBytes
);
170 uint32 charLen
= UTF8CountBytes(B_UTF8_BULLET
, 1);
171 uint32 newSize
= numChars
* charLen
;
173 if ((uint32
)fScratchSize
< newSize
) {
174 fScratchBuffer
= (char*)realloc(fScratchBuffer
, newSize
);
175 fScratchSize
= newSize
;
177 result
= fScratchBuffer
;
179 char* scratchPtr
= fScratchBuffer
;
180 for (uint32 i
= 0; i
< numChars
; i
++) {
181 memcpy(scratchPtr
, B_UTF8_BULLET
, charLen
);
182 scratchPtr
+= charLen
;
185 *_numBytes
= newSize
;
193 TextGapBuffer::FindChar(char inChar
, int32 fromIndex
, int32
* ioDelta
)
195 int32 numChars
= *ioDelta
;
196 for (int32 i
= 0; i
< numChars
; i
++) {
197 char realChar
= RealCharAt(fromIndex
+ i
);
198 if ((realChar
& 0xc0) == 0x80)
200 if (realChar
== inChar
) {
211 TextGapBuffer::Text()
213 const char* realText
= RealText();
216 const uint32 numChars
= UTF8CountChars(realText
, Length());
217 const uint32 bulletCharLen
= UTF8CountBytes(B_UTF8_BULLET
, 1);
218 uint32 newSize
= numChars
* bulletCharLen
+ 1;
220 if ((uint32
)fScratchSize
< newSize
) {
221 fScratchBuffer
= (char*)realloc(fScratchBuffer
, newSize
);
222 fScratchSize
= newSize
;
225 char* scratchPtr
= fScratchBuffer
;
226 for (uint32 i
= 0; i
< numChars
; i
++) {
227 memcpy(scratchPtr
, B_UTF8_BULLET
, bulletCharLen
);
228 scratchPtr
+= bulletCharLen
;
232 return fScratchBuffer
;
240 TextGapBuffer::RealText()
242 _MoveGapTo(fItemCount
);
245 _EnlargeGapTo(kTextGapBufferBlockSize
);
247 fBuffer
[fItemCount
] = '\0';
253 TextGapBuffer::GetString(int32 offset
, int32 length
, char* buffer
)
258 int32 textLen
= Length();
260 if (offset
< 0 || offset
> (textLen
- 1) || length
< 1) {
265 length
= ((offset
+ length
) > textLen
) ? textLen
- offset
: length
;
267 bool isStartBeforeGap
= (offset
< fGapIndex
);
268 bool isEndBeforeGap
= ((offset
+ length
- 1) < fGapIndex
);
270 if (isStartBeforeGap
== isEndBeforeGap
) {
271 char* source
= fBuffer
+ offset
;
272 if (!isStartBeforeGap
)
275 memcpy(buffer
, source
, length
);
278 // if we are here, it can only be that start is before gap,
279 // and the end is after gap.
281 int32 beforeLen
= fGapIndex
- offset
;
282 int32 afterLen
= length
- beforeLen
;
284 memcpy(buffer
, fBuffer
+ offset
, beforeLen
);
285 memcpy(buffer
+ beforeLen
, fBuffer
+ fGapIndex
+ fGapCount
, afterLen
);
289 buffer
[length
] = '\0';
294 TextGapBuffer::PasswordMode() const
296 return fPasswordMode
;
301 TextGapBuffer::SetPasswordMode(bool state
)
303 fPasswordMode
= state
;
308 TextGapBuffer::_MoveGapTo(int32 toIndex
)
310 if (toIndex
== fGapIndex
)
312 if (toIndex
> fItemCount
) {
313 debugger("MoveGapTo: invalid toIndex supplied");
320 if (toIndex
> fGapIndex
) {
321 srcIndex
= fGapIndex
+ fGapCount
;
322 dstIndex
= fGapIndex
;
323 count
= toIndex
- fGapIndex
;
326 dstIndex
= toIndex
+ fGapCount
;
327 count
= fGapIndex
- toIndex
;
331 memmove(fBuffer
+ dstIndex
, fBuffer
+ srcIndex
, count
);
338 TextGapBuffer::_EnlargeGapTo(int32 inCount
)
340 if (inCount
== fGapCount
)
343 fBuffer
= (char*)realloc(fBuffer
, fItemCount
+ inCount
);
344 memmove(fBuffer
+ fGapIndex
+ inCount
, fBuffer
+ fGapIndex
+ fGapCount
,
345 fBufferCount
- (fGapIndex
+ fGapCount
));
348 fBufferCount
= fItemCount
+ fGapCount
;
353 TextGapBuffer::_ShrinkGapTo(int32 inCount
)
355 if (inCount
== fGapCount
)
358 memmove(fBuffer
+ fGapIndex
+ inCount
, fBuffer
+ fGapIndex
+ fGapCount
,
359 fBufferCount
- (fGapIndex
+ fGapCount
));
360 fBuffer
= (char*)realloc(fBuffer
, fItemCount
+ inCount
);
363 fBufferCount
= fItemCount
+ fGapCount
;
367 } // namespace BPrivate