Merge "[Systeminfo] - changing the privilege checking for version 2.4" into tizen_2.4
[platform/core/api/webapi-plugins.git] / src / content / content_filter.cc
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
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 #include "content/content_filter.h"
18
19 #include <vector>
20
21 #include "common/converter.h"
22 #include "common/logger.h"
23
24 using common::AttributeMatchFlag;
25 using common::CompositeFilterType;
26 using common::ErrorCode;
27 using common::JsonCast;
28 using common::PlatformResult;
29
30 namespace extension {
31 namespace content {
32
33 namespace {
34
35 std::map<std::string, std::string> const attributeNameMap = {
36     {"id", "MEDIA_ID"},
37     {"type", "MEDIA_TYPE"},
38     {"mimeType", "MEDIA_MIME_TYPE"},
39     {"name", "MEDIA_DISPLAY_NAME"},
40     {"title", "MEDIA_TITLE"},
41     {"contentURI", "MEDIA_PATH"},
42     {"thumbnailURIs", "MEDIA_THUMBNAIL_PATH"},
43     {"description", "MEDIA_DESCRIPTION"},
44     {"rating", "MEDIA_RATING"},
45     {"createdDate", "MEDIA_ADDED_TIME"},
46     {"releaseDate", "MEDIA_DATETAKEN"},
47     {"modifiedDate", "MEDIA_MODIFIED_TIME"},
48     {"geolocation.latitude", "MEDIA_LATITUDE"},
49     {"geolocation.longitude", "MEDIA_LONGITUDE"},
50     {"duration", "MEDIA_DURATION"},
51     {"album", "MEDIA_ALBUM"},
52     {"artists", "MEDIA_ARTIST"},
53     {"width", "MEDIA_WIDTH"},
54     {"height", "MEDIA_HEIGHT"},
55     {"genres", "MEDIA_GENRE"},
56     {"size", "MEDIA_SIZE"},
57 };
58
59 std::string escapeValueString(const std::string& data) {
60   LoggerD("Enter");
61   std::string out;
62   // If string won't be resized, then it will be faster
63   out.reserve(data.size());
64   for (auto c : data) {
65     if (c == '\\')
66       out += "\\\\";
67     else if (c == '\"')
68       out += "\\\"";
69     else if (c == '\'')
70       out += "\\\'";
71     else if (c == '\n')
72       out += "\\\n";
73     else if (c == '\r')
74       out += "\\\r";
75     else
76       out += c;
77   }
78   return out;
79 }
80
81 }  // namespace
82
83 PlatformResult ContentFilter::MapField(const std::string& name,
84                                        std::string* result) {
85   LoggerD("Enter");
86   auto it = attributeNameMap.find(name);
87   if (it != attributeNameMap.end())
88     *result = it->second;
89   else
90   {
91     LoggerE("INVALID_VALUES_ERR");
92     return PlatformResult(ErrorCode::INVALID_VALUES_ERR);
93   }
94   return PlatformResult(ErrorCode::NO_ERROR);
95 }
96
97 PlatformResult ContentFilter::BuildQuery(const picojson::object& jsFilter,
98                                          std::string* queryToCall) {
99   LoggerD("Enter");
100   std::vector<std::vector<std::string> > partialqueries;
101   partialqueries.push_back(std::vector<std::string>());
102
103   visitor.SetOnAttributeFilter([&](const std::string& name,
104                                    AttributeMatchFlag match_flag,
105                                    const picojson::value& match_value) {
106     LoggerD("entered OnAttributeFilter");
107
108     PlatformResult result = PlatformResult(ErrorCode::NO_ERROR);
109
110     std::string query;
111     std::string matchValue;
112
113     result = MapField(name, &query);
114     if (!result)
115       return result;
116
117     if (AttributeMatchFlag::kExactly == match_flag ||
118         AttributeMatchFlag::kFullString == match_flag) {
119       query += " = ";
120     } else if (AttributeMatchFlag::kContains == match_flag ||
121                AttributeMatchFlag::kStartsWith == match_flag ||
122                AttributeMatchFlag::kEndsWith == match_flag) {
123       query += " LIKE ";
124     } else if (AttributeMatchFlag::kExists == match_flag) {
125       query += " IS NOT NULL ";
126     } else {
127       LoggerE("INVALID_VALUES_ERR");
128       return PlatformResult(ErrorCode::INVALID_VALUES_ERR);
129     }
130     if (AttributeMatchFlag::kExists != match_flag) {
131       query.append("\"");
132       matchValue = escapeValueString(JsonCast<std::string>(match_value));
133       if (name == "type") {
134         if (matchValue == "IMAGE") {
135           matchValue = "0";
136         } else if (matchValue == "VIDEO") {
137           matchValue = "1";
138         } else if (matchValue == "AUDIO") {
139           matchValue = "3";
140         } else {  // OTHER
141           matchValue = "4";
142         }
143       } else if (name == "contentURI") {
144         const char* uri_prefix = "file://";
145         size_t found = matchValue.find(uri_prefix);
146         if (found != std::string::npos) {
147           //simple convertion of URI to globalpath
148           matchValue = matchValue.substr(found + strlen(uri_prefix));
149         }
150       }
151       switch (match_flag) {
152         case AttributeMatchFlag::kStartsWith :
153           query += matchValue + "%";
154           break;
155         case AttributeMatchFlag::kEndsWith :
156           query += "%" + matchValue;
157           break;
158         case AttributeMatchFlag::kContains :
159           query += "%" + matchValue + "%";
160           break;
161         default :
162           query += matchValue;
163       }
164       query.append("\"");
165     }
166
167     partialqueries.back().push_back(query);
168
169     return result;
170   });
171
172   visitor.SetOnCompositeFilterBegin([&](CompositeFilterType type) {
173     LoggerD("entered OnCompositeFilterBegin");
174     partialqueries.push_back(std::vector<std::string>());
175     return PlatformResult(ErrorCode::NO_ERROR);
176   });
177
178   visitor.SetOnCompositeFilterEnd([&](CompositeFilterType calType) {
179     LoggerD("entered OnCompositeFilterEnd");
180     std::string finalQuery;
181     std::string separator;
182
183     if (CompositeFilterType::kUnion == calType)
184       separator = " OR ";
185     else
186       separator = " AND ";
187
188     if (partialqueries.back().empty()) {
189       partialqueries.pop_back();
190       return PlatformResult(ErrorCode::NO_ERROR);
191     }
192     if (partialqueries.back().size() != 1)
193       finalQuery.append("(");
194
195     for (unsigned long i = 0; i < partialqueries.back().size(); i++) {
196       finalQuery += partialqueries.back().at(i);
197       if (i != partialqueries.back().size() - 1) {
198         finalQuery += separator;
199       }
200     }
201
202     if (partialqueries.back().size() != 1)
203       finalQuery.append(")");
204     partialqueries.pop_back();
205     partialqueries.back().push_back(finalQuery);
206
207     return PlatformResult(ErrorCode::NO_ERROR);
208   });
209
210   visitor.SetOnAttributeRangeFilter([&](const std::string& name,
211                                         const picojson::value& initial_value,
212                                         const picojson::value& end_value) {
213     LoggerD("entered OnAttributeFilter");
214
215     PlatformResult result = PlatformResult(ErrorCode::NO_ERROR);
216     std::string query = "";
217     std::string paramName;
218     result = MapField(name, &paramName);
219     if (!result)
220       return result;
221
222     std::string initialValue = escapeValueString(JsonCast<std::string>(initial_value));
223     std::string endValue = escapeValueString(JsonCast<std::string>(end_value));
224     query += paramName;
225     query += " >= \"";
226     query += initialValue;
227     query += "\" AND ";
228     query += paramName;
229     query += " <= \"";
230     query += endValue;
231     query += "\"";
232     partialqueries.back().push_back(query);
233
234     return result;
235   });
236
237   if (!visitor.Visit(jsFilter)) {
238     LoggerE("INVALID_VALUES_ERR");
239     return PlatformResult(ErrorCode::INVALID_VALUES_ERR);
240   }
241
242   if (partialqueries.empty()) {
243     LoggerE("Filter parsing error!");
244     return PlatformResult(ErrorCode::SYNTAX_ERR);
245   }
246   if (partialqueries.back().empty()) {
247     LoggerD("Resolved to empty string!");
248     *queryToCall = "";
249     return PlatformResult(ErrorCode::NO_ERROR);
250   }
251
252   *queryToCall = partialqueries.back().front();
253   return PlatformResult(ErrorCode::NO_ERROR);
254 }
255
256 }  // namespace content
257 }  // namespace extension