• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Tehreer / SheenBidi / 28885974711

07 Jul 2026 05:31PM UTC coverage: 96.293% (-0.1%) from 96.404%
28885974711

push

github

mta452
[lib] Fix memory leaks

17 of 17 new or added lines in 4 files covered. (100.0%)

34 existing lines in 5 files now uncovered.

4000 of 4154 relevant lines covered (96.29%)

450834.3 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.86
/Source/API/SBText.c
1
/*
2
 * Copyright (C) 2025-2026 Muhammad Tayyab Akram
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
#include <API/SBBase.h>
18

19
#if SB_TEXT_API_SUPPORTED
20

21
#include <stddef.h>
22

23
#include <API/SBAssert.h>
24
#include <API/SBAttributeRegistry.h>
25
#include <API/SBTextConfig.h>
26
#include <API/SBTextIterators.h>
27
#include <Core/Object.h>
28
#include <Text/AttributeManager.h>
29
#include <Text/BidiTypesBuffer.h>
30
#include <Text/TextAnalysis.h>
31
#include <Text/TextBuffer.h>
32

33
#include "SBText.h"
34

35
/* =========================================================================
36
 * Text Implementation
37
 * ========================================================================= */
38

39
SBTextRef SBTextCreate(const void *string, SBUInteger length, SBStringEncoding encoding,
17✔
40
    SBTextConfigRef config)
41
{
42
    SBMutableTextRef text = SBTextCreateMutable(encoding, config);
17✔
43

44
    if (text) {
17✔
45
        SBTextAppendCodeUnits(text, string, length);
17✔
46
        text->isMutable = SBFalse;
17✔
47
    }
48

49
    return text;
17✔
50
}
51

52
SBTextRef SBTextCreateCopy(SBTextRef text)
2✔
53
{
54
    SBMutableTextRef copy = SBTextCreateMutableCopy(text);
2✔
55

56
    if (copy) {
2✔
57
        copy->isMutable = SBFalse;
2✔
58
    }
59

60
    return copy;
2✔
61
}
62

63
SBStringEncoding SBTextGetEncoding(SBTextRef text)
7✔
64
{
65
    return text->buffer.encoding;
7✔
66
}
67

68
SBAttributeRegistryRef SBTextGetAttributeRegistry(SBTextRef text)
10✔
69
{
70
    return text->attributeRegistry;
10✔
71
}
72

73
SBUInteger SBTextGetLength(SBTextRef text)
24✔
74
{
75
    return TextBufferGetLength((TextBufferRef)&text->buffer);
24✔
76
}
77

78
void SBTextGetCodeUnits(SBTextRef text, SBUInteger index, SBUInteger length, void *buffer)
10✔
79
{
80
    SBBoolean isRangeValid = SBUIntegerVerifyRange(text->buffer.codeUnits.count, index, length);
10✔
81

82
    SBAssert(isRangeValid);
10✔
83

84
    TextBufferGetCodeUnits((TextBufferRef)&text->buffer, index, length, buffer);
10✔
85
}
10✔
86

87
void SBTextGetBidiTypes(SBTextRef text, SBUInteger index, SBUInteger length, SBBidiType *buffer)
2✔
88
{
89
    SBBoolean isRangeValid = SBUIntegerVerifyRange(text->buffer.codeUnits.count, index, length);
2✔
90

91
    SBAssert(isRangeValid);
2✔
92

93
    BidiTypesBufferGetBidiTypes((BidiTypesBufferRef)&text->bidiTypes, index, length, buffer);
2✔
94
}
2✔
95

96
void SBTextGetScripts(SBTextRef text, SBUInteger index, SBUInteger length, SBScript *buffer)
2✔
97
{
98
    SBBoolean isRangeValid = SBUIntegerVerifyRange(text->buffer.codeUnits.count, index, length);
2✔
99

100
    SBAssert(isRangeValid && !text->isEditing);
2✔
101

102
    TextAnalysisGetScripts((TextAnalysisRef)&text->analysis, index, length, buffer);
2✔
103
}
2✔
104

105
void SBTextGetResolvedLevels(SBTextRef text, SBUInteger index, SBUInteger length, SBLevel *buffer)
2✔
106
{
107
    SBBoolean isRangeValid = SBUIntegerVerifyRange(text->buffer.codeUnits.count, index, length);
2✔
108

109
    SBAssert(isRangeValid && !text->isEditing);
2✔
110

111
    TextAnalysisGetResolvedLevels((TextAnalysisRef)&text->analysis, index, length, buffer);
2✔
112
}
2✔
113

