Merge remote-tracking branch 'remotes/spin/tizen_3.0' into tizen
[platform/core/api/webapi-plugins.git] / src / content / content_filter.cc
1 // Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/content_filter.h"
6
7 #include <vector>
8
9 #include "common/converter.h"
10 #include "common/logger.h"
11
12 using common::AttributeMatchFlag;
13 using common::CompositeFilterType;
14 using common::ErrorCode;
15 using common::JsonCast;
16 using common::PlatformResult;
17
18 namespace extension {
19 namespace content {
20
21 namespace {
22
23 std::map<std::string, std::string> const attributeNameMap = {
24     {"id", "MEDIA_ID"},
25     {"type", "MEDIA_TYPE"},
26     {"mimeType", "MEDIA_MIME_TYPE"},
27     {"name", "MEDIA_DISPLAY_NAME"},
28     {"title", "MEDIA_TITLE"},
29     {"contentURI", "MEDIA_PATH"},
30     {"thumbnailURIs", "MEDIA_THUMBNAIL_PATH"},
31     {"description", "MEDIA_DESCRIPTION"},
32     {"rating", "MEDIA_RATING"},
33     {"createdDate", "MEDIA_ADDED_TIME"},
34     {"releaseDate", "MEDIA_DATETAKEN"},
35     {"modifiedDate", "MEDIA_MODIFIED_TIME"},
36     {"geolocation.latitude", "MEDIA_LATITUDE"},
37     {"geolocation.longitude", "MEDIA_LONGITUDE"},
38     {"duration", "MEDIA_DURATION"},
39     {"album", "MEDIA_ALBUM"},
40     {"artists", "MEDIA_ARTIST"},
41     {"width", "MEDIA_WIDTH"},
42     {"height", "MEDIA_HEIGHT"},
43     {"genres", "MEDIA_GENRE"},
44     {"size", "MEDIA_SIZE"},
45 };
46
47 std::string escapeValueString(const std::string& data) {
48   std::string out;
49   // If string won't be resized, then it will be faster
50   out.reserve(data.size());
51   for (auto c : data) {
52     if (c == '\\')
53       out += "\\\\";
54     else if (c == '\"')
55       out += "\\\"";
56     else if (c == '\'')
57       out += "\\\'";
58     else if (c == '\n')
59       out += "\\\n";
60     else if (c == '\r')
61       out += "\\\r";
62     else
63       out += c;
64   }
65   return out;
66 }
67
68 }  // namespace
69
70 PlatformResult ContentFilter::MapField(const std::string& name,
71                                        std::string* result) {
72   auto it = attributeNameMap.find(name);
73   if (it != attributeNameMap.end())
74     *result = it->second;
75   else
76     return PlatformResult(ErrorCode::INVALID_VALUES_ERR);
77
78   return PlatformResult(ErrorCode::NO_ERROR);
79 }
80
81 PlatformResult ContentFilter::BuildQuery(const picojson::object& jsFilter,
82                                          std::string* queryToCall) {
83   std::vector<std::vector<std::string> > partialqueries;
84   partialqueries.push_back(std::vector<std::string>());
85
86   visitor.SetOnAttributeFilter([&](const std::string& name,
87                                    AttributeMatchFlag match_flag,
88                                    const picojson::value& match_value) {
89     LoggerD("entered OnAttributeFilter");
90
91     PlatformResult result = PlatformResult(ErrorCode::NO_ERROR);
92
93     std::string query;
94     std::string matchValue;
95
96     result = MapField(name, &query);
97     if (!result)
98       return result;
99
100     if (AttributeMatchFlag::kExactly == match_flag ||
101         AttributeMatchFlag::kFullString == match_flag) {
102       query += " = ";
103     } else if (AttributeMatchFlag::kContains == match_flag ||
104                AttributeMatchFlag::kStartsWith == match_flag ||
105                AttributeMatchFlag::kEndsWith == match_flag) {
106       query += " LIKE ";
107     } else if (AttributeMatchFlag::kExists == match_flag) {
108       query += " IS NOT NULL ";
109     } else {
110       return PlatformResult(ErrorCode::INVALID_VALUES_ERR);
111     }
112
113     if (AttributeMatchFlag::kExists != match_flag) {
114       query.append("\"");
115       matchValue = escapeValueString(JsonCast<std::string>(match_value));
116       if (name == "type") {
117         if (matchValue == "IMAGE") {
118           matchValue = "0";
119         } else if (matchValue == "VIDEO") {
120           matchValue = "1";
121         } else if (matchValue == "AUDIO") {
122           matchValue = "3";
123         } else {  // OTHER
124           matchValue = "4";
125         }
126       }
127       query += matchValue;
128       query.append("\"");
129     }
130
131     partialqueries.back().push_back(query);
132
133     return result;
134   });
135
136   visitor.SetOnCompositeFilterBegin([&](CompositeFilterType type) {
137     LoggerD("entered OnCompositeFilterBegin");
138     partialqueries.push_back(std::vector<std::string>());
139     return PlatformResult(ErrorCode::NO_ERROR);
140   });
141
142   visitor.SetOnCompositeFilterEnd([&](CompositeFilterType calType) {
143     LoggerD("entered OnCompositeFilterEnd");
144     std::string finalQuery;
145     std::string separator;
146
147     if (CompositeFilterType::kUnion == calType)
148       separator = " OR ";
149     else
150       separator = " AND ";
151
152     if (partialqueries.back().empty()) {
153       partialqueries.pop_back();
154       return PlatformResult(ErrorCode::NO_ERROR);
155     }
156     if (partialqueries.back().size() != 1)
157       finalQuery.append("(");
158
159     for (unsigned long i = 0; i < partialqueries.back().size(); i++) {
160       finalQuery += partialqueries.back().at(i);
161       if (i != partialqueries.back().size() - 1) {
162         finalQuery += separator;
163       }
164     }
165
166     if (partialqueries.back().size() != 1)
167       finalQuery.append(")");
168     partialqueries.pop_back();
169     partialqueries.back().push_back(finalQuery);
170
171     return PlatformResult(ErrorCode::NO_ERROR);
172   });
173
174   visitor.SetOnAttributeRangeFilter([&](const std::string& name,
175                                         const picojson::value& initial_value,
176                                         const picojson::value& end_value) {
177     LoggerD("entered OnAttributeFilter");
178
179     PlatformResult result = PlatformResult(ErrorCode::NO_ERROR);
180     std::string query = "";
181     std::string paramName;
182     result = MapField(name, &paramName);
183     if (!result)
184       return result;
185
186     std::string initialValue = escapeValueString(JsonCast<std::string>(initial_value));
187     std::string endValue = escapeValueString(JsonCast<std::string>(end_value));
188     query += paramName;
189     query += " >= \"";
190     query += initialValue;
191     query += "\" AND ";
192     query += paramName;
193     query += " <= \"";
194     query += endValue;
195     query += "\"";
196     partialqueries.back().push_back(query);
197
198     return result;
199   });
200
201   if (!visitor.Visit(jsFilter)) {
202     return PlatformResult(ErrorCode::INVALID_VALUES_ERR);
203   }
204
205   if (partialqueries.empty()) {
206     LoggerE("Filter parsing error!");
207     return PlatformResult(ErrorCode::SYNTAX_ERR);
208   }
209   if (partialqueries.back().empty()) {
210     LoggerD("Resolved to empty string!");
211     *queryToCall = "";
212     return PlatformResult(ErrorCode::NO_ERROR);
213   }
214
215   *queryToCall = partialqueries.back().front();
216   return PlatformResult(ErrorCode::NO_ERROR);
217 }
218
219 }  // namespace content
220 }  // namespace extension