ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
mdl_extract.c
Go to the documentation of this file.
1
10#include "mdl_extract.h"
11
12#include <stdio.h>
13#include <string.h>
14
15#include "ra8_attributes.h"
16
18typedef enum : uint16_t {
21
23
40RA8_INTERNAL static bool internal_authority_of(const char* base, char* auth, size_t cap)
41{
42 const char* sep = strstr(base, "://");
43 if (sep == nullptr) {
44 return false;
45 }
46 const char* host = sep + (sizeof("://") - 1U);
47 const char* end = strchr(host, '/');
48 const size_t len = (end == nullptr) ? strlen(base) : (size_t)(end - base);
49 if (len + 1U > cap) {
50 return false;
51 }
52 memcpy(auth, base, len);
53 auth[len] = '\0';
54 return true;
55}
56
74RA8_INTERNAL static bool
75internal_resolve_scheme_rel(const char* base, const char* raw, char* out, size_t out_cap)
76{
77 const char* colon = strstr(base, "://");
78 const size_t slen = (size_t)(colon - base);
79 if ((slen + 1U + strlen(raw) + 1U) > out_cap) {
80 return false;
81 }
82 memcpy(out, base, slen);
83 out[slen] = ':';
84 memcpy(out + slen + 1U, raw, strlen(raw) + 1U);
85 return true;
86}
87
105RA8_INTERNAL static bool
106internal_resolve_root_rel(const char* auth, const char* raw, char* out, size_t out_cap)
107{
108 /* The snprintf return is the truncation test: n >= out_cap is exactly the
109 * over-long case a separate strlen guard would reject, and using the return
110 * (rather than discarding it) is also what keeps -Wformat-truncation quiet.
111 */
112 const int n = snprintf(out, out_cap, "%s%s", auth, raw);
113 return (n >= 0) && ((size_t)n < out_cap);
114}
115
134RA8_INTERNAL static bool internal_resolve_path_rel(const char* base,
135 const char* auth,
136 const char* raw,
137 char* out,
138 size_t out_cap)
139{
140 const char* q = strpbrk(base, "?#");
141 const size_t blen = (q == nullptr) ? strlen(base) : (size_t)(q - base);
142 size_t slash = 0U;
143 for (size_t i = 0U; i < blen; ++i) {
144 if (base[i] == '/') {
145 slash = i;
146 }
147 }
148 if (slash < strlen(auth)) {
149 /* As in internal_resolve_root_rel: the snprintf return is the truncation test, and
150 * using it keeps -Wformat-truncation quiet where a discarded return does
151 * not. */
152 const int n = snprintf(out, out_cap, "%s/%s", auth, raw);
153 return (n >= 0) && ((size_t)n < out_cap);
154 }
155 if ((slash + 1U + strlen(raw) + 1U) > out_cap) {
156 return false;
157 }
158 memcpy(out, base, slash + 1U);
159 memcpy(out + slash + 1U, raw, strlen(raw) + 1U);
160 return true;
161}
162
164bool mdl_extract_resolve_url(const char* base, const char* raw, char* out, size_t out_cap)
165{
166 if ((base == nullptr) || (raw == nullptr) || (out == nullptr) || (out_cap == 0U)) {
167 return false;
168 }
169 while ((*raw == ' ') || (*raw == '\t') || (*raw == '\n') || (*raw == '\r')) {
170 ++raw;
171 }
172 if ((raw[0] == '\0') || (raw[0] == '#') || (strncmp(raw, "data:", sizeof("data:") - 1U) == 0)) {
173 return false;
174 }
175 if ((strncmp(raw, "http://", sizeof("http://") - 1U) == 0) ||
176 (strncmp(raw, "https://", sizeof("https://") - 1U) == 0)) {
177 return internal_copy_fits(out, out_cap, raw);
178 }
179
180 char auth[k_authority_max];
181 if (!internal_authority_of(base, auth, sizeof(auth))) {
182 return false;
183 }
184 if ((raw[0] == '/') && (raw[1] == '/')) {
185 return internal_resolve_scheme_rel(base, raw, out, out_cap);
186 }
187 if (raw[0] == '/') {
188 return internal_resolve_root_rel(auth, raw, out, out_cap);
189 }
190 return internal_resolve_path_rel(base, auth, raw, out, out_cap);
191}
192
208RA8_INTERNAL static bool internal_already_have(const mdl_url_list_t* list, const char* url)
209{
210 for (size_t i = 0U; i < list->count; ++i) {
211 if (strcmp(list->urls[i], url) == 0) {
212 return true;
213 }
214 }
215 return false;
216}
217
240RA8_INTERNAL static ra8_err_t internal_emit_tag_url(const char* base_url,
241 const char* attr1,
242 const char* attr2,
243 const char* keep,
244 const char* tag,
245 size_t tag_len,
246 mdl_url_list_t* out)
247{
248 char raw[k_mdl_url_max];
249 bool got = internal_find_attr_value(tag, tag_len, attr1, raw, sizeof(raw));
250 if (!got && (attr2 != nullptr)) {
251 got = internal_find_attr_value(tag, tag_len, attr2, raw, sizeof(raw));
252 }
253 if (!got) {
254 return k_ra8_ok;
255 }
256 char abs[k_mdl_url_max];
257 if (!mdl_extract_resolve_url(base_url, raw, abs, sizeof(abs)) ||
259 return k_ra8_ok;
260 }
261 if (out->count >= (size_t)k_mdl_max_urls) {
262 return k_ra8_err_no_mem;
263 }
264 (void)internal_copy_fits(out->urls[out->count], k_mdl_url_max, abs);
265 out->count++;
266 return k_ra8_ok;
267}
268
293 size_t html_len,
294 const char* base_url,
295 const char* tagname,
296 const char* attr1,
297 const char* attr2,
298 const char* keep,
299 mdl_url_list_t* out)
300{
301 if ((html == nullptr) || (base_url == nullptr) || (attr1 == nullptr) || (out == nullptr)) {
303 }
304 out->count = 0U;
305 const size_t name_len = strlen(tagname);
306
307 size_t pos = 0U;
308 while (pos < html_len) {
309 const char* tag = internal_find_ci(html + pos, html_len - pos, tagname);
310 if (tag == nullptr) {
311 break;
312 }
313 const size_t tag_off = (size_t)(tag - html);
314 const size_t after = tag_off + name_len;
315 if ((after < html_len) && !internal_is_name_end(html[after])) {
316 pos = tag_off + 1U; /* false match, e.g. "<article" while seeking "<a" */
317 continue;
318 }
319 const char* gt = memchr(tag, '>', html_len - tag_off);
320 const size_t tag_len = (gt == nullptr) ? (html_len - tag_off) : (size_t)(gt - tag);
321 if (internal_emit_tag_url(base_url, attr1, attr2, keep, tag, tag_len, out) ==
323 return k_ra8_err_no_mem;
324 }
325 pos = tag_off + ((gt == nullptr) ? tag_len : (tag_len + 1U));
326 }
327 return k_ra8_ok;
328}
329
331 size_t html_len,
332 const char* base_url,
333 const char* prefer_attr,
334 const char* url_contains,
335 mdl_url_list_t* out)
336{
337 const char* p1 = (prefer_attr == nullptr) ? "data-src" : prefer_attr;
338 const char* p2 = (strcmp(p1, "data-src") == 0) ? "src" : "data-src";
339 return internal_scan_tags(html, html_len, base_url, "<img", p1, p2, url_contains, out);
340}
341
343 size_t html_len,
344 const char* base_url,
345 const char* href_contains,
346 mdl_url_list_t* out)
347{
348 return internal_scan_tags(html, html_len, base_url, "<a", "href", nullptr, href_contains, out);
349}
ra8_err_t mdl_extract_anchors(const char *html, size_t html_len, const char *base_url, const char *href_contains, mdl_url_list_t *out)
Scan html for <a href> links, resolved to absolute form.
static bool internal_resolve_scheme_rel(const char *base, const char *raw, char *out, size_t out_cap)
Resolve a scheme-relative ("//host/...") URL against base.
Definition mdl_extract.c:75
static bool internal_resolve_root_rel(const char *auth, const char *raw, char *out, size_t out_cap)
Resolve a root-relative ("/path") URL against authority auth.
ra8_err_t mdl_extract_images(const char *html, size_t html_len, const char *base_url, const char *prefer_attr, const char *url_contains, mdl_url_list_t *out)
Scan html for <img> image URLs, resolved to absolute form.
static ra8_err_t internal_emit_tag_url(const char *base_url, const char *attr1, const char *attr2, const char *keep, const char *tag, size_t tag_len, mdl_url_list_t *out)
Read attr1 (or attr2) from one tag, resolve+filter, append.
static bool internal_resolve_path_rel(const char *base, const char *auth, const char *raw, char *out, size_t out_cap)
Resolve a path-relative URL against base (authority auth).
bool mdl_extract_resolve_url(const char *base, const char *raw, char *out, size_t out_cap)
Resolve raw (possibly relative) against base into out.
static bool internal_authority_of(const char *base, char *auth, size_t cap)
Extract "scheme://host" from base into auth (NUL-terminated).
Definition mdl_extract.c:40
static bool internal_already_have(const mdl_url_list_t *list, const char *url)
True if url is already present in list.
mdl_scan_limits_t
Local scan/resolve limits.
Definition mdl_extract.c:18
@ k_authority_max
Max bytes of "scheme://host" prefix.
Definition mdl_extract.c:19
static ra8_err_t internal_scan_tags(const char *html, size_t html_len, const char *base_url, const char *tagname, const char *attr1, const char *attr2, const char *keep, mdl_url_list_t *out)
Shared scanner for <img>/<a>: emit each tag's resolved URL.
Extract image URLs and anchor links from an HTML page (v1 scanner).
@ k_mdl_url_max
Max bytes per URL, including the NUL.
Definition mdl_extract.h:25
@ k_mdl_max_urls
Max URLs captured per page (chapters or images).
Definition mdl_extract.h:24
Shared bounded markup lexer helpers for media extraction units.
static bool internal_find_attr_value(const char *tag, size_t tag_len, const char *attr, char *out, size_t out_cap)
Read the value of attr inside one tag [tag, tag+tag_len).
static bool internal_copy_fits(char *out, size_t out_cap, const char *src)
Copy src into out if it fits (incl.
static const char * internal_find_ci(const char *hay, size_t hay_len, const char *needle)
Case-insensitive search for needle in [hay, hay+hay_len).
static bool internal_contains_ok(const char *url, const char *needle)
True if needle is empty/NULL or a substring of url.
static bool internal_is_name_end(char c)
True if c terminates a tag name (so "<a" != "<article").
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
@ k_ra8_err_no_mem
Static buffer exhausted (no dynamic memory on this project).
Definition ra8_err.h:142
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
int strncmp(const char *s1, const char *s2, size_t n)
Compare two strings up to a specified length.
void * memchr(const void *s, int c, size_t n)
Locate a byte in a memory area.
int strcmp(const char *s1, const char *s2)
Compare two null-terminated strings.
size_t strlen(const char *s)
Calculate string length.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
char * strstr(const char *haystack, const char *needle)
Locate substring in string.
char * strchr(const char *s, int c)
Locate first occurrence of character in string.
int abs(int j)
Compute absolute value of integer.
Bounded list of absolute URLs found on a page.
Definition mdl_extract.h:29
char urls[k_mdl_max_urls][k_mdl_url_max]
Absolute, NUL-terminated.
Definition mdl_extract.h:30
size_t count
Number of valid entries.
Definition mdl_extract.h:31