114
void SBTextGetCodeUnitParagraphInfo(SBTextRef text, SBUInteger index,
2✔
115
    SBParagraphInfo *paragraphInfo)
116
{
117
    SBBoolean isValidIndex = index < text->buffer.codeUnits.count;
2✔
118

119
    SBAssert(isValidIndex && !text->isEditing);
2✔
120

121
    TextAnalysisGetCodeUnitParagraphInfo((TextAnalysisRef)&text->analysis, index, paragraphInfo);
2✔
122
}
2✔
123

124
SBParagraphIteratorRef SBTextCreateParagraphIterator(SBTextRef text)
1✔
125
{
126
    return SBParagraphIteratorCreate(text);
1✔
127
}
128

129
SBLogicalRunIteratorRef SBTextCreateLogicalRunIterator(SBTextRef text)
1✔
130
{
131
    return SBLogicalRunIteratorCreate(text);
1✔
132
}
133

134
SBScriptRunIteratorRef SBTextCreateScriptRunIterator(SBTextRef text)
1✔
135
{
136
    return SBScriptRunIteratorCreate(text);
1✔
137
}
138

139
SBAttributeRunIteratorRef SBTextCreateAttributeRunIterator(SBTextRef text)
26✔
140
{
141
    return SBAttributeRunIteratorCreate(text);
26✔
142
}
143

UNCOV
144
SBVisualRunIteratorRef SBTextCreateVisualRunIterator(SBTextRef text,
×
145
    SBUInteger index, SBUInteger length)
146
{
UNCOV
147
    SBVisualRunIteratorRef iterator = SBVisualRunIteratorCreate(text);
×
148

UNCOV
149
    if (iterator) {
×
UNCOV
150
        SBVisualRunIteratorReset(iterator, index, length);
×
151
    }
152

UNCOV
153
    return iterator;
×
154
}
155

156
SBTextRef SBTextRetain(SBTextRef text)
88✔
157
{
158
    return ObjectRetain((ObjectRef)text);
88✔
159
}
160

161
void SBTextRelease(SBTextRef text)
260✔
162
{
163
    ObjectRelease((ObjectRef)text);
260✔
164
}
260✔
165

166
/* =========================================================================
167
 * Mutable Text Implementation
168
 * ========================================================================= */
169

170
static void FinalizeMutableText(ObjectRef object)
172✔
171
{
172
    SBMutableTextRef text = object;
172✔
173

174
    AttributeManagerFinalize(&text->attributeManager);
172✔
175
    TextAnalysisFinalize(&text->analysis);
172✔
176
    BidiTypesBufferFinalize(&text->bidiTypes);
172✔
177
    TextBufferFinalize(&text->buffer);
172✔
178

179
    if (text->attributeRegistry) {
172✔
180
        SBAttributeRegistryRelease(text->attributeRegistry);
124✔
181
    }
182
}
172✔
183

184
SB_INTERNAL SBMutableTextRef SBTextCreateMutableWithParameters(SBStringEncoding encoding,
172✔
185
    SBAttributeRegistryRef attributeRegistry, SBLevel baseLevel)
186
{
187
    const SBUInteger size = sizeof(SBText);
172✔
188
    void *pointer = NULL;
172✔
189
    SBMutableTextRef text;
190

191
    text = ObjectCreate(&size, 1, &pointer, FinalizeMutableText);
172✔
192

193
    if (text) {
172✔
194
        if (attributeRegistry) {
172✔
195
            attributeRegistry = SBAttributeRegistryRetain(attributeRegistry);
124✔
196
        }
197

198
        text->isMutable = SBTrue;
172✔
199
        text->isEditing = SBFalse;
172✔
200
        text->attributeRegistry = attributeRegistry;
172✔
201

202
        TextBufferInitialize(&text->buffer, encoding);
172✔
203
        BidiTypesBufferInitialize(&text->bidiTypes);
172✔
204
        TextAnalysisInitialize(&text->analysis, baseLevel);
172✔
205
        AttributeManagerInitialize(&text->attributeManager, &text->analysis, attributeRegistry);
172✔
206
    }
207

208
    return text;
172✔
209
}
210

