| 153 | } |
| 154 | |
| 155 | std::shared_ptr<Path> SVGPathParser::FromSVGString(const std::string& pathString) { |
| 156 | const char* data = pathString.c_str(); |
| 157 | // We will write all data to this local path and only write it to result if the whole parsing |
| 158 | // succeeds. |
| 159 | auto path = std::make_shared<Path>(); |
| 160 | Point first = {}; |
| 161 | Point opOrigin = {}; |
| 162 | Point lastOpOrigin = {}; |
| 163 | |
| 164 | // We will use find_points and find_scalar to read into these. There might not be enough data to |
| 165 | // fill them, so to avoid MSAN warnings about using uninitialized bytes, we initialize them there. |
| 166 | Point points[3] = {}; |
| 167 | float scratch = 0; |
| 168 | char op = '\0'; |
| 169 | char previousOp = '\0'; |
| 170 | bool relative = false; |
| 171 | for (;;) { |
| 172 | if (!data) { |
| 173 | // Truncated data |
| 174 | return nullptr; |
| 175 | } |
| 176 | data = skip_ws(data); |
| 177 | if (data[0] == '\0') { |
| 178 | break; |
| 179 | } |
| 180 | char ch = data[0]; |
| 181 | if (is_digit(ch) || ch == '-' || ch == '+' || ch == '.') { |
| 182 | if (op == '\0' || op == 'Z') { |
| 183 | return nullptr; |
| 184 | } |
| 185 | } else if (is_sep(ch)) { |
| 186 | data = skip_sep(data); |
| 187 | } else { |
| 188 | op = ch; |
| 189 | relative = false; |
| 190 | if (is_lower(op)) { |
| 191 | op = static_cast<char>(to_upper(op)); |
| 192 | relative = true; |
| 193 | } |
| 194 | data++; |
| 195 | data = skip_sep(data); |
| 196 | } |
| 197 | switch (op) { |
| 198 | case 'M': // Move |
| 199 | data = find_points(data, points, 1, relative, &opOrigin); |
| 200 | // find_points might have failed, so this might be the previous point. However, data will be |
| 201 | // set to nullptr if it failed, so we will check this at the top of the loop. |
| 202 | path->moveTo(points[0]); |
| 203 | previousOp = '\0'; |
| 204 | op = 'L'; |
| 205 | opOrigin = points[0]; |
| 206 | break; |
| 207 | case 'L': // Line |
| 208 | data = find_points(data, points, 1, relative, &opOrigin); |
| 209 | path->lineTo(points[0]); |
| 210 | opOrigin = points[0]; |
| 211 | break; |
| 212 | case 'H': // Horizontal Line |
nothing calls this directly
no test coverage detected