1 // util/hex.h
2
3
4 /**
5 * Copyright (C) 2018-present MongoDB, Inc.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the Server Side Public License, version 1,
9 * as published by MongoDB, Inc.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * Server Side Public License for more details.
15 *
16 * You should have received a copy of the Server Side Public License
17 * along with this program. If not, see
18 * <http://www.mongodb.com/licensing/server-side-public-license>.
19 *
20 * As a special exception, the copyright holders give permission to link the
21 * code of portions of this program with the OpenSSL library under certain
22 * conditions as described in each individual source file and distribute
23 * linked combinations including the program with the OpenSSL library. You
24 * must comply with the Server Side Public License in all respects for
25 * all of the code used other than as permitted herein. If you modify file(s)
26 * with this exception, you may extend this exception to your version of the
27 * file(s), but you are not obligated to do so. If you do not wish to do so,
28 * delete this exception statement from your version. If you delete this
29 * exception statement from all source files in the program, then also delete
30 * it in the license file.
31 */
32
33 #pragma once
34
35 #include <cctype>
36 #include <string>
37
38 #include "mongo/base/string_data.h"
39 #include "mongo/bson/util/builder.h"
40 #include "mongo/util/mongoutils/str.h"
41
42 namespace mongo {
43 // can't use hex namespace because it conflicts with hex iostream function
fromHex(char c)44 inline StatusWith<char> fromHex(char c) {
45 if ('0' <= c && c <= '9')
46 return c - '0';
47 if ('a' <= c && c <= 'f')
48 return c - 'a' + 10;
49 if ('A' <= c && c <= 'F')
50 return c - 'A' + 10;
51 return Status(ErrorCodes::FailedToParse,
52 str::stream() << "The character " << c << " failed to parse from hex.");
53 }
fromHex(const char * c)54 inline StatusWith<char> fromHex(const char* c) {
55 if (fromHex(c[0]).isOK() && fromHex(c[1]).isOK()) {
56 return (char)((fromHex(c[0]).getValue() << 4) | fromHex(c[1]).getValue());
57 }
58 return Status(ErrorCodes::FailedToParse,
59 str::stream() << "The character " << c[0] << c[1]
60 << " failed to parse from hex.");
61 }
fromHex(StringData c)62 inline StatusWith<char> fromHex(StringData c) {
63 if (fromHex(c[0]).isOK() && fromHex(c[1]).isOK()) {
64 return (char)((fromHex(c[0]).getValue() << 4) | fromHex(c[1]).getValue());
65 }
66 return Status(ErrorCodes::FailedToParse,
67 str::stream() << "The character " << c[0] << c[1]
68 << " failed to parse from hex.");
69 }
70
71 /**
72 * Decodes 'hexString' into raw bytes, appended to the out parameter 'buf'. Callers must first
73 * ensure that 'hexString' is a valid hex encoding.
74 */
fromHexString(StringData hexString,BufBuilder * buf)75 inline void fromHexString(StringData hexString, BufBuilder* buf) {
76 invariant(hexString.size() % 2 == 0);
77 // Combine every pair of two characters into one byte.
78 for (std::size_t i = 0; i < hexString.size(); i += 2) {
79 buf->appendChar(uassertStatusOK(fromHex(StringData(&hexString.rawData()[i], 2))));
80 }
81 }
82
83 /**
84 * Returns true if 'hexString' is a valid hexadecimal encoding.
85 */
isValidHex(StringData hexString)86 inline bool isValidHex(StringData hexString) {
87 // There must be an even number of characters, since each pair encodes a single byte.
88 return hexString.size() % 2 == 0 &&
89 std::all_of(hexString.begin(), hexString.end(), [](char c) { return std::isxdigit(c); });
90 }
91
toHex(const void * inRaw,int len)92 inline std::string toHex(const void* inRaw, int len) {
93 static const char hexchars[] = "0123456789ABCDEF";
94
95 StringBuilder out;
96 const char* in = reinterpret_cast<const char*>(inRaw);
97 for (int i = 0; i < len; ++i) {
98 char c = in[i];
99 char hi = hexchars[(c & 0xF0) >> 4];
100 char lo = hexchars[(c & 0x0F)];
101
102 out << hi << lo;
103 }
104
105 return out.str();
106 }
107
108 template <typename T>
109 std::string integerToHex(T val);
110
toHexLower(const void * inRaw,int len)111 inline std::string toHexLower(const void* inRaw, int len) {
112 static const char hexchars[] = "0123456789abcdef";
113
114 StringBuilder out;
115 const char* in = reinterpret_cast<const char*>(inRaw);
116 for (int i = 0; i < len; ++i) {
117 char c = in[i];
118 char hi = hexchars[(c & 0xF0) >> 4];
119 char lo = hexchars[(c & 0x0F)];
120
121 out << hi << lo;
122 }
123
124 return out.str();
125 }
126
127 /* @return a dump of the buffer as hex byte ascii output */
128 std::string hexdump(const char* data, unsigned len);
129 }
130