211
SBMutableTextRef SBTextCreateMutable(SBStringEncoding encoding, SBTextConfigRef config)
168✔
212
{
213
    SBMutableTextRef text = SBTextCreateMutableWithParameters(encoding,
168✔
214
        config->attributeRegistry, config->baseLevel);
168✔
215

216
    if (text) {
217
        /* TODO: Apply default attributes */
218
    }
219

220
    return text;
168✔
221
}
222

223
SBMutableTextRef SBTextCreateMutableCopy(SBTextRef text)
4✔
224
{
225
    SBMutableTextRef copy = SBTextCreateMutableWithParameters(text->buffer.encoding,
4✔
226
        text->attributeRegistry, text->analysis.baseLevel);
4✔
227

228
    if (copy) {
4✔
229
        TextBufferCopyCodeUnits(&copy->buffer, &text->buffer);
4✔
230
        BidiTypesBufferCopyBidiTypes(&copy->bidiTypes, &text->bidiTypes);
4✔
231
        TextAnalysisCopyParagraphs(&copy->analysis, &text->analysis);
4✔
232
        TextAnalysisFlush(&copy->analysis, &copy->buffer, &copy->bidiTypes);
4✔
233

234
        /* Copy attributes */
235
        AttributeManagerCopyAttributes(&copy->attributeManager, &text->attributeManager);
4✔
236
    }
237

238
    return copy;
4✔
239
}
240

241
void SBTextBeginEditing(SBMutableTextRef text)
4✔
242
{
243
    SBAssert(text->isMutable);
4✔
244

245
    if (!text->isMutable) {
4✔
UNCOV
246
        return;
×
247
    }
248

249
    text->isEditing = SBTrue;
4✔
250
}
251

252
void SBTextEndEditing(SBMutableTextRef text)
4✔
253
{
254
    SBAssert(text->isMutable);
4✔
255

256
    if (!text->isMutable) {
4✔
UNCOV
257
        return;
×
258
    }
259

260
    TextAnalysisFlush(&text->analysis, &text->buffer, &text->bidiTypes);
4✔
261
    text->isEditing = SBFalse;
4✔
262
}
263

264
void SBTextAppendCodeUnits(SBMutableTextRef text,
160✔
265
    const void *codeUnitBuffer, SBUInteger codeUnitCount)
266
{
267
    SBAssert(text->isMutable);
160✔
268

269
    if (!text->isMutable) {
160✔
UNCOV
270
        return;
×
271
    }
272

273
    SBTextInsertCodeUnits(text, text->buffer.codeUnits.count, codeUnitBuffer, codeUnitCount);
160✔
274
}
275

276
void SBTextInsertCodeUnits(SBMutableTextRef text, SBUInteger index,
193✔
277
    const void *codeUnitBuffer, SBUInteger codeUnitCount)
278
{
279
    SBAssert(text->isMutable && index <= text->buffer.codeUnits.count);
193✔
280

281
    if (!text->isMutable) {
193✔
UNCOV
282
        return;
×
283
    }
284

285
    if (codeUnitCount > 0) {
193✔
286
        /* Splice into the raw code-unit storage */
287
        TextBufferInsertCodeUnits(&text->buffer, index, codeUnitBuffer, codeUnitCount);
184✔
288

289
        /* Re-derive bidi types immediately; paragraph boundaries need them as input */
290
        BidiTypesBufferReplaceRange(&text->bidiTypes, &text->buffer, index, 0, codeUnitCount);
184✔
291

292
        /* Re-derive paragraph boundaries; scripts/levels stay deferred */
293
        TextAnalysisReplaceRange(&text->analysis, &text->buffer, &text->bidiTypes, index, 0, codeUnitCount);
184✔
294

295
        /* Reserve attribute manager space */
296
        AttributeManagerReserveRange(&text->attributeManager, index, codeUnitCount);
184✔
297

298
        /* Perform immediate analysis if not in batch editing mode */
299
        if (!text->isEditing) {
184✔
300
            TextAnalysisFlush(&text->analysis, &text->buffer, &text->bidiTypes);
178✔
301
        }
302
    }
303
}
304

