File indexing completed on 2024-05-12 03:54:23

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2008 Jakub Stachowski <qbast@go2.pl>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #ifndef BUFFERFRAGMENT_H
0009 #define BUFFERFRAGMENT_H
0010 
0011 #include "kconfigini_p.h"
0012 
0013 #define bf_isspace(str) ((str == ' ') || (str == '\t') || (str == '\r'))
0014 
0015 // This class provides wrapper around fragment of existing buffer (array of bytes).
0016 // If underlying buffer gets deleted, all BufferFragment objects referencing it become invalid.
0017 // Use toByteArray() to make deep copy of the buffer fragment.
0018 //
0019 // API is designed to subset of QByteArray methods with some changes:
0020 // - trim() is like QByteArray.trimmed(), but it modifies current object
0021 // - truncateLeft() provides way to cut off beginning of the buffer
0022 // - split() works more like strtok_r than QByteArray.split()
0023 // - truncateLeft() and mid() require position argument to be valid
0024 
0025 class KConfigIniBackend::BufferFragment
0026 {
0027 public:
0028     BufferFragment()
0029         : d(nullptr)
0030         , len(0)
0031     {
0032     }
0033 
0034     BufferFragment(char *buf, int size)
0035         : d(buf)
0036         , len(size)
0037     {
0038     }
0039 
0040     int length() const
0041     {
0042         return len;
0043     }
0044 
0045     char at(unsigned int i) const
0046     {
0047         Q_ASSERT(i < len);
0048         return d[i];
0049     }
0050 
0051     void clear()
0052     {
0053         len = 0;
0054     }
0055 
0056     const char *constData() const
0057     {
0058         return d;
0059     }
0060 
0061     char *data() const
0062     {
0063         return d;
0064     }
0065 
0066     void trim()
0067     {
0068         while (bf_isspace(*d) && len > 0) {
0069             ++d;
0070             --len;
0071         }
0072         while (len > 0 && bf_isspace(d[len - 1])) {
0073             --len;
0074         }
0075     }
0076 
0077     // similar to strtok_r . On first call variable pointed by start should be set to 0.
0078     // Each call will update *start to new starting position.
0079     BufferFragment split(char c, unsigned int *start)
0080     {
0081         if (*start < len) {
0082             int end = indexOf(c, *start);
0083             if (end == -1) {
0084                 end = len;
0085             }
0086             BufferFragment line(d + (*start), end - (*start));
0087             *start = end + 1;
0088             return line;
0089         }
0090         return BufferFragment();
0091     }
0092 
0093     bool isEmpty() const
0094     {
0095         return !len;
0096     }
0097 
0098     BufferFragment left(unsigned int size) const
0099     {
0100         return BufferFragment(d, qMin(size, len));
0101     }
0102 
0103     void truncateLeft(unsigned int size)
0104     {
0105         Q_ASSERT(size <= len);
0106         d += size;
0107         len -= size;
0108     }
0109 
0110     void truncate(unsigned int pos)
0111     {
0112         if (pos < len) {
0113             len = pos;
0114         }
0115     }
0116 
0117     bool isNull() const
0118     {
0119         return !d;
0120     }
0121 
0122     BufferFragment mid(unsigned int pos, int length = -1) const
0123     {
0124         Q_ASSERT(pos < len);
0125         int size = length;
0126         if (length == -1 || (pos + length) > len) {
0127             size = len - pos;
0128         }
0129         return BufferFragment(d + pos, size);
0130     }
0131 
0132     bool operator==(const QByteArray &other) const
0133     {
0134         return (other.size() == (int)len && memcmp(d, other.constData(), len) == 0);
0135     }
0136 
0137     bool operator!=(const QByteArray &other) const
0138     {
0139         return (other.size() != (int)len || memcmp(d, other.constData(), len) != 0);
0140     }
0141 
0142     bool operator==(const BufferFragment other) const
0143     {
0144         return other.len == len && !memcmp(d, other.d, len);
0145     }
0146 
0147     int indexOf(char c, unsigned int from = 0) const
0148     {
0149         const char *cursor = d + from - 1;
0150         const char *end = d + len;
0151         while (++cursor < end)
0152             if (*cursor == c) {
0153                 return cursor - d;
0154             }
0155         return -1;
0156     }
0157 
0158     int lastIndexOf(char c) const
0159     {
0160         int from = len - 1;
0161         while (from >= 0)
0162             if (d[from] == c) {
0163                 return from;
0164             } else {
0165                 --from;
0166             }
0167         return -1;
0168     }
0169 
0170     QByteArray toByteArray() const
0171     {
0172         return QByteArray(d, len);
0173     }
0174 
0175     // this is faster than toByteArray, but returned QByteArray becomes invalid
0176     // when buffer for this BufferFragment disappears
0177     QByteArray toVolatileByteArray() const
0178     {
0179         return QByteArray::fromRawData(d, len);
0180     }
0181 
0182 private:
0183     char *d;
0184     unsigned int len;
0185 };
0186 
0187 size_t qHash(const KConfigIniBackend::BufferFragment fragment, size_t seed = 0)
0188 {
0189     const uchar *p = reinterpret_cast<const uchar *>(fragment.constData());
0190     const int len = fragment.length();
0191 
0192     if (len == 0) {
0193         return seed;
0194     }
0195     return qHashBits(p, len, seed);
0196 }
0197 
0198 #endif