VLC 4.0.0-dev
Loading...
Searching...
No Matches
mrl_helpers.h
Go to the documentation of this file.
1/*****************************************************************************
2 * mrl_helpers.h
3 *****************************************************************************
4 * Copyright (C) 2016 VLC authors and VideoLAN
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
20
21#ifndef INPUT_MRL_HELPERS_H
22#define INPUT_MRL_HELPERS_H
23
24#include <string.h>
25#include <stdlib.h>
26
27#include <vlc_common.h>
28#include <vlc_memstream.h>
29#include <vlc_arrays.h>
30#include <vlc_url.h>
31
32/**
33 * \defgroup mrl_helpers MRL helpers
34 * \ingroup mrl
35 *
36 * Helper functions related to parsing, as well as generating, data
37 * related to the \link mrl MRL-specification\endlink.
38 *
39 * @{
40 * \file
41 **/
42
43/**
44 * Escape a fragment identifier for use within an MRL
45 *
46 * The function will generate a string that follows the \link mrl
47 * MRL-specification\endlink regarding \em fragment-identifiers.
48 *
49 * See the \link mrl MRL-specification\endlink for a detailed
50 * explanation of how `payload` will be escaped.
51 *
52 * \param[in] payload the data to escape.
53 * \return he created string on success, and NULL on error.
54 **/
55VLC_MALLOC static inline char *
56mrl_EscapeFragmentIdentifier( char const* payload )
57{
58 struct vlc_memstream mstream;
59
60#define RFC3986_SUBDELIMS "!" "$" "&" "'" "(" ")" \
61 "*" "+" "," ";" "="
62#define RFC3986_ALPHA "abcdefghijklmnopqrstuvwxyz" \
63 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
64#define RFC3986_DIGIT "0123456789"
65#define RFC3986_UNRESERVED RFC3986_ALPHA RFC3986_DIGIT "-" "." "_" "~"
66#define RFC3986_PCHAR RFC3986_UNRESERVED RFC3986_SUBDELIMS ":" "@"
67#define RFC3986_FRAGMENT RFC3986_PCHAR "/" "?"
68
69 if( vlc_memstream_open( &mstream ) )
70 return NULL;
71
72 for( char const* p = payload; *p; ++p )
73 {
74 vlc_memstream_printf( &mstream,
75 ( strchr( "!?", *p ) == NULL &&
76 strchr( RFC3986_FRAGMENT, *p ) ? "%c" : "%%%02hhx"), *p );
77 }
78
79#undef RFC3986_FRAGMENT
80#undef RFC3986_PCHAR
81#undef RFC3986_UNRESERVEd
82#undef RFC3986_DIGIT
83#undef RFC3986_ALPHA
84#undef RFC3986_SUBDELIMS
85
86 if( vlc_memstream_close( &mstream ) )
87 return NULL;
88
89 return mstream.ptr;
90}
91
92static inline char *
93mrl_AppendAnchorFragment( const char *anchor, char const *payload )
94{
95 struct vlc_memstream mstream;
96 if( vlc_memstream_open( &mstream ) )
97 return NULL;
98
99 if( anchor )
100 vlc_memstream_puts( &mstream, anchor );
101 else
102 vlc_memstream_putc( &mstream, '#' );
103
104 char *escaped = mrl_EscapeFragmentIdentifier( payload );
105 if( escaped == NULL )
106 {
107 if( !vlc_memstream_close( &mstream ) )
108 free( mstream.ptr );
109 return NULL;
110 }
111
112 vlc_memstream_puts( &mstream, "!+" );
113 vlc_memstream_puts( &mstream, escaped );
114 free( escaped );
115
116 if( vlc_memstream_close( &mstream ) )
117 return NULL;
118
119 return mstream.ptr;
120}
121
128
129static inline void
131{
132 for( size_t i = 0; i < vlc_array_count( &mrli->identifiers ); ++i )
133 free( vlc_array_item_at_index( &mrli->identifiers, i ) );
135 for( size_t i = 0; i < vlc_array_count( &mrli->volumes ); ++i )
136 free( vlc_array_item_at_index( &mrli->volumes, i ) );
137 vlc_array_clear( &mrli->volumes );
138}
139
140static inline void
141mrl_info_Init( struct mrl_info *mrli )
142{
143 vlc_array_init( &mrli->identifiers );
144 vlc_array_init( &mrli->volumes );
145 mrli->extra = NULL;
146}
147
148/**
149 * Split an \link mrl_technical_fragment MRL-fragment\endlink into identifiers
150 *
151 * Function used to split the fragment-data (also referred to as
152 * anchor-data) into an array containing each of the files specified.
153 *
154 * See the \link mrl MRL-specification\endlink for detailed
155 * information regarding how `payload` will be interpreted.
156 *
157 * \warning On success, the caller has ownership of the contents of *out_items
158 * which means that it is responsible for freeing the individual
159 * elements, as well as cleaning the array itself.
160 *
161 * \param[out] out_items storage for a vlc_array_t that will contain the
162 * parsed identifiers on success.
163 * \param[out] out_extra `*out_extra` will point to any remaining data (if any)
164 * \param[in] payload the data to parse
165 * \return VLC_SUCCESS on success, an error-code on failure
166 **/
167static inline int
169 char const* payload )
170{
171 while( strncmp( payload, "!/", 2 ) == 0 )
172 {
173 payload += 2;
174
175 int len = strcspn( payload, "!?" );
176 char* decoded = strndup( payload, len );
177
178 if( unlikely( !decoded ) || !vlc_uri_decode( decoded ) )
179 goto error;
180
181 if( vlc_array_append( &mrli->identifiers, decoded ) )
182 {
183 free( decoded );
184 goto error;
185 }
186 payload += len;
187 }
188
189 while( strncmp( payload, "!+", 2 ) == 0 )
190 {
191 payload += 2;
192
193 int len = strcspn( payload, "!?" );
194 char* decoded = strndup( payload, len );
195
196 if( unlikely( !decoded ) || !vlc_uri_decode( decoded ) )
197 goto error;
198
199 if( vlc_array_append( &mrli->volumes, decoded ) )
200 {
201 free( decoded );
202 goto error;
203 }
204 payload += len;
205 }
206
207 if( *payload )
208 {
209 if( *payload == '!' )
210 goto error;
211
212 if( *payload == '?' && vlc_array_count( &mrli->identifiers ) )
213 ++payload;
214
215 mrli->extra = payload;
216 }
217
218 return VLC_SUCCESS;
219
220error:
221 return VLC_EGENERIC;
222}
223
224/** @} */
225
226#endif /* include-guard */
#define p(t)
#define unlikely(p)
Predicted false condition.
Definition vlc_common.h:246
#define VLC_MALLOC
Definition vlc_common.h:157
#define VLC_EGENERIC
Unspecified error.
Definition vlc_common.h:480
#define VLC_SUCCESS
No error.
Definition vlc_common.h:478
int vlc_memstream_open(struct vlc_memstream *ms)
Initializes a byte stream object.
Definition memstream.c:119
int vlc_memstream_printf(struct vlc_memstream *ms, const char *fmt,...)
Appends a formatted string to a byte stream.
Definition memstream.c:214
int vlc_memstream_putc(struct vlc_memstream *ms, int c)
Appends a single byte to a byte stream.
Definition memstream.c:171
int() vlc_memstream_puts(struct vlc_memstream *ms, const char *str)
Appends a nul-terminated string to a byte stream.
Definition memstream.c:176
int vlc_memstream_close(struct vlc_memstream *ms)
Closes a byte stream object.
Definition memstream.c:134
static void mrl_info_Clean(struct mrl_info *mrli)
Definition mrl_helpers.h:130
static void mrl_info_Init(struct mrl_info *mrli)
Definition mrl_helpers.h:141
static char * mrl_EscapeFragmentIdentifier(char const *payload)
Escape a fragment identifier for use within an MRL.
Definition mrl_helpers.h:56
static char * mrl_AppendAnchorFragment(const char *anchor, char const *payload)
Definition mrl_helpers.h:93
static int mrl_FragmentSplit(struct mrl_info *mrli, char const *payload)
Split an MRL-fragment into identifiers.
Definition mrl_helpers.h:168
char * vlc_uri_decode(char *str)
Decodes an URI component in place.
Definition url.c:74
#define RFC3986_FRAGMENT
Definition mrl_helpers.h:123
vlc_array_t volumes
Definition mrl_helpers.h:125
vlc_array_t identifiers
Definition mrl_helpers.h:124
char const * extra
Definition mrl_helpers.h:126
Definition vlc_arrays.h:259
In-memory stream object.
Definition vlc_memstream.h:42
char * ptr
Buffer start address.
Definition vlc_memstream.h:48
This file defines functions, structures and macros for handling arrays in vlc.
static int vlc_array_append(vlc_array_t *ar, void *elem)
Definition vlc_arrays.h:335
static void vlc_array_init(vlc_array_t *p_array)
Definition vlc_arrays.h:264
static void vlc_array_clear(vlc_array_t *p_array)
Definition vlc_arrays.h:270
#define vlc_array_item_at_index(ar, idx)
Definition vlc_arrays.h:283
static size_t vlc_array_count(const vlc_array_t *p_array)
Definition vlc_arrays.h:277
This file is a collection of common definitions and types.
char * strndup(const char *, size_t)