[dali_2.3.20] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / visual-url.cpp
1 /*
2  * Copyright (c) 2021 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 namespace
30 {
31 VisualUrl::ProtocolType ResolveLocation(const std::string& url)
32 {
33   const char*    urlCStr = url.c_str();
34   const uint32_t length  = url.size();
35   if((length > 7) && urlCStr[5] == ':' && urlCStr[6] == '/' && urlCStr[7] == '/')
36   {
37     // https:// or enbuf://
38     const char hOre = tolower(urlCStr[0]);
39     const char tOrn = tolower(urlCStr[1]);
40     const char tOrb = tolower(urlCStr[2]);
41     const char pOru = tolower(urlCStr[3]);
42     const char sOrf = tolower(urlCStr[4]);
43     if(('h' == hOre) &&
44        ('t' == tOrn) &&
45        ('t' == tOrb) &&
46        ('p' == pOru) &&
47        ('s' == sOrf))
48     {
49       return VisualUrl::REMOTE;
50     }
51     if(('e' == hOre) &&
52        ('n' == tOrn) &&
53        ('b' == tOrb) &&
54        ('u' == pOru) &&
55        ('f' == sOrf))
56     {
57       return VisualUrl::BUFFER;
58     }
59   }
60   else if((length > 6) && urlCStr[4] == ':' && urlCStr[5] == '/' && urlCStr[6] == '/')
61   {
62     // http:// or dali://
63     const char hOrd = tolower(urlCStr[0]);
64     const char tOra = tolower(urlCStr[1]);
65     const char tOrl = tolower(urlCStr[2]);
66     const char pOri = tolower(urlCStr[3]);
67     if(('h' == hOrd) &&
68        ('t' == tOra) &&
69        ('t' == tOrl) &&
70        ('p' == pOri))
71     {
72       return VisualUrl::REMOTE;
73     }
74     if(('d' == hOrd) &&
75        ('a' == tOra) &&
76        ('l' == tOrl) &&
77        ('i' == pOri))
78     {
79       return VisualUrl::TEXTURE;
80     }
81   }
82   else if((length > 5) && urlCStr[3] == ':' && urlCStr[4] == '/' && urlCStr[5] == '/')
83   {
84     // ftp:// or ssh://
85     const char fOrs = tolower(urlCStr[0]);
86     const char tOrs = tolower(urlCStr[1]);
87     const char pOrh = tolower(urlCStr[2]);
88     if(('f' == fOrs) &&
89        ('t' == tOrs) &&
90        ('p' == pOrh))
91     {
92       return VisualUrl::REMOTE;
93     }
94     if(('s' == fOrs) &&
95        ('s' == tOrs) &&
96        ('h' == pOrh))
97     {
98       return VisualUrl::REMOTE;
99     }
100   }
101   return VisualUrl::LOCAL;
102 }
103
104 VisualUrl::Type ResolveType(const std::string& url)
105 {
106   // if only one char in string, can only be regular image
107   const std::size_t count = url.size();
108   if(count > 0)
109   {
110     // parsing from the end for better chance of early outs
111     enum
112     {
113       SUFFIX,
114       HASH,
115       HASH_DOT
116     } state                = SUFFIX;
117     char         SVG[4]    = {'g', 'v', 's', '.'};
118     char         GIF[4]    = {'f', 'i', 'g', '.'};
119     char         WEBP[5]   = {'p', 'b', 'e', 'w', '.'};
120     char         JSON[5]   = {'n', 'o', 's', 'j', '.'};
121     char         TVG[4]    = {'g', 'v', 't', '.'};
122     unsigned int svgScore  = 0;
123     unsigned int tvgScore  = 0;
124     unsigned int gifScore  = 0;
125     unsigned int webpScore = 0;
126     unsigned int jsonScore = 0;
127     int          index     = count;
128     while(--index >= 0)
129     {
130       const char        currentChar   = tolower(url[index]);
131       const std::size_t offsetFromEnd = count - index - 1u;
132       if((offsetFromEnd < sizeof(SVG)) && (currentChar == SVG[offsetFromEnd]))
133       {
134         // early out if SVG as can't be used in N patch for now
135         if(++svgScore == sizeof(SVG))
136         {
137           return VisualUrl::SVG;
138         }
139       }
140       if((offsetFromEnd < sizeof(TVG)) && (currentChar == TVG[offsetFromEnd]))
141       {
142         // early out if TVG as can't be used in N patch for now
143         if(++tvgScore == sizeof(TVG))
144         {
145           return VisualUrl::TVG;
146         }
147       }
148       if((offsetFromEnd < sizeof(GIF)) && (currentChar == GIF[offsetFromEnd]))
149       {
150         // early out if GIF as can't be used in N patch for now
151         if(++gifScore == sizeof(GIF))
152         {
153           return VisualUrl::GIF;
154         }
155       }
156       if((offsetFromEnd < sizeof(WEBP)) && (currentChar == WEBP[offsetFromEnd]))
157       {
158         // early out if WEBP as can't be used in N patch for now
159         if(++webpScore == sizeof(WEBP))
160         {
161           return VisualUrl::WEBP;
162         }
163       }
164       if((offsetFromEnd < sizeof(JSON)) && (currentChar == JSON[offsetFromEnd]))
165       {
166         // early out if JSON as can't be used in N patch for now
167         if(++jsonScore == sizeof(JSON))
168         {
169           return VisualUrl::JSON;
170         }
171       }
172       switch(state)
173       {
174         case SUFFIX:
175         {
176           if('.' == currentChar)
177           {
178             state = HASH;
179           }
180           break;
181         }
182         case HASH:
183         {
184           if(('#' == currentChar) || ('9' == currentChar))
185           {
186             state = HASH_DOT;
187           }
188           else
189           {
190             // early out, not a valid N/9-patch URL
191             return VisualUrl::REGULAR_IMAGE;
192           }
193           break;
194         }
195         case HASH_DOT:
196         {
197           if('.' == currentChar)
198           {
199             return VisualUrl::N_PATCH;
200           }
201           else
202           {
203             // early out, not a valid N/9-patch URL
204             return VisualUrl::REGULAR_IMAGE;
205           }
206           break;
207         }
208       }
209     }
210   }
211   // if we got here it is a regular image
212   return VisualUrl::REGULAR_IMAGE;
213 }
214
215 } // namespace
216
217 VisualUrl::VisualUrl()
218 : mUrl(),
219   mType(VisualUrl::REGULAR_IMAGE),
220   mLocation(VisualUrl::LOCAL)
221 {
222 }
223
224 VisualUrl::VisualUrl(const std::string& url)
225 : mUrl(url),
226   mType(VisualUrl::REGULAR_IMAGE),
227   mLocation(VisualUrl::LOCAL)
228 {
229   if(!url.empty())
230   {
231     mLocation = ResolveLocation(url);
232     if(VisualUrl::TEXTURE != mLocation && VisualUrl::BUFFER != mLocation)
233     {
234       // TEXTURE and BUFFER location url doesn't need type resolving, REGULAR_IMAGE is fine
235       mType = ResolveType(url);
236     }
237   }
238 }
239
240 VisualUrl::VisualUrl(const VisualUrl& url)
241 : mUrl(url.mUrl),
242   mType(url.mType),
243   mLocation(url.mLocation)
244 {
245 }
246
247 VisualUrl::~VisualUrl()
248 {
249 }
250
251 VisualUrl& VisualUrl::operator=(const VisualUrl& url)
252 {
253   if(&url != this)
254   {
255     mUrl      = url.mUrl;
256     mType     = url.mType;
257     mLocation = url.mLocation;
258   }
259   return *this;
260 }
261
262 const std::string& VisualUrl::GetUrl() const
263 {
264   return mUrl;
265 }
266
267 VisualUrl::Type VisualUrl::GetType() const
268 {
269   return mType;
270 }
271
272 VisualUrl::ProtocolType VisualUrl::GetProtocolType() const
273 {
274   return mLocation;
275 }
276
277 bool VisualUrl::IsValid() const
278 {
279   return mUrl.size() > 0u;
280 }
281
282 bool VisualUrl::IsLocalResource() const
283 {
284   return mLocation == VisualUrl::LOCAL;
285 }
286
287 bool VisualUrl::IsBufferResource() const
288 {
289   return mLocation == VisualUrl::BUFFER;
290 }
291
292 std::string VisualUrl::GetLocation() const
293 {
294   return GetLocation(mUrl);
295 }
296
297 std::string VisualUrl::CreateTextureUrl(const std::string& location)
298 {
299   return "dali://" + location;
300 }
301
302 std::string VisualUrl::CreateBufferUrl(const std::string& location)
303 {
304   return "enbuf://" + location;
305 }
306
307 VisualUrl::ProtocolType VisualUrl::GetProtocolType(const std::string& url)
308 {
309   return ResolveLocation(url);
310 }
311
312 std::string VisualUrl::GetLocation(const std::string& url)
313 {
314   const auto location = url.find("://");
315   if(std::string::npos != location)
316   {
317     return url.substr(location + 3u); // 3 characters forwards from the start of ://
318   }
319   return url;
320 }
321
322 } // namespace Internal
323
324 } // namespace Toolkit
325
326 } // namespace Dali