1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "data_uri_utils.h"
16 
17 #include <memory>
18 #include <regex>
19 #include <vector>
20 
21 #include "securec.h"
22 
23 namespace OHOS {
24 namespace AppExecFwk {
25 namespace {
26 const string EMPTY = "";
27 const std::regex INTEGER_REGEX("^[-+]?([0-9]+)([.]([0-9]+))?$");
28 const int BUFFER_LEN = 64;
29 const char *SEPARATOR = "/";
30 };  // namespace
31 
32 /**
33  * @brief Default constructor of DataUriUtils class
34  * @return None
35  */
DataUriUtils()36 DataUriUtils::DataUriUtils()
37 {}
38 
39 /**
40  * @brief Default deconstructor of DataUriUtils class
41  * @return None
42  */
~DataUriUtils()43 DataUriUtils::~DataUriUtils()
44 {}
45 
46 /**
47  * @brief Attaches the given ID to the end of the path component of the given URI.
48  * @param dataUri based on RFC 2396( Uniform Resource Identifier ).
49  * @param id
50  * @return Uri( scheme://authority/path1/path2/path3/updateIDNumber....)
51  */
AttachId(const Uri & dataUri,long long id)52 Uri DataUriUtils::AttachId(const Uri &dataUri, long long id)
53 {
54     // 1. get Path
55     string path = const_cast<Uri &>(dataUri).GetPath();
56     if (path.empty()) {
57         return dataUri;
58     }
59 
60     string uriString = dataUri.ToString();
61 
62     std::vector<string> pathVector;
63     const_cast<Uri &>(dataUri).GetPathSegments(pathVector);
64     if (pathVector.empty()) {
65         return dataUri;
66     }
67     string lastPath = pathVector[pathVector.size() - 1];
68 
69     char longBuffer[BUFFER_LEN] = {0};
70 
71     int ret = sprintf_s(longBuffer, sizeof(longBuffer), "%lld", id);
72     if (ret == -1) {
73         return dataUri;
74     }
75     // new path string (lastPath+SEPARATOR+number)
76     string newLastPath("");
77 
78     newLastPath = lastPath + string(SEPARATOR) + string(longBuffer);
79 
80     // find "/+lastPath"
81     string tempLastPath = string(SEPARATOR) + lastPath;
82     auto lastPathPos = uriString.rfind(tempLastPath);
83 
84     uriString.replace(lastPathPos + 1, tempLastPath.size() - 1, newLastPath.c_str());
85     return Uri(uriString);
86 }
87 
88 /**
89  * @brief Obtains the ID attached to the end of the path component of the given URI.
90  * @param dataUri based on RFC 2396( Uniform Resource Identifier ).
91  * @return long ID
92  */
GetId(const Uri & dataUri)93 long long DataUriUtils::GetId(const Uri &dataUri)
94 {
95     // 1. get Path
96     string path = const_cast<Uri &>(dataUri).GetPath();
97     if (path.empty()) {
98         return -1;
99     }
100     std::vector<string> pathVector;
101     const_cast<Uri &>(dataUri).GetPathSegments(pathVector);
102     if (pathVector.empty()) {
103         return -1;
104     }
105     string lastPath = pathVector[pathVector.size() - 1];
106     if (!IsNumber(lastPath)) {
107         return -1;
108     }
109     return std::atoll(lastPath.c_str());
110 }
111 
112 /**
113  * @brief Deletes the ID from the end of the path component of the given URI.
114  * @param dataUri based on RFC 2396( Uniform Resource Identifier ).
115  * @return long ID
116  */
DeleteId(const Uri & dataUri)117 Uri DataUriUtils::DeleteId(const Uri &dataUri)
118 {
119     return UriUpateLastPath(dataUri, EMPTY);
120 }
121 
122 /**
123  * @brief Updates the ID in the specified dataUri
124  * @param dataUri based on RFC 2396( Uniform Resource Identifier ).
125  * @param id indiates Update attached to the end of the path component of the given URI
126  * @return Uri return is the URI after path is updated
127  */
UpdateId(const Uri & dataUri,long long id)128 Uri DataUriUtils::UpdateId(const Uri &dataUri, long long id)
129 {
130     char longBuffer[BUFFER_LEN] = {0};
131     int ret = sprintf_s(longBuffer, sizeof(longBuffer), "%lld", id);
132     if (ret == -1) {
133         return dataUri;
134     }
135 
136     string newLastPath("");
137     newLastPath = string(longBuffer);
138 
139     return UriUpateLastPath(dataUri, newLastPath);
140 }
141 
142 /**
143  * @brief Does the end path of the path component of the given URI have an ID attached to it?
144  * @param dataUri based on RFC 2396( Uniform Resource Identifier ).
145  * @return bool
146  */
IsAttachedId(const Uri & dataUri)147 bool DataUriUtils::IsAttachedId(const Uri &dataUri)
148 {
149     // 1. get Path
150     string path = const_cast<Uri &>(dataUri).GetPath();
151     if (path.empty()) {
152         return false;
153     }
154 
155     std::vector<string> pathVector;
156     const_cast<Uri &>(dataUri).GetPathSegments(pathVector);
157     if (pathVector.empty()) {
158         return false;
159     }
160     string lastPath = pathVector[pathVector.size() - 1];
161 
162     return IsNumber(lastPath);
163 }
164 
165 /**
166  * @brief Determine whether the string content is a numeric string
167  * @param str indicates stirng.
168  * @return bool
169  */
IsNumber(const string & str)170 bool DataUriUtils::IsNumber(const string &str)
171 {
172     return std::regex_match(str, INTEGER_REGEX);
173 }
174 
175 /**
176  * @brief Determine whether the string content is a numeric string
177  * @param dataUri indicates Uri object
178    scheme://authority/path/aaa?query/#fragment
179  * @return Uri return is the URI after path is updated
180  */
UriUpateLastPath(const Uri & dataUri,const string & updateLastPath)181 Uri DataUriUtils::UriUpateLastPath(const Uri &dataUri, const string &updateLastPath)
182 {
183     std::string strUpdateLastPath;
184 
185     if (updateLastPath.size() > 0) {
186         strUpdateLastPath = SEPARATOR + updateLastPath;
187     }
188 
189     // 1. get Path
190     string path = const_cast<Uri &>(dataUri).GetPath();
191     if (path.empty()) {
192         return dataUri;
193     }
194 
195     std::vector<string> pathVector;
196     const_cast<Uri &>(dataUri).GetPathSegments(pathVector);
197     if (pathVector.empty()) {
198         return dataUri;
199     }
200     string lastPath = pathVector[pathVector.size() - 1];
201     if (!IsNumber(lastPath)) {
202         return dataUri;
203     }
204 
205     string uriString = dataUri.ToString();
206     // find "/+lastPath"
207     int lastPathPos = (int)uriString.rfind(string(SEPARATOR) + lastPath);
208     if (lastPathPos == -1) {
209         return dataUri;
210     }
211 
212     // replace "/lastpath"==>""
213     uriString.replace(lastPathPos, lastPath.size() + 1, strUpdateLastPath);
214 
215     return Uri(uriString);
216 }
217 }  // namespace AppExecFwk
218 }  // namespace OHOS
219