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