File Coverage

_hex.c
Criterion Covered Total %
statement 69 75 92.0
branch 49 62 79.0
condition n/a
subroutine n/a
pod n/a
total 118 137 86.1


line stmt bran cond sub pod time code
1             /* hex.c - conversion for hexadecimal and base32 strings.
2             *
3             * Copyright: 2008-2012 Aleksey Kravchenko
4             *
5             * Permission is hereby granted, free of charge, to any person obtaining a
6             * copy of this software and associated documentation files (the "Software"),
7             * to deal in the Software without restriction, including without limitation
8             * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9             * and/or sell copies of the Software, and to permit persons to whom the
10             * Software is furnished to do so.
11             *
12             * This program is distributed in the hope that it will be useful, but
13             * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14             * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
15             */
16             #include
17             #include
18             #include "hex.h"
19              
20             /**
21             * Convert a byte to a hexadecimal number. The result, consisting of two
22             * hexadecimal digits is stored into a buffer.
23             *
24             * @param dest the buffer to receive two symbols of hex representation
25             * @param byte the byte to decode
26             * @param upper_case flag to print string in uppercase
27             * @return pointer to the chararcter just after the written number (dest + 2)
28             */
29 984           char* rhash_print_hex_byte(char *dest, const unsigned char byte, int upper_case)
30             {
31 984 50         const char add = (upper_case ? 'A' - 10 : 'a' - 10);
32 984           unsigned char c = (byte >> 4) & 15;
33 984 100         *dest++ = (c > 9 ? c + add : c + '0');
34 984           c = byte & 15;
35 984 100         *dest++ = (c > 9 ? c + add : c + '0');
36 984           return dest;
37             }
38              
39             /**
40             * Store hexadecimal representation of a binary string to given buffer.
41             *
42             * @param dest the buffer to receive hexadecimal representation
43             * @param src binary string
44             * @param len string length
45             * @param upper_case flag to print string in uppercase
46             */
47 38           void rhash_byte_to_hex(char *dest, const unsigned char *src, unsigned len, int upper_case)
48             {
49 1022 100         while (len-- > 0) {
50 984           dest = rhash_print_hex_byte(dest, *src++, upper_case);
51             }
52 38           *dest = '\0';
53 38           }
54              
55             /**
56             * Encode a binary string to base32.
57             *
58             * @param dest the buffer to store result
59             * @param src binary string
60             * @param len string length
61             * @param upper_case flag to print string in uppercase
62             */
63 8           void rhash_byte_to_base32(char* dest, const unsigned char* src, unsigned len, int upper_case)
64             {
65 8 50         const char a = (upper_case ? 'A' : 'a');
66 8           unsigned shift = 0;
67             unsigned char word;
68 8           const unsigned char* e = src + len;
69 260 100         while (src < e) {
70 252 100         if (shift > 3) {
71 128           word = (*src & (0xFF >> shift));
72 128           shift = (shift + 5) % 8;
73 128           word <<= shift;
74 128 100         if (src + 1 < e)
75 123           word |= *(src + 1) >> (8 - shift);
76 128           ++src;
77             } else {
78 124           shift = (shift + 5) % 8;
79 124           word = ( *src >> ( (8 - shift) & 7 ) ) & 0x1F;
80 124 100         if (shift == 0) src++;
81             }
82 252 100         *dest++ = ( word < 26 ? word + a : word + '2' - 26 );
83             }
84 8           *dest = '\0';
85 8           }
86              
87             /**
88             * Encode a binary string to base64.
89             * Encoded output length is always a multiple of 4 bytes.
90             *
91             * @param dest the buffer to store result
92             * @param src binary string
93             * @param len string length
94             */
95 1           void rhash_byte_to_base64(char* dest, const unsigned char* src, unsigned len)
96             {
97             static const char* tail = "0123456789+/";
98 1           unsigned shift = 0;
99             unsigned char word;
100 1           const unsigned char* e = src + len;
101 12 100         while (src < e) {
102 11 100         if (shift > 2) {
103 6           word = (*src & (0xFF >> shift));
104 6           shift = (shift + 6) % 8;
105 6           word <<= shift;
106 6 100         if (src + 1 < e)
107 5           word |= *(src + 1) >> (8 - shift);
108 6           ++src;
109             } else {
110 5           shift = (shift + 6) % 8;
111 5           word = ( *src >> ( (8 - shift) & 7 ) ) & 0x3F;
112 5 100         if (shift == 0) src++;
113             }
114 11 100         *dest++ = ( word < 52 ? (word < 26 ? word + 'A' : word - 26 + 'a') : tail[word - 52]);
    100          
115             }
116 1 50         if (shift > 0) {
117 1           *dest++ = '=';
118 1 50         if (shift == 4) *dest++ = '=';
119             }
120 1           *dest = '\0';
121 1           }
122              
123             /* unsafe characters are "<>{}[]%#/|\^~`@:;?=&+ */
124             #define IS_GOOD_URL_CHAR(c) (isalnum((unsigned char)c) || strchr("$-_.!'(),", c))
125              
126             /**
127             * URL-encode a string.
128             *
129             * @param dst buffer to receive result or NULL to calculate
130             * the lengths of encoded string
131             * @param filename the file name
132             * @return the length of the result string
133             */
134 2           int rhash_urlencode(char *dst, const char *name)
135             {
136             const char *start;
137 2 100         if (!dst) {
138             int len;
139 9 100         for (len = 0; *name; name++) len += (IS_GOOD_URL_CHAR(*name) ? 1 : 3);
    50          
    100          
140 1           return len;
141             }
142             /* encode URL as specified by RFC 1738 */
143 9 100         for (start = dst; *name; name++) {
144 8 100         if ( IS_GOOD_URL_CHAR(*name) ) {
    50          
145 8           *dst++ = *name;
146             } else {
147 0           *dst++ = '%';
148 0           dst = rhash_print_hex_byte(dst, *name, 'A');
149             }
150             }
151 1           *dst = 0;
152 1           return (int)(dst - start);
153             }
154              
155             /**
156             * Print 64-bit number with trailing '\0' to a string buffer.
157             * if dst is NULL, then just return the length of the number.
158             *
159             * @param dst output buffer
160             * @param number the number to print
161             * @return length of the printed number (without trailing '\0')
162             */
163 9           int rhash_sprintI64(char *dst, uint64_t number)
164             {
165             /* The biggest number has 20 digits: 2^64 = 18 446 744 073 709 551 616 */
166             char buf[24], *p;
167             size_t length;
168              
169 9 50         if (dst == NULL) {
170             /* just calculate the length of the number */
171 0 0         if (number == 0) return 1;
172 0 0         for (length = 0; number != 0; number /= 10) length++;
173 0           return (int)length;
174             }
175              
176 9           p = buf + 23;
177 9           *p = '\0'; /* last symbol should be '\0' */
178 9 50         if (number == 0) {
179 0           *(--p) = '0';
180             } else {
181 46 50         for (; p >= buf && number != 0; number /= 10) {
    100          
182 37           *(--p) = '0' + (char)(number % 10);
183             }
184             }
185 9           length = buf + 23 - p;
186 9           memcpy(dst, p, length + 1);
187 9           return (int)length;
188             }