libchromeos: Move data_encoding from Buffet to libchromeos
BUG=chromium:405714
TEST=USE=buffet ./build_packages
Change-Id: I9c9d3994d1e33a05cd5c978a2697164071ce5aa0
Reviewed-on: https://chromium-review.googlesource.com/213362
Tested-by: Alex Vakulenko <avakulenko@chromium.org>
Reviewed-by: Bertrand Simonnet <bsimonnet@chromium.org>
Commit-Queue: Alex Vakulenko <avakulenko@chromium.org>
diff --git a/chromeos/data_encoding.cc b/chromeos/data_encoding.cc
new file mode 100644
index 0000000..83e7a56
--- /dev/null
+++ b/chromeos/data_encoding.cc
@@ -0,0 +1,100 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <chromeos/data_encoding.h>
+
+#include <base/strings/stringprintf.h>
+#include <chromeos/string_utils.h>
+#include <cstring>
+
+namespace {
+
+inline int HexToDec(int hex) {
+ int dec = -1;
+ if (hex >= '0' && hex <= '9') {
+ dec = hex - '0';
+ } else if (hex >= 'A' && hex <= 'F') {
+ dec = hex - 'A' + 10;
+ } else if (hex >= 'a' && hex <= 'f') {
+ dec = hex - 'a' + 10;
+ }
+ return dec;
+}
+
+} // namespace
+
+/////////////////////////////////////////////////////////////////////////
+namespace chromeos {
+namespace data_encoding {
+
+std::string UrlEncode(const char* data, bool encodeSpaceAsPlus) {
+ std::string result;
+
+ while (*data) {
+ char c = *data++;
+ // According to RFC3986 (http://www.faqs.org/rfcs/rfc3986.html),
+ // section 2.3. - Unreserved Characters
+ if ((c >= '0' && c <= '9') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= 'a' && c <= 'z') ||
+ c == '-' || c == '.' || c == '_' || c == '~') {
+ result += c;
+ } else if (c == ' ' && encodeSpaceAsPlus) {
+ // For historical reasons, some URLs have spaces encoded as '+',
+ // this also applies to form data encoded as
+ // 'application/x-www-form-urlencoded'
+ result += '+';
+ } else {
+ base::StringAppendF(&result, "%%%02X",
+ static_cast<unsigned char>(c)); // Encode as %NN
+ }
+ }
+ return result;
+}
+
+std::string UrlDecode(const char* data) {
+ std::string result;
+ while (*data) {
+ char c = *data++;
+ int part1 = 0, part2 = 0;
+ // HexToDec would return -1 even for character 0 (end of string),
+ // so it is safe to access data[0] and data[1] without overrunning the buf.
+ if (c == '%' &&
+ (part1 = HexToDec(data[0])) >= 0 && (part2 = HexToDec(data[1])) >= 0) {
+ c = static_cast<char>((part1 << 4) | part2);
+ data += 2;
+ } else if (c == '+') {
+ c = ' ';
+ }
+ result += c;
+ }
+ return result;
+}
+
+std::string WebParamsEncode(const WebParamList& params,
+ bool encodeSpaceAsPlus) {
+ std::vector<std::string> pairs;
+ pairs.reserve(params.size());
+ for (const auto& p : params) {
+ std::string key = UrlEncode(p.first.c_str(), encodeSpaceAsPlus);
+ std::string value = UrlEncode(p.second.c_str(), encodeSpaceAsPlus);
+ pairs.push_back(chromeos::string_utils::Join('=', key, value));
+ }
+
+ return chromeos::string_utils::Join('&', pairs);
+}
+
+WebParamList WebParamsDecode(const std::string& data) {
+ WebParamList result;
+ std::vector<std::string> params = chromeos::string_utils::Split(data, '&');
+ for (const auto& p : params) {
+ auto pair = chromeos::string_utils::SplitAtFirst(p, '=');
+ result.emplace_back(UrlDecode(pair.first.c_str()),
+ UrlDecode(pair.second.c_str()));
+ }
+ return result;
+}
+
+} // namespace data_encoding
+} // namespace chromeos
diff --git a/chromeos/data_encoding.h b/chromeos/data_encoding.h
new file mode 100644
index 0000000..1141ba8
--- /dev/null
+++ b/chromeos/data_encoding.h
@@ -0,0 +1,46 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIBCHROMEOS_CHROMEOS_DATA_ENCODING_H_
+#define LIBCHROMEOS_CHROMEOS_DATA_ENCODING_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace chromeos {
+namespace data_encoding {
+
+typedef std::vector<std::pair<std::string, std::string>> WebParamList;
+
+// Encode/escape string to be used in the query portion of a URL.
+// If |encodeSpaceAsPlus| is set to true, spaces are encoded as '+' instead
+// of "%20"
+std::string UrlEncode(const char* data, bool encodeSpaceAsPlus);
+
+inline std::string UrlEncode(const char* data) {
+ return UrlEncode(data, true);
+}
+
+// Decodes/unescapes a URL. Replaces all %XX sequences with actual characters.
+// Also replaces '+' with spaces.
+std::string UrlDecode(const char* data);
+
+// Converts a list of key-value pairs into a string compatible with
+// 'application/x-www-form-urlencoded' content encoding.
+std::string WebParamsEncode(const WebParamList& params, bool encodeSpaceAsPlus);
+
+inline std::string WebParamsEncode(const WebParamList& params) {
+ return WebParamsEncode(params, true);
+}
+
+// Parses a string of '&'-delimited key-value pairs (separated by '=') and
+// encoded in a way compatible with 'application/x-www-form-urlencoded'
+// content encoding.
+WebParamList WebParamsDecode(const std::string& data);
+
+} // namespace data_encoding
+} // namespace chromeos
+
+#endif // LIBCHROMEOS_CHROMEOS_DATA_ENCODING_H_
diff --git a/chromeos/data_encoding_unittest.cc b/chromeos/data_encoding_unittest.cc
new file mode 100644
index 0000000..a09b09e
--- /dev/null
+++ b/chromeos/data_encoding_unittest.cc
@@ -0,0 +1,43 @@
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <chromeos/data_encoding.h>
+
+#include <gtest/gtest.h>
+
+namespace chromeos {
+namespace data_encoding {
+
+TEST(data_encoding, UrlEncoding) {
+ std::string test = "\"http://sample/path/0014.html \"";
+ std::string encoded = UrlEncode(test.c_str());
+ EXPECT_EQ("%22http%3A%2F%2Fsample%2Fpath%2F0014.html+%22",
+ encoded);
+ EXPECT_EQ(test, UrlDecode(encoded.c_str()));
+
+ test = "\"http://sample/path/0014.html \"";
+ encoded = UrlEncode(test.c_str(), false);
+ EXPECT_EQ("%22http%3A%2F%2Fsample%2Fpath%2F0014.html%20%22",
+ encoded);
+ EXPECT_EQ(test, UrlDecode(encoded.c_str()));
+}
+
+TEST(data_encoding, WebParamsEncoding) {
+ std::string encoded = WebParamsEncode({{"q", "test"},
+ {"path", "/usr/bin"},
+ {"#", "%"}});
+ EXPECT_EQ("q=test&path=%2Fusr%2Fbin&%23=%25", encoded);
+
+ auto params = WebParamsDecode(encoded);
+ EXPECT_EQ(3, params.size());
+ EXPECT_EQ("q", params[0].first);
+ EXPECT_EQ("test", params[0].second);
+ EXPECT_EQ("path", params[1].first);
+ EXPECT_EQ("/usr/bin", params[1].second);
+ EXPECT_EQ("#", params[2].first);
+ EXPECT_EQ("%", params[2].second);
+}
+
+} // namespace data_encoding
+} // namespace chromeos