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