305
void SBTextDeleteCodeUnits(SBMutableTextRef text, SBUInteger index, SBUInteger length)
16✔
306
{
307
    SBUInteger rangeEnd = index + length;
16✔
308
    SBBoolean isRangeValid = (rangeEnd <= text->buffer.codeUnits.count && index <= rangeEnd);
16✔
309

310
    SBAssert(text->isMutable && isRangeValid);
16✔
311

312
    if (!text->isMutable) {
16✔
UNCOV
313
        return;
×
314
    }
315

316
    if (length > 0) {
16✔
317
        TextBufferDeleteCodeUnits(&text->buffer, index, length);
15✔
318
        BidiTypesBufferReplaceRange(&text->bidiTypes, &text->buffer, index, length, 0);
15✔
319
        TextAnalysisReplaceRange(&text->analysis, &text->buffer, &text->bidiTypes, index, length, 0);
15✔
320
        AttributeManagerRemoveRange(&text->attributeManager, index, length);
15✔
321

322
        if (!text->isEditing) {
15✔
323
            /* Perform immediate analysis if not in batch editing mode */
324
            TextAnalysisFlush(&text->analysis, &text->buffer, &text->bidiTypes);
14✔
325
        }
326
    }
327
}
328

329
void SBTextSetCodeUnits(SBMutableTextRef text,
3✔
330
    const void *codeUnitBuffer, SBUInteger codeUnitCount)
331
{
332
    SBAssert(text->isMutable);
3✔
333

334
    if (!text->isMutable) {
3✔
UNCOV
335
        return;
×
336
    }
337

338
    SBTextReplaceCodeUnits(text, 0, text->buffer.codeUnits.count, codeUnitBuffer, codeUnitCount);
3✔
339
}
340

341
void SBTextReplaceCodeUnits(SBMutableTextRef text, SBUInteger index, SBUInteger length,
28✔
342
    const void *codeUnitBuffer, SBUInteger codeUnitCount)
343
{
344
    SBUInteger rangeEnd = index + length;
28✔
345
    SBBoolean isRangeValid = (rangeEnd <= text->buffer.codeUnits.count && index <= rangeEnd);
28✔
346

347
    SBAssert(text->isMutable && isRangeValid);
28✔
348

349
    if (!text->isMutable) {
28✔
UNCOV
350
        return;
×
351
    }
352

353
    if (length > 0 || codeUnitCount > 0) {
28✔
354
        TextBufferReplaceCodeUnits(&text->buffer, index, length, codeUnitBuffer, codeUnitCount);
26✔
355
        BidiTypesBufferReplaceRange(&text->bidiTypes, &text->buffer, index, length, codeUnitCount);
26✔
356
        TextAnalysisReplaceRange(&text->analysis, &text->buffer, &text->bidiTypes, index, length, codeUnitCount);
26✔
357
        AttributeManagerReplaceRange(&text->attributeManager, index, length, codeUnitCount);
26✔
358

359
        if (!text->isEditing) {
26✔
360
            /* Perform immediate analysis if not in batch editing mode */
361
            TextAnalysisFlush(&text->analysis, &text->buffer, &text->bidiTypes);
25✔
362
        }
363
    }
364
}
365

366
void SBTextSetAttribute(SBMutableTextRef text, SBUInteger index, SBUInteger length,
110✔
367
    SBAttributeID attributeID, const void *attributeValue)
368
{
369
    SBUInteger rangeEnd = index + length;
110✔
370
    SBBoolean isRangeValid = (rangeEnd <= text->buffer.codeUnits.count && index <= rangeEnd);
110✔
371

372
    SBAssert(text->isMutable && isRangeValid);
110✔
373

374
    if (!text->isMutable) {
110✔
UNCOV
375
        return;
×
376
    }
377

378
    if (length > 0) {
110✔
379
        AttributeManagerSetAttribute(&text->attributeManager,
107✔
380
            index, length, attributeID, attributeValue);
381
    }
382
}
383

384
void SBTextRemoveAttribute(SBMutableTextRef text, SBUInteger index, SBUInteger length,
15✔
385
    SBAttributeID attributeID)
386
{
387
    SBUInteger rangeEnd = index + length;
15✔
388
    SBBoolean isRangeValid = (rangeEnd <= text->buffer.codeUnits.count && index <= rangeEnd);
15✔
389

390
    SBAssert(text->isMutable && isRangeValid);
15✔
391

392
    if (!text->isMutable) {
15✔
UNCOV
393
        return;
×
394
    }
395

396
    if (length > 0) {
15✔
397
        AttributeManagerRemoveAttribute(&text->attributeManager, index, length, attributeID);
13✔
398
    }
399
}
400

401
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc