demux: adaptive: fixup AnyURI
[vlc.git] / modules / demux / adaptive / playlist / Url.cpp
1 /*
2  * Url.cpp
3  *****************************************************************************
4  * Copyright (C) 2014 - VideoLAN and VLC Authors
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
8  * by 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 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23
24 #include "Url.hpp"
25 #include "BaseRepresentation.h"
26 #include "SegmentTemplate.h"
27
28 #include <vlc_url.h>
29
30 using namespace adaptive::playlist;
31
32 Url::Url()
33 {
34 }
35
36 Url::Url(const Component & comp)
37 {
38     prepend(comp);
39 }
40
41 Url::Url(const std::string &str)
42 {
43     prepend(Component(str));
44 }
45
46 bool Url::hasScheme() const
47 {
48     if(components.empty())
49         return false;
50
51     return components[0].b_scheme;
52 }
53
54 bool Url::empty() const
55 {
56     return components.empty();
57 }
58
59 Url & Url::prepend(const Component & comp)
60 {
61     components.insert(components.begin(), comp);
62     return *this;
63 }
64
65 Url & Url::append(const Component & comp)
66 {
67     if(!components.empty() && !components.back().b_dir)
68         components.pop_back();
69     components.push_back(comp);
70     return *this;
71 }
72
73 Url & Url::prepend(const Url &url)
74 {
75     components.insert(components.begin(), url.components.begin(), url.components.end());
76     return *this;
77 }
78
79 Url & Url::append(const Url &url)
80 {
81     if(!components.empty() && url.components.front().b_absolute)
82     {
83         if(components.front().b_scheme)
84         {
85             while(components.size() > 1)
86                 components.pop_back();
87             std::string scheme(components.front().component);
88             std::size_t schemepos = scheme.find_first_of("://");
89             if(schemepos != std::string::npos)
90             {
91                 std::size_t pathpos = scheme.find_first_of('/', schemepos + 3);
92                 if(pathpos != std::string::npos)
93                     components.front().component = scheme.substr(0, pathpos);
94                 /* otherwise should be domain only */
95             }
96         }
97     }
98
99     if(!components.empty() && !components.back().b_dir)
100         components.pop_back();
101     components.insert(components.end(), url.components.begin(), url.components.end());
102     return *this;
103 }
104
105 std::string Url::toString() const
106 {
107     return toString(0, NULL);
108 }
109
110 std::string Url::toString(size_t index, const BaseRepresentation *rep) const
111 {
112     std::string ret;
113     std::vector<Component>::const_iterator it;
114
115     for(it = components.begin(); it != components.end(); ++it)
116     {
117         std::string part;
118         const Component *comp = & (*it);
119         if(rep)
120             part = rep->contextualize(index, comp->component, comp->templ);
121         else
122             part = comp->component;
123
124         if( ret.empty() )
125             ret = part;
126         else
127         {
128             char *psz_fixup = vlc_uri_fixup( part.c_str() );
129             char *psz_resolved = vlc_uri_resolve( ret.c_str(),
130                                                   psz_fixup ? psz_fixup : part.c_str() );
131             free(psz_fixup);
132             if( psz_resolved )
133             {
134                 ret = std::string( psz_resolved );
135                 free( psz_resolved );
136             }
137         }
138     }
139
140     return ret;
141 }
142
143 Url::Component::Component(const std::string & str, const BaseSegmentTemplate *templ_)
144  : component(str), templ(templ_), b_scheme(false), b_dir(false), b_absolute(false)
145 {
146     if(!component.empty())
147     {
148         b_dir = (component[component.length()-1]=='/');
149         b_scheme = (component.find_first_of("://") == (component.find_first_of('/') - 1));
150         b_absolute = (component[0] =='/');
151     }
152 }