/src/FreeRDP/winpr/libwinpr/utils/print.c
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * WinPR: Windows Portable Runtime |
3 | | * Print Utils |
4 | | * |
5 | | * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com> |
6 | | * |
7 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | | * you may not use this file except in compliance with the License. |
9 | | * You may obtain a copy of the License at |
10 | | * |
11 | | * http://www.apache.org/licenses/LICENSE-2.0 |
12 | | * |
13 | | * Unless required by applicable law or agreed to in writing, software |
14 | | * distributed under the License is distributed on an "AS IS" BASIS, |
15 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | | * See the License for the specific language governing permissions and |
17 | | * limitations under the License. |
18 | | */ |
19 | | |
20 | | #include <winpr/config.h> |
21 | | #include <winpr/debug.h> |
22 | | |
23 | | #include <stdio.h> |
24 | | #include <string.h> |
25 | | #include <stdarg.h> |
26 | | #include <errno.h> |
27 | | |
28 | | #include <winpr/crt.h> |
29 | | #include <winpr/print.h> |
30 | | |
31 | | #include "../log.h" |
32 | | |
33 | | #ifndef MIN |
34 | 0 | #define MIN(a, b) (a) < (b) ? (a) : (b) |
35 | | #endif |
36 | | |
37 | | void winpr_HexDump(const char* tag, UINT32 level, const void* data, size_t length) |
38 | 0 | { |
39 | 0 | wLog* log = WLog_Get(tag); |
40 | 0 | winpr_HexLogDump(log, level, data, length); |
41 | 0 | } |
42 | | |
43 | | void winpr_HexLogDump(wLog* log, UINT32 level, const void* data, size_t length) |
44 | 0 | { |
45 | 0 | const BYTE* p = data; |
46 | 0 | size_t line = 0; |
47 | 0 | size_t offset = 0; |
48 | 0 | const size_t maxlen = 20; /* 64bit SIZE_MAX as decimal */ |
49 | | /* String line length: |
50 | | * prefix '[1234] ' |
51 | | * hexdump '01 02 03 04' |
52 | | * separator ' ' |
53 | | * ASIC line 'ab..cd' |
54 | | * zero terminator '\0' |
55 | | */ |
56 | 0 | const size_t blen = (maxlen + 3ULL) + (WINPR_HEXDUMP_LINE_LENGTH * 3ULL) + 3ULL + |
57 | 0 | WINPR_HEXDUMP_LINE_LENGTH + 1ULL; |
58 | 0 | size_t pos = 0; |
59 | |
|
60 | 0 | char* buffer = NULL; |
61 | |
|
62 | 0 | if (!WLog_IsLevelActive(log, level)) |
63 | 0 | return; |
64 | | |
65 | 0 | if (!log) |
66 | 0 | return; |
67 | | |
68 | 0 | buffer = malloc(blen); |
69 | |
|
70 | 0 | if (!buffer) |
71 | 0 | { |
72 | 0 | char ebuffer[256] = { 0 }; |
73 | 0 | WLog_Print(log, WLOG_ERROR, "malloc(%" PRIuz ") failed with [%" PRIuz "] %s", blen, errno, |
74 | 0 | winpr_strerror(errno, ebuffer, sizeof(ebuffer))); |
75 | 0 | return; |
76 | 0 | } |
77 | | |
78 | 0 | while (offset < length) |
79 | 0 | { |
80 | 0 | int rc = _snprintf(&buffer[pos], blen - pos, "%04" PRIuz " ", offset); |
81 | |
|
82 | 0 | if (rc < 0) |
83 | 0 | goto fail; |
84 | | |
85 | 0 | pos += (size_t)rc; |
86 | 0 | line = length - offset; |
87 | |
|
88 | 0 | if (line > WINPR_HEXDUMP_LINE_LENGTH) |
89 | 0 | line = WINPR_HEXDUMP_LINE_LENGTH; |
90 | |
|
91 | 0 | size_t i = 0; |
92 | 0 | for (; i < line; i++) |
93 | 0 | { |
94 | 0 | rc = _snprintf(&buffer[pos], blen - pos, "%02" PRIx8 " ", p[i]); |
95 | |
|
96 | 0 | if (rc < 0) |
97 | 0 | goto fail; |
98 | | |
99 | 0 | pos += (size_t)rc; |
100 | 0 | } |
101 | | |
102 | 0 | for (; i < WINPR_HEXDUMP_LINE_LENGTH; i++) |
103 | 0 | { |
104 | 0 | rc = _snprintf(&buffer[pos], blen - pos, " "); |
105 | |
|
106 | 0 | if (rc < 0) |
107 | 0 | goto fail; |
108 | | |
109 | 0 | pos += (size_t)rc; |
110 | 0 | } |
111 | | |
112 | 0 | for (size_t j = 0; j < line; j++) |
113 | 0 | { |
114 | 0 | rc = _snprintf(&buffer[pos], blen - pos, "%c", |
115 | 0 | (p[j] >= 0x20 && p[j] < 0x7F) ? (char)p[j] : '.'); |
116 | |
|
117 | 0 | if (rc < 0) |
118 | 0 | goto fail; |
119 | | |
120 | 0 | pos += (size_t)rc; |
121 | 0 | } |
122 | | |
123 | 0 | WLog_Print(log, level, "%s", buffer); |
124 | 0 | offset += line; |
125 | 0 | p += line; |
126 | 0 | pos = 0; |
127 | 0 | } |
128 | | |
129 | 0 | WLog_Print(log, level, "[length=%" PRIuz "] ", length); |
130 | 0 | fail: |
131 | 0 | free(buffer); |
132 | 0 | } |
133 | | |
134 | | void winpr_CArrayDump(const char* tag, UINT32 level, const void* data, size_t length, size_t width) |
135 | 0 | { |
136 | 0 | const BYTE* p = data; |
137 | 0 | size_t offset = 0; |
138 | 0 | const size_t llen = ((length > width) ? width : length) * 4ull + 1ull; |
139 | 0 | size_t pos = 0; |
140 | 0 | char* buffer = malloc(llen); |
141 | |
|
142 | 0 | if (!buffer) |
143 | 0 | { |
144 | 0 | char ebuffer[256] = { 0 }; |
145 | 0 | WLog_ERR(tag, "malloc(%" PRIuz ") failed with [%d] %s", llen, errno, |
146 | 0 | winpr_strerror(errno, ebuffer, sizeof(ebuffer))); |
147 | 0 | return; |
148 | 0 | } |
149 | | |
150 | 0 | while (offset < length) |
151 | 0 | { |
152 | 0 | size_t line = length - offset; |
153 | |
|
154 | 0 | if (line > width) |
155 | 0 | line = width; |
156 | |
|
157 | 0 | pos = 0; |
158 | |
|
159 | 0 | for (size_t i = 0; i < line; i++) |
160 | 0 | { |
161 | 0 | const int rc = _snprintf(&buffer[pos], llen - pos, "\\x%02" PRIX8 "", p[i]); |
162 | 0 | if (rc < 0) |
163 | 0 | goto fail; |
164 | 0 | pos += (size_t)rc; |
165 | 0 | } |
166 | | |
167 | 0 | WLog_LVL(tag, level, "%s", buffer); |
168 | 0 | offset += line; |
169 | 0 | p += line; |
170 | 0 | } |
171 | | |
172 | 0 | fail: |
173 | 0 | free(buffer); |
174 | 0 | } |
175 | | |
176 | | static BYTE value(char c) |
177 | 0 | { |
178 | 0 | if ((c >= '0') && (c <= '9')) |
179 | 0 | return (c - '0') & 0xFF; |
180 | 0 | if ((c >= 'A') && (c <= 'F')) |
181 | 0 | return (10 + c - 'A') & 0xFF; |
182 | 0 | if ((c >= 'a') && (c <= 'f')) |
183 | 0 | return (10 + c - 'a') & 0xFF; |
184 | 0 | return 0; |
185 | 0 | } |
186 | | |
187 | | size_t winpr_HexStringToBinBuffer(const char* str, size_t strLength, BYTE* data, size_t dataLength) |
188 | 0 | { |
189 | 0 | size_t y = 0; |
190 | 0 | size_t maxStrLen = 0; |
191 | 0 | if (!str || !data || (strLength == 0) || (dataLength == 0)) |
192 | 0 | return 0; |
193 | | |
194 | 0 | maxStrLen = strnlen(str, strLength); |
195 | 0 | for (size_t x = 0; x < maxStrLen;) |
196 | 0 | { |
197 | 0 | BYTE val = value(str[x++]); |
198 | 0 | if (x < maxStrLen) |
199 | 0 | val = (BYTE)(val << 4) | (value(str[x++])); |
200 | 0 | if (x < maxStrLen) |
201 | 0 | { |
202 | 0 | if (str[x] == ' ') |
203 | 0 | x++; |
204 | 0 | } |
205 | 0 | data[y++] = val; |
206 | 0 | if (y >= dataLength) |
207 | 0 | return y; |
208 | 0 | } |
209 | 0 | return y; |
210 | 0 | } |
211 | | |
212 | | size_t winpr_BinToHexStringBuffer(const BYTE* data, size_t length, char* dstStr, size_t dstSize, |
213 | | BOOL space) |
214 | 0 | { |
215 | 0 | const size_t n = space ? 3 : 2; |
216 | 0 | const char bin2hex[] = "0123456789ABCDEF"; |
217 | 0 | const size_t maxLength = MIN(length, dstSize / n); |
218 | |
|
219 | 0 | if (!data || !dstStr || (length == 0) || (dstSize == 0)) |
220 | 0 | return 0; |
221 | | |
222 | 0 | for (size_t i = 0; i < maxLength; i++) |
223 | 0 | { |
224 | 0 | const int ln = data[i] & 0xF; |
225 | 0 | const int hn = (data[i] >> 4) & 0xF; |
226 | 0 | char* dst = &dstStr[i * n]; |
227 | |
|
228 | 0 | dst[0] = bin2hex[hn]; |
229 | 0 | dst[1] = bin2hex[ln]; |
230 | |
|
231 | 0 | if (space) |
232 | 0 | dst[2] = ' '; |
233 | 0 | } |
234 | |
|
235 | 0 | if (space && (maxLength > 0)) |
236 | 0 | { |
237 | 0 | dstStr[maxLength * n - 1] = '\0'; |
238 | 0 | return maxLength * n - 1; |
239 | 0 | } |
240 | 0 | dstStr[maxLength * n] = '\0'; |
241 | 0 | return maxLength * n; |
242 | 0 | } |
243 | | |
244 | | char* winpr_BinToHexString(const BYTE* data, size_t length, BOOL space) |
245 | 0 | { |
246 | 0 | size_t rc = 0; |
247 | 0 | const size_t n = space ? 3 : 2; |
248 | 0 | const size_t size = (length + 1ULL) * n; |
249 | 0 | char* p = (char*)malloc(size); |
250 | |
|
251 | 0 | if (!p) |
252 | 0 | return NULL; |
253 | | |
254 | 0 | rc = winpr_BinToHexStringBuffer(data, length, p, size, space); |
255 | 0 | if (rc == 0) |
256 | 0 | { |
257 | 0 | free(p); |
258 | 0 | return NULL; |
259 | 0 | } |
260 | | |
261 | 0 | return p; |
262 | 0 | } |