1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2008 Jakub Stachowski <qbast@go2.pl>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#ifndef BUFFERFRAGMENT_H
9#define BUFFERFRAGMENT_H
10
11#include "kconfigini_p.h"
12
13#define bf_isspace(str) ((str == ' ') || (str == '\t') || (str == '\r'))
14
15// This class provides wrapper around fragment of existing buffer (array of bytes).
16// If underlying buffer gets deleted, all BufferFragment objects referencing it become invalid.
17// Use toByteArray() to make deep copy of the buffer fragment.
18//
19// API is designed to subset of QByteArray methods with some changes:
20// - trim() is like QByteArray.trimmed(), but it modifies current object
21// - truncateLeft() provides way to cut off beginning of the buffer
22// - split() works more like strtok_r than QByteArray.split()
23// - truncateLeft() and mid() require position argument to be valid
24
25class KConfigIniBackend::BufferFragment
26{
27public:
28 BufferFragment()
29 : d(nullptr)
30 , len(0)
31 {
32 }
33
34 BufferFragment(char *buf, int size)
35 : d(buf)
36 , len(size)
37 {
38 }
39
40 int length() const
41 {
42 return len;
43 }
44
45 char at(unsigned int i) const
46 {
47 Q_ASSERT(i < len);
48 return d[i];
49 }
50
51 void clear()
52 {
53 len = 0;
54 }
55
56 const char *constData() const
57 {
58 return d;
59 }
60
61 char *data() const
62 {
63 return d;
64 }
65
66 void trim()
67 {
68 while (bf_isspace(*d) && len > 0) {
69 ++d;
70 --len;
71 }
72 while (len > 0 && bf_isspace(d[len - 1])) {
73 --len;
74 }
75 }
76
77 // similar to strtok_r . On first call variable pointed by start should be set to 0.
78 // Each call will update *start to new starting position.
79 BufferFragment split(char c, unsigned int *start)
80 {
81 if (*start < len) {
82 int end = indexOf(c, from: *start);
83 if (end == -1) {
84 end = len;
85 }
86 BufferFragment line(d + (*start), end - (*start));
87 *start = end + 1;
88 return line;
89 }
90 return BufferFragment();
91 }
92
93 bool isEmpty() const
94 {
95 return !len;
96 }
97
98 BufferFragment left(unsigned int size) const
99 {
100 return BufferFragment(d, qMin(a: size, b: len));
101 }
102
103 void truncateLeft(unsigned int size)
104 {
105 Q_ASSERT(size <= len);
106 d += size;
107 len -= size;
108 }
109
110 void truncate(unsigned int pos)
111 {
112 if (pos < len) {
113 len = pos;
114 }
115 }
116
117 bool isNull() const
118 {
119 return !d;
120 }
121
122 BufferFragment mid(unsigned int pos, int length = -1) const
123 {
124 Q_ASSERT(pos < len);
125 int size = length;
126 if (length == -1 || (pos + length) > len) {
127 size = len - pos;
128 }
129 return BufferFragment(d + pos, size);
130 }
131
132 bool operator==(const QByteArray &other) const
133 {
134 return (other.size() == (int)len && memcmp(s1: d, s2: other.constData(), n: len) == 0);
135 }
136
137 bool operator!=(const QByteArray &other) const
138 {
139 return (other.size() != (int)len || memcmp(s1: d, s2: other.constData(), n: len) != 0);
140 }
141
142 bool operator==(const BufferFragment other) const
143 {
144 return other.len == len && !memcmp(s1: d, s2: other.d, n: len);
145 }
146
147 int indexOf(char c, unsigned int from = 0) const
148 {
149 const char *cursor = d + from - 1;
150 const char *end = d + len;
151 while (++cursor < end)
152 if (*cursor == c) {
153 return cursor - d;
154 }
155 return -1;
156 }
157
158 int lastIndexOf(char c) const
159 {
160 int from = len - 1;
161 while (from >= 0)
162 if (d[from] == c) {
163 return from;
164 } else {
165 --from;
166 }
167 return -1;
168 }
169
170 QByteArray toByteArray() const
171 {
172 return QByteArray(d, len);
173 }
174
175 // this is faster than toByteArray, but returned QByteArray becomes invalid
176 // when buffer for this BufferFragment disappears
177 QByteArray toVolatileByteArray() const
178 {
179 return QByteArray::fromRawData(data: d, size: len);
180 }
181
182private:
183 char *d;
184 unsigned int len;
185};
186
187size_t qHash(const KConfigIniBackend::BufferFragment fragment, size_t seed = 0)
188{
189 const uchar *p = reinterpret_cast<const uchar *>(fragment.constData());
190 const int len = fragment.length();
191
192 if (len == 0) {
193 return seed;
194 }
195 return qHashBits(p, size: len, seed);
196}
197
198#endif
199

source code of kconfig/src/core/bufferfragment_p.h