SERD_API uint8_t* serd_file_uri_parse(const uint8_t* uri, uint8_t** hostname) { const uint8_t* path = uri; if (hostname) { *hostname = NULL; } if (!strncmp((const char*)uri, "file://", 7)) { const uint8_t* auth = uri + 7; if (*auth == '/') { // No hostname path = auth; } else { // Has hostname if (!(path = (const uint8_t*)strchr((const char*)auth, '/'))) { return NULL; } if (hostname) { *hostname = (uint8_t*)calloc(1, path - auth + 1); memcpy(*hostname, auth, path - auth); } } } if (is_windows_path(path + 1)) { ++path; } SerdChunk chunk = { NULL, 0 }; for (const uint8_t* s = path; *s; ++s) { if (*s == '%') { if (*(s + 1) == '%') { serd_chunk_sink("%", 1, &chunk); ++s; } else if (is_digit(*(s + 1)) && is_digit(*(s + 2))) { const uint8_t code[3] = { *(s + 1), *(s + 2), 0 }; uint32_t num; sscanf((const char*)code, "%X", &num); const uint8_t c = num; serd_chunk_sink(&c, 1, &chunk); s += 2; } else { s += 2; // Junk escape, ignore } } else { serd_chunk_sink(s, 1, &chunk); } } return serd_chunk_sink_finish(&chunk); }
SERD_API uint8_t* serd_chunk_sink_finish(SerdChunk* stream) { serd_chunk_sink("", 1, stream); return (uint8_t*)stream->buf; }
SERD_API SerdNode serd_node_new_file_uri(const uint8_t* path, const uint8_t* hostname, SerdURI* out, bool escape) { const size_t path_len = strlen((const char*)path); const size_t hostname_len = hostname ? strlen((const char*)hostname) : 0; const bool evil = is_windows_path(path); size_t uri_len = 0; uint8_t* uri = NULL; if (path[0] == '/' || is_windows_path(path)) { uri_len = strlen("file://") + hostname_len + evil; uri = (uint8_t*)malloc(uri_len + 1); snprintf((char*)uri, uri_len + 1, "file://%s%s", hostname ? (const char*)hostname : "", evil ? "/" : ""); } SerdChunk chunk = { uri, uri_len }; for (size_t i = 0; i < path_len; ++i) { if (evil && path[i] == '\\') { serd_chunk_sink("/", 1, &chunk); } else if (path[i] == '%') { serd_chunk_sink("%%", 2, &chunk); } else if (!escape || is_uri_path_char(path[i])) { serd_chunk_sink(path + i, 1, &chunk); } else { char escape_str[4] = { '%', 0, 0, 0 }; snprintf(escape_str + 1, sizeof(escape_str) - 1, "%X", path[i]); serd_chunk_sink(escape_str, 3, &chunk); } } serd_chunk_sink_finish(&chunk); if (out) { serd_uri_parse(chunk.buf, out); } return serd_node_from_string(SERD_URI, chunk.buf); }
static LV2_Atom_Forge_Ref forge_sink(LV2_Atom_Forge_Sink_Handle handle, const void* buf, uint32_t size) { SerdChunk* chunk = (SerdChunk*)handle; const LV2_Atom_Forge_Ref ref = chunk->len + 1; serd_chunk_sink(buf, size, chunk); return ref; }