Inkscape
Vector Graphics Editor
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages Concepts
extract-uri.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
/*
5 * Authors: see git history
6 *
7 * Copyright (C) 2018 Authors
8 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
9 */
10#include <cstring>
11#include <glib.h>
12#include <optional>
13
14#include "extract-uri.h"
15
16// FIXME: kill this ugliness when we have a proper CSS parser
17
18// Functions as per 4.3.4 of CSS 2.1
19// http://www.w3.org/TR/CSS21/syndata.html#uri
20std::string extract_uri(char const *s, char const **endptr)
21{
22 std::string result;
23
24 if (!s)
25 return result;
26
27 gchar const *sb = s;
28 if ( strlen(sb) < 4 || strncmp(sb, "url", 3) != 0 ) {
29 return result;
30 }
31
32 sb += 3;
33
34 if ( endptr ) {
35 *endptr = nullptr;
36 }
37
38 // This first whitespace technically is not allowed.
39 // Just left in for now for legacy behavior.
40 while ( ( *sb == ' ' ) ||
41 ( *sb == '\t' ) )
42 {
43 sb++;
44 }
45
46 if ( *sb == '(' ) {
47 sb++;
48 while ( ( *sb == ' ' ) ||
49 ( *sb == '\t' ) )
50 {
51 sb++;
52 }
53
54 gchar delim = ')';
55 if ( (*sb == '\'' || *sb == '"') ) {
56 delim = *sb;
57 sb++;
58 }
59
60 if (!*sb) {
61 return result;
62 }
63
64 gchar const* se = sb;
65 while ( *se && (*se != delim) ) {
66 se++;
67 }
68
69 // we found the delimiter
70 if ( *se ) {
71 if ( delim == ')' ) {
72 if ( endptr ) {
73 *endptr = se + 1;
74 }
75
76 // back up for any trailing whitespace
77 while (se > sb && g_ascii_isspace(se[-1]))
78 {
79 se--;
80 }
81
82 result = std::string(sb, se);
83 } else {
84 gchar const* tail = se + 1;
85 while ( ( *tail == ' ' ) ||
86 ( *tail == '\t' ) )
87 {
88 tail++;
89 }
90 if ( *tail == ')' ) {
91 if ( endptr ) {
92 *endptr = tail + 1;
93 }
94 result = std::string(sb, se);
95 }
96 }
97 }
98 }
99
100 return result;
101}
102
103std::optional<std::string> try_extract_uri(const char* url) {
104 auto link = extract_uri(url);
105 return link.empty() ? std::nullopt : std::make_optional(link);
106}
107
108std::optional<std::string> try_extract_uri_id(const char *url) {
109 if (auto ret = try_extract_uri(url)) {
110 if (!ret->empty() && (*ret)[0] == '#') {
111 ret->erase(0, 1);
112 return ret;
113 }
114 }
115 return std::nullopt;
116}
117
118/*
119 Local Variables:
120 mode:c++
121 c-file-style:"stroustrup"
122 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
123 indent-tabs-mode:nil
124 fill-column:99
125 End:
126*/
127// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
Css & result
std::string extract_uri(char const *s, char const **endptr)
Parse functional URI notation, as per 4.3.4 of CSS 2.1.
std::optional< std::string > try_extract_uri_id(const char *url)
Try extracting the object id from "url(#obj_id)" string using extract_uri.
std::optional< std::string > try_extract_uri(const char *url)
Try extracting URI from "url(xyz)" string using extract_uri.
TODO: insert short description here.