Imported Upstream version 2.13.2
[platform/upstream/freetype2.git] / src / tools / vms_shorten_symbol.c
1 /*
2  * Copyright (c) 2010, 2017 Craig A. Berry
3  * 
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  * 
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19  * THE SOFTWARE.
20  */
21
22 /* vms_shorten_symbol
23  * 
24  * This program provides shortening of long symbols (> 31 characters) using the
25  * same mechanism as the OpenVMS C compiler.  The basic procedure is to compute
26  * an AUTODIN II checksum of the entire symbol, encode the checksum in base32,
27  * and glue together a shortened symbol from the first 23 characters of the 
28  * original symbol plus the encoded checksum appended.  The output format is
29  * the same used in the name mangler database, stored by default in 
30  * [.CXX_REPOSITORY]CXX$DEMANGLER_DB.
31  *
32  * To obtain the same result as CC/NAMES=SHORTENED, run like so:
33  * 
34  * $ mcr []vms_shorten_symbol "Please_forgive_this_absurdly_long_symbol_name"
35  * PLEASE_FORGIVE_THIS_ABS1ARO4QU$Please_forgive_this_absurdly_long_symbol_name
36  *
37  * To obtain the same result as CC/NAMES=(SHORTENED,AS_IS), pass a non-zero
38  * value as the second argument, like so:
39  *
40  * $ mcr []vms_shorten_symbol "Please_forgive_this_absurdly_long_symbol_name" 1
41  * Please_forgive_this_abs3rv8rnn$Please_forgive_this_absurdly_long_symbol_name
42  */
43  
44 #include <ctype.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48
49 #ifdef __VMS
50 #define UINT32 unsigned int
51 #else
52 #include <inttypes.h>
53 #define UINT32 uint32_t
54 #endif
55
56 extern UINT32 crc32(const char *input_string);
57 extern int u32_to_base32(UINT32 input, char *output);
58 extern int vms_shorten_symbol(const char *symbol, char *shortened, char as_is_flag);
59
60 /*
61  * This routine implements the AUTODIN II polynomial.
62  */
63
64 UINT32
65 crc32(const char *input_string)
66 {
67
68 /*
69  * CRC code and data based partly on FreeBSD implementation, which
70  * notes:
71  *
72  * The crc32 functions and data was originally written by Spencer
73  * Garrett <srg@quick.com> and was cleaned from the PostgreSQL source
74  * tree via the files contrib/ltree/crc32.[ch].  No license was
75  * included, therefore it is assumed that this code is public
76  * domain.  Attribution still noted.
77  *
78  * (I think they mean "gleaned" not "cleaned".)
79  */
80
81     static const UINT32 autodin_ii_table[256] = {
82         0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
83         0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
84         0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
85         0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
86         0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
87         0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
88         0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
89         0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
90         0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
91         0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
92         0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
93         0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
94         0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
95         0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
96         0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
97         0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
98         0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
99         0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
100         0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
101         0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
102         0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
103         0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
104         0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
105         0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
106         0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
107         0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
108         0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
109         0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
110         0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
111         0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
112         0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
113         0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
114         0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
115         0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
116         0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
117         0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
118         0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
119         0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
120         0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
121         0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
122         0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
123         0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
124         0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
125     };
126     
127     UINT32 crc = ~0U;
128     char *c;
129     for (c = (char *)input_string; *c; ++c)
130         crc = (crc >> 8) ^ autodin_ii_table[(crc ^ *c) & 0xff];
131     return ~crc;
132 }
133
134 /*
135  * This is the RFC2938 variant of base32, not RFC3548, Crockford's, or
136  * other newer variant.  It produces an 8-byte encoded character string
137  * (plus trailing null) from a 32-bit integer input.
138  */
139
140 int
141 u32_to_base32(UINT32 input, char *output)
142 {
143     static const char base32hex_table[32] = {
144         '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
145         'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
146         'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
147         'u', 'v'
148     };
149     int i;
150
151     /* 
152      * Grab lowest 5 bits and look up conversion in table.  Lather, rinse,
153      * repeat for a total of 7, 5-bit chunks to accommodate 32 bits of input.
154      */
155     for (i = 0; i < 7; i++) {
156         output[6 - i] = base32hex_table[input & 0x1f];
157         input >>= 5;     /* position to look at next 5 */
158     }
159     output[7] = '$';     /* It's DEC, so use '$' not '=' to pad. */
160     output[8] = '\0';    
161     return 0;    
162 }
163
164 /*
165  * Take an input symbol name of arbitrary length and produce a symbol shortened
166  * to 31 characters.  The shortened symbol consists of the first 23 characters
167  * of the original symbol plus the 8 characters of the encoded checksum.  The
168  * third argument is a boolean indicating whether to emulate the compiler's
169  * /NAMES=AS_IS option.  When false (the compiler's default), the shortened
170  * symbol will be upper cased.  When the original symbol is 31 characters or 
171  * fewer in length, no checksum will be appended and the original symbol is
172  * returned verbatim (though upper cased if the as_is_flag is false).
173  */
174
175 int
176 vms_shorten_symbol(const char *input_symbol, char *shortened, char as_is_flag)
177 {
178     char b32str[9];
179     UINT32 crc;
180     char *c, *symbol;
181     int symlen;
182
183     symlen = strlen(input_symbol);
184     symbol = (char *)malloc(symlen + 1);
185     if (symbol == NULL)
186         return -1;
187
188     strncpy(symbol, input_symbol, symlen);
189     symbol[symlen] = '\0';
190
191     if (!as_is_flag) {
192         for (c = symbol; *c; c++)
193             *c = toupper(*c);
194     }
195
196     if (symlen <= 31) {
197         strncpy(shortened, symbol, symlen);
198         shortened[symlen] = '\0';
199         free(symbol);
200         return 0;
201     }
202         
203     /*
204      * Compute the checksum on the whole symbol.
205      */
206
207     crc = crc32(symbol);
208
209     /* The compiler does not use the inverted checksum, so we invert it
210      * back before encoding in base32.
211      */
212
213     if (u32_to_base32(~crc, (char *)&b32str) == -1) {
214         free(symbol);
215         return -1;
216     }
217
218     if (!as_is_flag) {
219         for (c = (char *)&b32str; *c; c++)
220             *c = toupper(*c);
221     }
222
223     sprintf(shortened, "%.23s%.8s", symbol, b32str);
224     shortened[31] = '\0';
225     free(symbol);
226     return 0;
227 }
228
229 #ifdef TEST_MAIN
230 int
231 main(int argc, char **argv)
232 {
233     char short_symbol[32];
234     char as_is_flag = 0;
235
236     if (argc < 2) {
237         fprintf(stderr, "Usage: %s <symbol name> [<AS_IS flag>]\n", argv[0]);
238         exit(EXIT_FAILURE);
239     }
240     if (argc > 2)
241         as_is_flag = 1;
242
243     if (vms_shorten_symbol(argv[1], (char *)&short_symbol, as_is_flag) == -1) {
244         fprintf(stderr, "Symbol shortening failed\n");
245         exit(EXIT_FAILURE);
246     }
247
248     printf("%s%s\n", (char *)&short_symbol, argv[1]);
249 }
250 #endif