/src/boringssl/crypto/bio/hexdump.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #include <openssl/bio.h> |
16 | | |
17 | | #include <limits.h> |
18 | | #include <string.h> |
19 | | |
20 | | #include "../internal.h" |
21 | | |
22 | | |
23 | | namespace { |
24 | | // hexdump_ctx contains the state of a hexdump. |
25 | | struct hexdump_ctx { |
26 | | BIO *bio; |
27 | | char right_chars[18]; // the contents of the right-hand side, ASCII dump. |
28 | | unsigned used; // number of bytes in the current line. |
29 | | size_t n; // number of bytes total. |
30 | | unsigned indent; |
31 | | }; |
32 | | } // namespace |
33 | | |
34 | 0 | static void hexbyte(char *out, uint8_t b) { |
35 | 0 | static const char hextable[] = "0123456789abcdef"; |
36 | 0 | out[0] = hextable[b >> 4]; |
37 | 0 | out[1] = hextable[b & 0x0f]; |
38 | 0 | } |
39 | | |
40 | 0 | static char to_char(uint8_t b) { |
41 | 0 | if (b < 32 || b > 126) { |
42 | 0 | return '.'; |
43 | 0 | } |
44 | 0 | return b; |
45 | 0 | } |
46 | | |
47 | | // hexdump_write adds |len| bytes of |data| to the current hex dump described by |
48 | | // |ctx|. |
49 | | static int hexdump_write(struct hexdump_ctx *ctx, const uint8_t *data, |
50 | 0 | size_t len) { |
51 | 0 | char buf[10]; |
52 | 0 | unsigned l; |
53 | | |
54 | | // Output lines look like: |
55 | | // 00000010 2e 2f 30 31 32 33 34 35 36 37 38 ... 3c 3d // |./0123456789:;<=| |
56 | | // ^ offset ^ extra space ^ ASCII of line |
57 | |
|
58 | 0 | for (size_t i = 0; i < len; i++) { |
59 | 0 | if (ctx->used == 0) { |
60 | | // The beginning of a line. |
61 | 0 | BIO_indent(ctx->bio, ctx->indent, UINT_MAX); |
62 | |
|
63 | 0 | hexbyte(&buf[0], ctx->n >> 24); |
64 | 0 | hexbyte(&buf[2], ctx->n >> 16); |
65 | 0 | hexbyte(&buf[4], ctx->n >> 8); |
66 | 0 | hexbyte(&buf[6], ctx->n); |
67 | 0 | buf[8] = buf[9] = ' '; |
68 | 0 | if (BIO_write(ctx->bio, buf, 10) < 0) { |
69 | 0 | return 0; |
70 | 0 | } |
71 | 0 | } |
72 | | |
73 | 0 | hexbyte(buf, data[i]); |
74 | 0 | buf[2] = ' '; |
75 | 0 | l = 3; |
76 | 0 | if (ctx->used == 7) { |
77 | | // There's an additional space after the 8th byte. |
78 | 0 | buf[3] = ' '; |
79 | 0 | l = 4; |
80 | 0 | } else if (ctx->used == 15) { |
81 | | // At the end of the line there's an extra space and the bar for the |
82 | | // right column. |
83 | 0 | buf[3] = ' '; |
84 | 0 | buf[4] = '|'; |
85 | 0 | l = 5; |
86 | 0 | } |
87 | |
|
88 | 0 | if (BIO_write(ctx->bio, buf, l) < 0) { |
89 | 0 | return 0; |
90 | 0 | } |
91 | 0 | ctx->right_chars[ctx->used] = to_char(data[i]); |
92 | 0 | ctx->used++; |
93 | 0 | ctx->n++; |
94 | 0 | if (ctx->used == 16) { |
95 | 0 | ctx->right_chars[16] = '|'; |
96 | 0 | ctx->right_chars[17] = '\n'; |
97 | 0 | if (BIO_write(ctx->bio, ctx->right_chars, sizeof(ctx->right_chars)) < 0) { |
98 | 0 | return 0; |
99 | 0 | } |
100 | 0 | ctx->used = 0; |
101 | 0 | } |
102 | 0 | } |
103 | | |
104 | 0 | return 1; |
105 | 0 | } |
106 | | |
107 | | // finish flushes any buffered data in |ctx|. |
108 | 0 | static int finish(struct hexdump_ctx *ctx) { |
109 | | // See the comments in |hexdump| for the details of this format. |
110 | 0 | const unsigned n_bytes = ctx->used; |
111 | 0 | unsigned l; |
112 | 0 | char buf[5]; |
113 | |
|
114 | 0 | if (n_bytes == 0) { |
115 | 0 | return 1; |
116 | 0 | } |
117 | | |
118 | 0 | OPENSSL_memset(buf, ' ', 4); |
119 | 0 | buf[4] = '|'; |
120 | |
|
121 | 0 | for (; ctx->used < 16; ctx->used++) { |
122 | 0 | l = 3; |
123 | 0 | if (ctx->used == 7) { |
124 | 0 | l = 4; |
125 | 0 | } else if (ctx->used == 15) { |
126 | 0 | l = 5; |
127 | 0 | } |
128 | 0 | if (BIO_write(ctx->bio, buf, l) < 0) { |
129 | 0 | return 0; |
130 | 0 | } |
131 | 0 | } |
132 | | |
133 | 0 | ctx->right_chars[n_bytes] = '|'; |
134 | 0 | ctx->right_chars[n_bytes + 1] = '\n'; |
135 | 0 | if (BIO_write(ctx->bio, ctx->right_chars, n_bytes + 2) < 0) { |
136 | 0 | return 0; |
137 | 0 | } |
138 | 0 | return 1; |
139 | 0 | } |
140 | | |
141 | 0 | int BIO_hexdump(BIO *bio, const uint8_t *data, size_t len, unsigned indent) { |
142 | 0 | struct hexdump_ctx ctx; |
143 | 0 | OPENSSL_memset(&ctx, 0, sizeof(ctx)); |
144 | 0 | ctx.bio = bio; |
145 | 0 | ctx.indent = indent; |
146 | |
|
147 | 0 | if (!hexdump_write(&ctx, data, len) || !finish(&ctx)) { |
148 | 0 | return 0; |
149 | 0 | } |
150 | | |
151 | 0 | return 1; |
152 | 0 | } |