[dali_1.9.31] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / visual-url.cpp
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 // CLASS HEADER
18 #include <dali-toolkit/internal/visuals/visual-url.h>
19
20 // EXTERNAL HEADERS
21 #include <cstring> // for toupper()
22
23 namespace Dali
24 {
25 namespace Toolkit
26 {
27 namespace Internal
28 {
29
30 namespace
31 {
32
33 VisualUrl::ProtocolType ResolveLocation( const std::string& url )
34 {
35   const char* urlCStr = url.c_str();
36   const uint32_t length = url.size();
37   if( ( length > 7 ) && urlCStr[5] == ':' && urlCStr[6] == '/' && urlCStr[7] == '/' )
38   {
39     // https://
40     if( ( 'h' == tolower( urlCStr[0] ) )&&
41         ( 't' == tolower( urlCStr[1] ) )&&
42         ( 't' == tolower( urlCStr[2] ) )&&
43         ( 'p' == tolower( urlCStr[3] ) )&&
44         ( 's' == tolower( urlCStr[4] ) ) )
45     {
46       return VisualUrl::REMOTE;
47     }
48   }
49   else if( ( length > 6 ) && urlCStr[4] == ':' && urlCStr[5] == '/' && urlCStr[6] == '/' )
50   {
51     // http:// or dali://
52     const char hOrd = tolower( urlCStr[0] );
53     const char tOra = tolower( urlCStr[1] );
54     const char tOrl = tolower( urlCStr[2] );
55     const char pOri = tolower( urlCStr[3] );
56     if( ( 'h' == hOrd )&&
57         ( 't' == tOra )&&
58         ( 't' == tOrl )&&
59         ( 'p' == pOri ) )
60     {
61       return VisualUrl::REMOTE;
62     }
63     if( ( 'd' == hOrd )&&
64         ( 'a' == tOra )&&
65         ( 'l' == tOrl )&&
66         ( 'i' == pOri ) )
67     {
68       return VisualUrl::TEXTURE;
69     }
70   }
71   else if( ( length > 5 ) && urlCStr[3] == ':' && urlCStr[4] == '/' && urlCStr[5] == '/' )
72   {
73     // ftp:// or ssh://
74     const char fOrS = tolower( urlCStr[0] );
75     if( ( 'f' == fOrS )||( 's' == fOrS ) )
76     {
77       const char tOrs = tolower( urlCStr[1] );
78       if( ( 't' == tOrs )||( 's' == tOrs ) )
79       {
80         const char pOrh = tolower( urlCStr[2] );
81         if( ( 'p' == pOrh )||( 'h' == pOrh ) )
82         {
83           return VisualUrl::REMOTE;
84         }
85       }
86     }
87   }
88   return VisualUrl::LOCAL;
89 }
90
91
92 VisualUrl::Type ResolveType( const std::string& url )
93 {
94   // if only one char in string, can only be regular image
95   const std::size_t count = url.size();
96   if( count > 0 )
97   {
98     // parsing from the end for better chance of early outs
99     enum { SUFFIX, HASH, HASH_DOT } state = SUFFIX;
100     char SVG[ 4 ] = { 'g', 'v', 's', '.' };
101     char GIF[ 4 ] = { 'f', 'i', 'g', '.' };
102     char WEBP[ 5 ] = { 'p', 'b', 'e', 'w', '.' };
103     char JSON[ 5 ] = { 'n', 'o', 's', 'j', '.' };
104     unsigned int svgScore = 0;
105     unsigned int gifScore = 0;
106     unsigned int webpScore = 0;
107     unsigned int jsonScore = 0;
108     int index = count;
109     while( --index >= 0 )
110     {
111       const char currentChar = tolower( url[ index ] );
112       const std::size_t offsetFromEnd = count - index - 1u;
113       if( ( offsetFromEnd < sizeof(SVG) )&&( currentChar == SVG[ offsetFromEnd ] ) )
114       {
115         // early out if SVG as can't be used in N patch for now
116         if( ++svgScore == sizeof(SVG) )
117         {
118           return VisualUrl::SVG;
119         }
120       }
121       if( ( offsetFromEnd < sizeof(GIF) )&&( currentChar == GIF[ offsetFromEnd ] ) )
122       {
123         // early out if GIF as can't be used in N patch for now
124         if( ++gifScore == sizeof(GIF) )
125         {
126           return VisualUrl::GIF;
127         }
128       }
129       if( ( offsetFromEnd < sizeof(WEBP) )&&( currentChar == WEBP[ offsetFromEnd ] ) )
130       {
131         // early out if WEBP as can't be used in N patch for now
132         if( ++webpScore == sizeof(WEBP) )
133         {
134           return VisualUrl::WEBP;
135         }
136       }
137       if( ( offsetFromEnd < sizeof(JSON) )&&( currentChar == JSON[ offsetFromEnd ] ) )
138       {
139         // early out if JSON as can't be used in N patch for now
140         if( ++jsonScore == sizeof(JSON) )
141         {
142           return VisualUrl::JSON;
143         }
144       }
145       switch( state )
146       {
147         case SUFFIX:
148         {
149           if( '.' == currentChar )
150           {
151             state = HASH;
152           }
153           break;
154         }
155         case HASH:
156         {
157           if( ( '#' == currentChar ) || ( '9' == currentChar ) )
158           {
159             state = HASH_DOT;
160           }
161           else
162           {
163             // early out, not a valid N/9-patch URL
164             return VisualUrl::REGULAR_IMAGE;
165           }
166           break;
167         }
168         case HASH_DOT:
169         {
170           if( '.' == currentChar )
171           {
172             return VisualUrl::N_PATCH;
173           }
174           else
175           {
176             // early out, not a valid N/9-patch URL
177             return VisualUrl::REGULAR_IMAGE;
178           }
179           break;
180         }
181       }
182     }
183   }
184   // if we got here it is a regular image
185   return VisualUrl::REGULAR_IMAGE;
186 }
187
188 }
189
190
191 VisualUrl::VisualUrl()
192 : mUrl(),
193   mType( VisualUrl::REGULAR_IMAGE ),
194   mLocation( VisualUrl::LOCAL )
195 {
196 }
197
198 VisualUrl::VisualUrl( const std::string& url )
199 : mUrl( url ),
200   mType( VisualUrl::REGULAR_IMAGE ),
201   mLocation( VisualUrl::LOCAL )
202 {
203   if( ! url.empty() )
204   {
205     mLocation = ResolveLocation( url );
206     if( VisualUrl::TEXTURE != mLocation )
207     {
208       // TEXTURE location url doesn't need type resolving, REGULAR_IMAGE is fine
209       mType = ResolveType( url );
210     }
211   }
212 }
213
214 VisualUrl::VisualUrl( const VisualUrl& url )
215 : mUrl( url.mUrl ),
216   mType( url.mType ),
217   mLocation( url.mLocation )
218 {
219 }
220
221 VisualUrl& VisualUrl::operator=( const VisualUrl& url )
222 {
223   if( &url != this )
224   {
225     mUrl = url.mUrl;
226     mType = url.mType;
227     mLocation = url.mLocation;
228   }
229   return *this;
230 }
231
232 const std::string& VisualUrl::GetUrl() const
233 {
234   return mUrl;
235 }
236
237 VisualUrl::Type VisualUrl::GetType() const
238 {
239   return mType;
240 }
241
242 VisualUrl::ProtocolType VisualUrl::GetProtocolType() const
243 {
244   return mLocation;
245 }
246
247 bool VisualUrl::IsValid() const
248 {
249   return mUrl.size() > 0u;
250 }
251
252 bool VisualUrl::IsLocalResource() const
253 {
254   return mLocation == VisualUrl::LOCAL;
255 }
256
257 std::string VisualUrl::GetLocation() const
258 {
259   const auto location = mUrl.find( "://" );
260   if( std::string::npos != location )
261   {
262     return mUrl.substr( location + 3u ); // 3 characters forwards from the start of ://
263   }
264   return mUrl;
265 }
266
267 std::string VisualUrl::CreateTextureUrl( const std::string& location )
268 {
269   return "dali://" + location;
270 }
271
272 } // Internal
273
274 } // Toolkit
275
276 } // Dali