// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <amp>
+#include "content/content_filter.h"
-#include "content_filter.h"
+#include <vector>
-#define __DEBUG__ 1
+#include "common/converter.h"
+#include "common/logger.h"
+using common::AttributeMatchFlag;
+using common::CompositeFilterType;
+using common::ErrorCode;
+using common::JsonCast;
+using common::PlatformResult;
namespace extension {
namespace content {
-const std::map<std::string, std::string>& attributeNameMap = {
- {"id", "MEDIA_ID"},
- {"type", "MEDIA_TYPE"},
- {"mimeType", "MEDIA_MIME_TYPE"},
- {"name", "MEDIA_DISPLAY_NAME"},
- {"title", "MEDIA_TITLE"},
- {"contentURI", "MEDIA_PATH"},
- {"thumbnailURIs", "MEDIA_THUMBNAIL_PATH"},
- {"description", "MEDIA_DESCRIPTION"},
- {"rating", "MEDIA_RATING"},
- {"createdDate", "MEDIA_ADDED_TIME"},
- {"releaseDate", "MEDIA_DATETAKEN"},
- {"modifiedDate", "MEDIA_MODIFIED_TIME"},
- {"geolocation.latitude", "MEDIA_LATITUDE"},
- {"geolocation.longitude", "MEDIA_LONGITUDE"},
- {"duration", "MEDIA_DURATION"},
- {"album", "MEDIA_ALBUM"},
- {"artists", "MEDIA_ARTIST"},
- {"width", "MEDIA_WIDTH"},
- {"height", "MEDIA_HEIGHT"},
- {"genres", "MEDIA_GENRE"},
- {"size", "MEDIA_SIZE"},
+namespace {
+
+std::map<std::string, std::string> const attributeNameMap = {
+ {"id", "MEDIA_ID"},
+ {"type", "MEDIA_TYPE"},
+ {"mimeType", "MEDIA_MIME_TYPE"},
+ {"name", "MEDIA_DISPLAY_NAME"},
+ {"title", "MEDIA_TITLE"},
+ {"contentURI", "MEDIA_PATH"},
+ {"thumbnailURIs", "MEDIA_THUMBNAIL_PATH"},
+ {"description", "MEDIA_DESCRIPTION"},
+ {"rating", "MEDIA_RATING"},
+ {"createdDate", "MEDIA_ADDED_TIME"},
+ {"releaseDate", "MEDIA_DATETAKEN"},
+ {"modifiedDate", "MEDIA_MODIFIED_TIME"},
+ {"geolocation.latitude", "MEDIA_LATITUDE"},
+ {"geolocation.longitude", "MEDIA_LONGITUDE"},
+ {"duration", "MEDIA_DURATION"},
+ {"album", "MEDIA_ALBUM"},
+ {"artists", "MEDIA_ARTIST"},
+ {"width", "MEDIA_WIDTH"},
+ {"height", "MEDIA_HEIGHT"},
+ {"genres", "MEDIA_GENRE"},
+ {"size", "MEDIA_SIZE"},
};
-const std::map<std::string, std::string>& opMap = {
- {"EXACTLY", " = "},
- {"FULLSTRING", " = "},
- {"CONTAINS", " LIKE "},
- {"STARTSWITH", " LIKE "},
- {"ENDSWITH", " LIKE "},
- {"EXISTS", " IS NOT NULL "},
-};
-
-std::string ContentFilter::convert(const picojson::value& jsFilter) {
- std::string attributeName = jsFilter.get("attributeName").to_str();
- std::string matchFlag = jsFilter.get("matchFlag").to_str();
- std::string matchValue = jsFilter.get("matchValue").to_str();
-
-#ifdef DEBUG
- std::cout << "Filter IN: " << attributeName << " " << matchFlag << " " << matchValue << std::endl;
-#endif
-
- std::string query;
- if (attributeName.empty() || matchFlag.empty()) {
- std::cerr <<
- "Filter ERR: attribute or match flag missing" << std::endl;
- return query;
+std::string escapeValueString(const std::string& data) {
+ std::string out;
+ // If string won't be resized, then it will be faster
+ out.reserve(data.size());
+ for (auto c : data) {
+ if (c == '\\')
+ out += "\\\\";
+ else if (c == '\"')
+ out += "\\\"";
+ else if (c == '\'')
+ out += "\\\'";
+ else if (c == '\n')
+ out += "\\\n";
+ else if (c == '\r')
+ out += "\\\r";
+ else
+ out += c;
}
+ return out;
+}
- std::map<std::string, std::string>::const_iterator it;
- it = attributeNameMap.find(attributeName);
- if (it == attributeNameMap.end()) {
- std::cerr << "Filter ERR: unknown attributeName " <<
- attributeName << std::endl;
- return query;
+} // namespace
+
+PlatformResult ContentFilter::buildQuery(const picojson::object& jsFilter,
+ std::string* queryToCall) {
+ std::vector<std::vector<std::string> > partialqueries;
+ partialqueries.push_back(std::vector<std::string>());
+
+ visitor.SetOnAttributeFilter([&](const std::string& name,
+ AttributeMatchFlag match_flag,
+ const picojson::value& match_value) {
+ std::string query;
+ LoggerD("entered OnAttributeFilter");
+ std::string matchValue;
+ auto it = attributeNameMap.find(name);
+ if (it != attributeNameMap.end())
+ query += it->second;
+ else
+ return PlatformResult(ErrorCode::INVALID_VALUES_ERR);
+
+ if (AttributeMatchFlag::kExactly == match_flag ||
+ AttributeMatchFlag::kFullString == match_flag) {
+ query += " = ";
+ } else if (AttributeMatchFlag::kContains == match_flag ||
+ AttributeMatchFlag::kStartsWith == match_flag ||
+ AttributeMatchFlag::kEndsWith == match_flag) {
+ query += " LIKE ";
+ } else if (AttributeMatchFlag::kExists == match_flag) {
+ query += " IS NOT NULL ";
+ } else {
+ return PlatformResult(ErrorCode::INVALID_VALUES_ERR);
+ }
+ query.append("\"");
+
+ if (AttributeMatchFlag::kExists != match_flag) {
+ matchValue = escapeValueString(JsonCast<std::string>(match_value));
+ if (name == "type") {
+ if (matchValue == "IMAGE") {
+ matchValue = "0";
+ } else if (matchValue == "VIDEO") {
+ matchValue = "1";
+ } else if (matchValue == "AUDIO") {
+ matchValue = "3";
+ } else { // OTHER
+ matchValue = "4";
+ }
+ }
+ query += matchValue;
+ }
+ query.append("\"");
+ partialqueries.back().push_back(query);
+
+ LoggerD("about to call with condition %s", query.c_str());
+ return PlatformResult(ErrorCode::NO_ERROR);
+ });
+
+ visitor.SetOnCompositeFilterBegin([&](CompositeFilterType type) {
+ LoggerD("entered OnCompositeFilterBegin");
+ partialqueries.push_back(std::vector<std::string>());
+ return PlatformResult(ErrorCode::NO_ERROR);
+ });
+
+ visitor.SetOnCompositeFilterEnd([&](CompositeFilterType calType) {
+ LoggerD("entered OnCompositeFilterEnd");
+ std::string finalQuery;
+ std::string separator;
+
+ if (CompositeFilterType::kUnion == calType)
+ separator = " OR ";
+ else
+ separator = " AND ";
+
+ LoggerD("Composite filter: %i", partialqueries.back().size());
+ if (partialqueries.back().empty()) {
+ partialqueries.pop_back();
+ return PlatformResult(ErrorCode::NO_ERROR);
+ }
+ if (partialqueries.back().size() != 1)
+ finalQuery.append("(");
+
+ for (unsigned long i = 0; i < partialqueries.back().size(); i++) {
+ finalQuery += partialqueries.back().at(i);
+ if (i != partialqueries.back().size() - 1) {
+ finalQuery += separator;
+ }
+ }
+
+ if (partialqueries.back().size() != 1)
+ finalQuery.append(")");
+ partialqueries.pop_back();
+ partialqueries.back().push_back(finalQuery);
+ return PlatformResult(ErrorCode::NO_ERROR);
+ });
+
+ visitor.SetOnAttributeRangeFilter([&](const std::string& name,
+ const picojson::value& initial_value,
+ const picojson::value& end_value) {
+ LoggerD("entered OnAttributeFilter");
+ std::string query = "";
+ std::string paramName;
+ auto it = attributeNameMap.find(name);
+ if (it != attributeNameMap.end())
+ paramName = it->second;
+ else
+ return PlatformResult(ErrorCode::INVALID_VALUES_ERR);
+ std::string initialValue = escapeValueString(JsonCast<std::string>(initial_value));
+ std::string endValue = escapeValueString(JsonCast<std::string>(end_value));
+ query += paramName;
+ query += " >= \"";
+ query += initialValue;
+ query += "\" AND ";
+ query += paramName;
+ query += " <= \"";
+ query += endValue;
+ query += "\"";
+ partialqueries.back().push_back(query);
+
+ LoggerD("about to call with condition %s", query.c_str());
+ return PlatformResult(ErrorCode::NO_ERROR);
+ });
+
+ if (!visitor.Visit(jsFilter)) {
+ return PlatformResult(ErrorCode::INVALID_VALUES_ERR);
}
- std::string lValue = it->second;
- it = opMap.find(matchFlag);
- if (it == attributeNameMap.end()) {
- std::cerr << "Filter ERR: unknown matchFlag " << matchFlag << std::endl;
- return query;
+ if (partialqueries.empty()) {
+ LoggerE("Filter parsing error!");
+ return PlatformResult(ErrorCode::SYNTAX_ERR);
}
- std::string op = it->second;
-
- // Tizen requires this weird mapping on type
- if (attributeName == "type") {
- if (matchValue == "IMAGE") {
- matchValue = "0";
- } else if (matchValue == "VIDEO") {
- matchValue = "1";
- } else if (matchValue == "AUDIO") {
- matchValue = "3";
- } else if (matchValue == "OTHER") {
- matchValue = "4";
- } else {
- std::cerr << "Filter ERR: unknown media type " << matchValue << std::endl;
- return query;
- }
+ if (partialqueries.back().empty()) {
+ LoggerD("Resolved to empty string!");
+ *queryToCall = "";
+ return PlatformResult(ErrorCode::NO_ERROR);
}
- const std::string STR_QUOTE("'");
- const std::string STR_PERCENT("%");
- std::string rValue;
- if (matchFlag == "CONTAINS")
- rValue = STR_QUOTE + STR_PERCENT + matchValue + STR_PERCENT + STR_QUOTE;
- else if (matchFlag == "STARTSWITH")
- rValue = STR_QUOTE + matchValue + STR_PERCENT + STR_QUOTE;
- else if (matchFlag == "ENDSWITH")
- rValue = STR_QUOTE + STR_PERCENT + matchValue + STR_QUOTE;
- else if (matchFlag == "FULLSTRING")
- rValue = STR_QUOTE + matchValue + STR_QUOTE + " COLLATE NOCASE ";
- else if (matchFlag == "EXISTS")
- rValue = "";
- else
- rValue = STR_QUOTE + matchValue + STR_QUOTE;
-
- query = lValue + op + rValue;
-#ifdef DEBUG
- std::cout << "Filter OUT: " << query << std::endl;
-#endif
- return query;
+ *queryToCall = partialqueries.back().front();
+ return PlatformResult(ErrorCode::NO_ERROR);
}
-
-
-
-} // namespace content
-} // namespace extension
-
+} // namespace content
+} // namespace extension
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <unistd.h>
-#include <cstring>
-#include <string>
+#include "content/content_manager.h"
+
#include <algorithm>
+#include <cstring>
#include <dlog.h>
-#include <memory>
-#include <sstream>
#include <metadata_extractor.h>
+#include <sstream>
+#include <string>
+#include <unistd.h>
+#include "common/converter.h"
#include "common/logger.h"
#include "common/platform_exception.h"
-#include "content_manager.h"
-#include "content_filter.h"
+#include "common/platform_result.h"
+#include "common/scope_exit.h"
+#include "content/content_filter.h"
using namespace std;
using namespace common;
namespace extension {
namespace content {
-#define TAG_DELIMETER '/'
-
static int get_utc_offset()
{
time_t zero = 24*60*60L;
std::string description = content.get("description").to_str();
std::string rating = content.get("rating").to_str();
std::string is_fav = content.get("isFavorite").to_str();
-
if (media != NULL) {
media_content_type_e type;
ret = media_info_get_media_type(media, &type);
if (type == MEDIA_CONTENT_TYPE_IMAGE || type == MEDIA_CONTENT_TYPE_VIDEO) {
picojson::value geo = content.get("geolocation");
double latitude = atof(geo.get("latitude").to_str().c_str());
- double longitude = atof(geo.get("longitude ").to_str().c_str());
+ double longitude = atof(geo.get("longitude").to_str().c_str());
ret = media_info_set_latitude(media, latitude);
if ( ret != MEDIA_CONTENT_ERROR_NONE) {
LoggerD("Updating geolocation is failed.");
static bool media_foreach_content_cb(media_info_h media, void *user_data) {
picojson::value::array *contents = static_cast<picojson::value::array*>(user_data);
picojson::value::object o;
-
contentToJson(media, o);
contents->push_back(picojson::value(o));
return true;
double count, offset;
std::string dirId, attributeName, matchFlag, matchValue;
std::string sortModeName, sortModeOrder;
+ int error_code = 0;
media_content_order_e order;
picojson::value::array arrayContent;
- filter_h filter = NULL;
- ret = media_filter_create(&filter);
-
- if(ret != MEDIA_CONTENT_ERROR_NONE) {
- UnknownException err("Memory allcation for filter is failed.");
- user_data->isSuccess = false;
- user_data->result = err.ToJSON();
- return;
- }
- if(user_data->args.contains("filter")) {
- //to be implemented. dykim.
- picojson::value vfilter = user_data->args.get("filter");
- if (!vfilter.is<picojson::null>() && vfilter.is<picojson::object>()) {
- attributeName = vfilter.get("attributeName").to_str();
- matchFlag = vfilter.get("matchFlag").to_str();
- matchValue = vfilter.get("matchValue").to_str();
+ filter_h filter = nullptr;
+ media_filter_create(&filter);
+ SCOPE_EXIT {
+ if (filter) {
+ media_filter_destroy(filter);
}
- }
- if(user_data->args.contains("sortMode")) {
- picojson::value vSortMode = user_data->args.get("sortMode");
- if (!vSortMode.is<picojson::null>() && vSortMode.is<picojson::object>()) {
- sortModeName = vSortMode.get("attributeName").to_str();
- sortModeOrder = vSortMode.get("order").to_str();
- if ( !sortModeOrder.empty() ) {
- if( sortModeOrder == "ASC" ) {
- order = MEDIA_CONTENT_ORDER_ASC;
- }
- else if( sortModeOrder == "DESC" ) {
- order = MEDIA_CONTENT_ORDER_DESC;
- }
- ret = media_filter_set_order(filter, order, sortModeName.c_str(), MEDIA_CONTENT_COLLATE_DEFAULT );
- if (MEDIA_CONTENT_ERROR_NONE != ret )
- {
- LoggerD("Platform SortMode setting is failed.");
- }
+ };
+ if (user_data->args.contains("filter")) {
+ ContentFilter filterMechanism;
+ std::string query;
+ picojson::object argsObject = JsonCast<picojson::object>(user_data->args);
+ if (filterMechanism.buildQuery(
+ FromJson<picojson::object>(argsObject, "filter"), &query)) {
+ ret = media_filter_set_condition(filter, query.c_str(),
+ MEDIA_CONTENT_COLLATE_DEFAULT);
+ if (MEDIA_CONTENT_ERROR_NONE != ret) {
}
}
}
if(user_data->args.contains("count")) {
count = user_data->args.get("count").get<double>();
- }
- else {
- count = -1;
+ } else {
+ count = 100; //TODO rethink proper default count setting
}
if(user_data->args.contains("offset")) {
offset = user_data->args.get("offset").get<double>();
}
else {
- offset = -1;
+ offset = 0;
}
ret = media_filter_set_offset(filter, offset, count);
if ( MEDIA_CONTENT_ERROR_NONE != ret) {
else {
ret = media_info_foreach_media_from_db(filter, media_foreach_content_cb, static_cast<void*>(&arrayContent));
}
- media_filter_destroy(filter);
if (ret == MEDIA_CONTENT_ERROR_NONE) {
user_data->isSuccess = true;