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