1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
|
/*-------------------------------------------------------------------------
*
* hex.c
* Encoding and decoding routines for hex.
*
* Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* src/common/hex.c
*
*-------------------------------------------------------------------------
*/
#ifndef FRONTEND
#include "postgres.h"
#else
#include "postgres_fe.h"
#endif
#include "common/hex.h"
#ifdef FRONTEND
#include "common/logging.h"
#endif
#include "mb/pg_wchar.h"
static const int8 hexlookup[128] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
};
static const char hextbl[] = "0123456789abcdef";
static inline char
get_hex(const char *cp)
{
unsigned char c = (unsigned char) *cp;
int res = -1;
if (c < 127)
res = hexlookup[c];
if (res < 0)
{
#ifdef FRONTEND
pg_log_fatal("invalid hexadecimal digit");
exit(EXIT_FAILURE);
#else
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid hexadecimal digit: \"%.*s\"",
pg_mblen(cp), cp)));
#endif
}
return (char) res;
}
/*
* pg_hex_encode
*
* Encode into hex the given string. Returns the length of the encoded
* string.
*/
uint64
pg_hex_encode(const char *src, size_t srclen, char *dst, size_t dstlen)
{
const char *end = src + srclen;
char *p;
p = dst;
while (src < end)
{
/*
* Leave if there is an overflow in the area allocated for the encoded
* string.
*/
if ((p - dst + 2) > dstlen)
{
#ifdef FRONTEND
pg_log_fatal("overflow of destination buffer in hex encoding");
exit(EXIT_FAILURE);
#else
elog(ERROR, "overflow of destination buffer in hex encoding");
#endif
}
*p++ = hextbl[(*src >> 4) & 0xF];
*p++ = hextbl[*src & 0xF];
src++;
}
Assert((p - dst) <= dstlen);
return p - dst;
}
/*
* pg_hex_decode
*
* Decode the given hex string. Returns the length of the decoded string.
*/
uint64
pg_hex_decode(const char *src, size_t srclen, char *dst, size_t dstlen)
{
const char *s,
*srcend;
char v1,
v2,
*p;
srcend = src + srclen;
s = src;
p = dst;
while (s < srcend)
{
if (*s == ' ' || *s == '\n' || *s == '\t' || *s == '\r')
{
s++;
continue;
}
v1 = get_hex(s) << 4;
s++;
if (s >= srcend)
{
#ifdef FRONTEND
pg_log_fatal("invalid hexadecimal data: odd number of digits");
exit(EXIT_FAILURE);
#else
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid hexadecimal data: odd number of digits")));
#endif
}
v2 = get_hex(s);
s++;
/* overflow check */
if ((p - dst + 1) > dstlen)
{
#ifdef FRONTEND
pg_log_fatal("overflow of destination buffer in hex decoding");
exit(EXIT_FAILURE);
#else
elog(ERROR, "overflow of destination buffer in hex decoding");
#endif
}
*p++ = v1 | v2;
}
Assert((p - dst) <= dstlen);
return p - dst;
}
/*
* pg_hex_enc_len
*
* Returns to caller the length of the string if it were encoded with
* hex based on the length provided by caller. This is useful to estimate
* how large a buffer allocation needs to be done before doing the actual
* encoding.
*/
uint64
pg_hex_enc_len(size_t srclen)
{
return (uint64) srclen << 1;
}
/*
* pg_hex_dec_len
*
* Returns to caller the length of the string if it were to be decoded
* with hex, based on the length given by caller. This is useful to
* estimate how large a buffer allocation needs to be done before doing
* the actual decoding.
*/
uint64
pg_hex_dec_len(size_t srclen)
{
return (uint64) srclen >> 1;
}
|