blob: 642b238f52d4508e016add01eaebcc6f9d74653d [file] [log] [blame]
Alexander Afanasyev8828ca62015-07-02 13:40:09 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesavento5d0b0102017-10-07 13:43:16 -04002/*
Davide Pesavento38a061d2018-02-15 22:45:48 -05003 * Copyright (c) 2013-2018 Regents of the University of California.
Alexander Afanasyev8828ca62015-07-02 13:40:09 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
22#include "string-helper.hpp"
Davide Pesaventodd461432017-01-28 21:47:26 -050023#include "../encoding/buffer.hpp"
Alexander Afanasyev8828ca62015-07-02 13:40:09 -070024#include "../encoding/buffer-stream.hpp"
Davide Pesavento03115ce2017-01-27 01:17:55 -050025#include "../security/transform/buffer-source.hpp"
26#include "../security/transform/hex-decode.hpp"
Davide Pesaventofdda2412017-01-28 18:53:51 -050027#include "../security/transform/hex-encode.hpp"
Davide Pesavento03115ce2017-01-27 01:17:55 -050028#include "../security/transform/stream-sink.hpp"
29
Alexander Afanasyev8828ca62015-07-02 13:40:09 -070030#include <sstream>
Alexander Afanasyev8828ca62015-07-02 13:40:09 -070031
Alexander Afanasyev8828ca62015-07-02 13:40:09 -070032namespace ndn {
33
Davide Pesaventoe78eeca2017-02-23 23:22:32 -050034std::ostream&
35operator<<(std::ostream& os, const AsHex& hex)
36{
37 printHex(os, hex.m_value, os.flags() & std::ostream::uppercase);
38 return os;
39}
40
41void
42printHex(std::ostream& os, uint64_t num, bool wantUpperCase)
43{
44 auto osFlags = os.flags();
45 // std::showbase doesn't work with number 0
46 os << "0x" << std::noshowbase << std::noshowpos
47 << (wantUpperCase ? std::uppercase : std::nouppercase)
48 << std::hex << num;
49 os.flags(osFlags);
50}
51
Alexander Afanasyev8828ca62015-07-02 13:40:09 -070052void
Davide Pesaventofdda2412017-01-28 18:53:51 -050053printHex(std::ostream& os, const uint8_t* buffer, size_t length, bool wantUpperCase)
Alexander Afanasyev8828ca62015-07-02 13:40:09 -070054{
Davide Pesavento218e5be2017-02-03 00:13:47 -050055 namespace tr = security::transform;
56 BOOST_ASSERT(buffer != nullptr || length == 0);
57 tr::bufferSource(buffer, length) >> tr::hexEncode(wantUpperCase) >> tr::streamSink(os);
Alexander Afanasyev8828ca62015-07-02 13:40:09 -070058}
59
60void
Davide Pesaventofdda2412017-01-28 18:53:51 -050061printHex(std::ostream& os, const Buffer& buffer, bool wantUpperCase)
Alexander Afanasyev8828ca62015-07-02 13:40:09 -070062{
Davide Pesavento5d0b0102017-10-07 13:43:16 -040063 return printHex(os, buffer.data(), buffer.size(), wantUpperCase);
Alexander Afanasyev8828ca62015-07-02 13:40:09 -070064}
65
66std::string
Davide Pesaventofdda2412017-01-28 18:53:51 -050067toHex(const uint8_t* buffer, size_t length, bool wantUpperCase)
Alexander Afanasyev8828ca62015-07-02 13:40:09 -070068{
Alexander Afanasyev8828ca62015-07-02 13:40:09 -070069 std::ostringstream result;
Davide Pesavento218e5be2017-02-03 00:13:47 -050070 printHex(result, buffer, length, wantUpperCase);
Alexander Afanasyev8828ca62015-07-02 13:40:09 -070071 return result.str();
72}
73
74std::string
Davide Pesaventofdda2412017-01-28 18:53:51 -050075toHex(const Buffer& buffer, bool wantUpperCase)
Alexander Afanasyev8828ca62015-07-02 13:40:09 -070076{
Davide Pesavento5d0b0102017-10-07 13:43:16 -040077 return toHex(buffer.data(), buffer.size(), wantUpperCase);
Alexander Afanasyev8828ca62015-07-02 13:40:09 -070078}
79
Davide Pesavento03115ce2017-01-27 01:17:55 -050080shared_ptr<Buffer>
Alexander Afanasyev8828ca62015-07-02 13:40:09 -070081fromHex(const std::string& hexString)
82{
Davide Pesavento03115ce2017-01-27 01:17:55 -050083 namespace tr = security::transform;
Alexander Afanasyev8828ca62015-07-02 13:40:09 -070084
85 OBufferStream os;
Davide Pesavento03115ce2017-01-27 01:17:55 -050086 try {
87 tr::bufferSource(hexString) >> tr::hexDecode() >> tr::streamSink(os);
88 }
89 catch (const tr::Error& e) {
90 BOOST_THROW_EXCEPTION(StringHelperError(std::string("Conversion from hex failed: ") + e.what()));
Alexander Afanasyev8828ca62015-07-02 13:40:09 -070091 }
92
Davide Pesavento03115ce2017-01-27 01:17:55 -050093 return os.buf();
Alexander Afanasyev8828ca62015-07-02 13:40:09 -070094}
95
Alexander Afanasyev8828ca62015-07-02 13:40:09 -070096std::string
Davide Pesavento38a061d2018-02-15 22:45:48 -050097escape(const std::string& str)
98{
99 std::ostringstream os;
100 escape(os, str.data(), str.size());
101 return os.str();
102}
103
104void
105escape(std::ostream& os, const char* str, size_t len)
106{
107 for (size_t i = 0; i < len; ++i) {
108 auto c = str[i];
109 // Unreserved characters don't need to be escaped.
110 if ((c >= 'a' && c <= 'z') ||
111 (c >= 'A' && c <= 'Z') ||
112 (c >= '0' && c <= '9') ||
113 c == '-' || c == '.' ||
114 c == '_' || c == '~') {
115 os << c;
116 }
117 else {
118 os << '%';
119 os << toHexChar((c & 0xf0) >> 4);
120 os << toHexChar(c & 0xf);
121 }
122 }
123}
124
125std::string
Alexander Afanasyev8828ca62015-07-02 13:40:09 -0700126unescape(const std::string& str)
127{
Davide Pesavento38a061d2018-02-15 22:45:48 -0500128 std::ostringstream os;
129 unescape(os, str.data(), str.size());
130 return os.str();
131}
Alexander Afanasyev8828ca62015-07-02 13:40:09 -0700132
Davide Pesavento38a061d2018-02-15 22:45:48 -0500133void
134unescape(std::ostream& os, const char* str, size_t len)
135{
136 for (size_t i = 0; i < len; ++i) {
137 if (str[i] == '%' && i + 2 < len) {
Alexander Afanasyev8828ca62015-07-02 13:40:09 -0700138 int hi = fromHexChar(str[i + 1]);
139 int lo = fromHexChar(str[i + 2]);
140
141 if (hi < 0 || lo < 0)
142 // Invalid hex characters, so just keep the escaped string.
Davide Pesavento38a061d2018-02-15 22:45:48 -0500143 os << str[i] << str[i + 1] << str[i + 2];
Alexander Afanasyev8828ca62015-07-02 13:40:09 -0700144 else
Davide Pesavento38a061d2018-02-15 22:45:48 -0500145 os << static_cast<char>((hi << 4) | lo);
Alexander Afanasyev8828ca62015-07-02 13:40:09 -0700146
147 // Skip ahead past the escaped value.
148 i += 2;
149 }
Davide Pesavento218e5be2017-02-03 00:13:47 -0500150 else {
Alexander Afanasyev8828ca62015-07-02 13:40:09 -0700151 // Just copy through.
Davide Pesavento38a061d2018-02-15 22:45:48 -0500152 os << str[i];
Davide Pesavento218e5be2017-02-03 00:13:47 -0500153 }
Alexander Afanasyev8828ca62015-07-02 13:40:09 -0700154 }
Alexander Afanasyev8828ca62015-07-02 13:40:09 -0700155}
156
157} // namespace ndn