| 107 | size_t offset = 0; |
| 108 | |
| 109 | bool parseLine(StringSpan& key, StringSpan& value) |
| 110 | { |
| 111 | if (text.getEncoding() == StringEncoding::Utf16) |
| 112 | return false; |
| 113 | const auto isSkipped = [](char current) |
| 114 | { return current == '\t' or current == '\n' or current == '\r' or current == ' ' or current == '/'; }; |
| 115 | while (offset < text.sizeInBytes() and isSkipped(text.bytesWithoutTerminator()[offset])) |
| 116 | ++offset; |
| 117 | const size_t keyStart = offset; |
| 118 | while (offset < text.sizeInBytes() and text.bytesWithoutTerminator()[offset] != ':' and |
| 119 | not isSkipped(text.bytesWithoutTerminator()[offset])) |
| 120 | ++offset; |
| 121 | key = PluginString::slice(text, keyStart, offset - keyStart); |
| 122 | while (offset < text.sizeInBytes() and isSkipped(text.bytesWithoutTerminator()[offset])) |
| 123 | ++offset; |
| 124 | if (offset >= text.sizeInBytes() or text.bytesWithoutTerminator()[offset++] != ':') |
| 125 | return false; |
| 126 | while (offset < text.sizeInBytes() and isSkipped(text.bytesWithoutTerminator()[offset])) |
| 127 | ++offset; |
| 128 | const size_t valueStart = offset; |
| 129 | while (offset < text.sizeInBytes() and text.bytesWithoutTerminator()[offset] != '\n' and |
| 130 | text.bytesWithoutTerminator()[offset] != '\r') |
| 131 | ++offset; |
| 132 | value = PluginString::slice(text, valueStart, offset - valueStart); |
| 133 | const bool endedByNewLine = offset < text.sizeInBytes(); |
| 134 | while (offset < text.sizeInBytes() and |
| 135 | (text.bytesWithoutTerminator()[offset] == '\n' or text.bytesWithoutTerminator()[offset] == '\r')) |
| 136 | ++offset; |
| 137 | return endedByNewLine or not value.isEmpty(); |
| 138 | } |
| 139 | } cursor{text}; |
| 140 | |
| 141 | StringSpan key, value; |
no test coverage detected