1 /* Copyright (c) 2002 Jeff Johnston <jjohnstn@redhat.com> */
2 /*
3 FUNCTION
4 <<a64l>>, <<l64a>>---convert between radix-64 ASCII string and long
5
6 INDEX
7 a64l
8 INDEX
9 l64a
10
11 SYNOPSIS
12 #include <stdlib.h>
13 long a64l(const char *<[input]>);
14 char *l64a(long <[input]>);
15
16 DESCRIPTION
17 Conversion is performed between long and radix-64 characters. The
18 <<l64a>> routine transforms up to 32 bits of input value starting from
19 least significant bits to the most significant bits. The input value
20 is split up into a maximum of 5 groups of 6 bits and possibly one
21 group of 2 bits (bits 31 and 30).
22
23 Each group of 6 bits forms a value from 0--63 which is translated into
24 a character as follows:
25
26 O+
27 o 0 = '.'
28 o 1 = '/'
29 o 2--11 = '0' to '9'
30 o 12--37 = 'A' to 'Z'
31 o 38--63 = 'a' to 'z'
32 O-
33
34 When the remaining bits are zero or all bits have been translated, a
35 null terminator is appended to the string. An input value of 0
36 results in the empty string.
37
38 The <<a64l>> function performs the reverse translation. Each
39 character is used to generate a 6-bit value for up to 30 bits and then
40 a 2-bit value to complete a 32-bit result. The null terminator means
41 that the remaining digits are 0. An empty input string or NULL string
42 results in 0L. An invalid string results in undefined behavior. If
43 the size of a long is greater than 32 bits, the result is sign-extended.
44
45 RETURNS
46 <<l64a>> returns a null-terminated string of 0 to 6 characters.
47 <<a64l>> returns the 32-bit translated value from the input character string.
48
49 PORTABILITY
50 <<l64a>> and <<a64l>> are non-ANSI and are defined by the Single Unix Specification.
51
52 Supporting OS subroutines required: None.
53 */
54
55 #include <_ansi.h>
56 #include <stdlib.h>
57 #include <limits.h>
58
59 long
a64l(const char * input)60 a64l (const char *input)
61 {
62 const char *ptr;
63 char ch;
64 int i, digit;
65 unsigned long result = 0;
66
67 if (input == NULL)
68 return 0;
69
70 ptr = input;
71
72 /* it easiest to go from most significant digit to least so find end of input or up
73 to 6 characters worth */
74 for (i = 0; i < 6; ++i)
75 {
76 if (*ptr)
77 ++ptr;
78 }
79
80 while (ptr > input)
81 {
82 ch = *(--ptr);
83
84 #if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
85 if (ch >= 'a')
86 digit = (ch - 'a') + 38;
87 else if (ch >= 'A')
88 digit = (ch - 'A') + 12;
89 else if (ch >= '0')
90 digit = (ch - '0') + 2;
91 else if (ch == '/')
92 digit = 1;
93 else
94 digit = 0;
95 #else /* !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) */
96 switch (ch)
97 {
98 case '/':
99 digit = 1;
100 break;
101 case '0':
102 case '1':
103 case '2':
104 case '3':
105 case '4':
106 case '5':
107 case '6':
108 case '7':
109 case '8':
110 case '9':
111 digit = (ch - '0') + 2;
112 break;
113 case 'A':
114 case 'B':
115 case 'C':
116 case 'D':
117 case 'E':
118 case 'F':
119 case 'G':
120 case 'H':
121 case 'I':
122 case 'J':
123 case 'K':
124 case 'L':
125 case 'M':
126 case 'N':
127 case 'O':
128 case 'P':
129 case 'Q':
130 case 'R':
131 case 'S':
132 case 'T':
133 case 'U':
134 case 'V':
135 case 'W':
136 case 'X':
137 case 'Y':
138 case 'Z':
139 digit = (ch - 'A') + 12;
140 break;
141 case 'a':
142 case 'b':
143 case 'c':
144 case 'd':
145 case 'e':
146 case 'f':
147 case 'g':
148 case 'h':
149 case 'i':
150 case 'j':
151 case 'k':
152 case 'l':
153 case 'm':
154 case 'n':
155 case 'o':
156 case 'p':
157 case 'q':
158 case 'r':
159 case 's':
160 case 't':
161 case 'u':
162 case 'v':
163 case 'w':
164 case 'x':
165 case 'y':
166 case 'z':
167 digit = (ch - 'a') + 38;
168 break;
169 default:
170 digit = 0;
171 break;
172 }
173 #endif /* !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) */
174
175 result = (result << 6) + digit;
176 }
177
178 return (long int) result;
179 }
180
181
182
183
184