|
|
1.1.1.3 ! root 1: /* Deprecated/legacy */ ! 2: 1.1 root 3: /* crypto/des/des_locl.org */ 4: /* Copyright (C) 1995-1997 Eric Young ([email protected]) 5: * All rights reserved. 6: * 7: * This package is an SSL implementation written 8: * by Eric Young ([email protected]). 9: * The implementation was written so as to conform with Netscapes SSL. 10: * 11: * This library is free for commercial and non-commercial use as long as 12: * the following conditions are aheared to. The following conditions 13: * apply to all code found in this distribution, be it the RC4, RSA, 14: * lhash, DES, etc., code; not just the SSL code. The SSL documentation 15: * included with this distribution is covered by the same copyright terms 16: * except that the holder is Tim Hudson ([email protected]). 17: * 18: * Copyright remains Eric Young's, and as such any Copyright notices in 19: * the code are not to be removed. 20: * If this package is used in a product, Eric Young should be given attribution 21: * as the author of the parts of the library used. 22: * This can be in the form of a textual message at program startup or 23: * in documentation (online or textual) provided with the package. 24: * 25: * Redistribution and use in source and binary forms, with or without 26: * modification, are permitted provided that the following conditions 27: * are met: 28: * 1. Redistributions of source code must retain the copyright 29: * notice, this list of conditions and the following disclaimer. 30: * 2. Redistributions in binary form must reproduce the above copyright 31: * notice, this list of conditions and the following disclaimer in the 32: * documentation and/or other materials provided with the distribution. 33: * 3. All advertising materials mentioning features or use of this software 34: * must display the following acknowledgement: 35: * "This product includes cryptographic software written by 36: * Eric Young ([email protected])" 37: * The word 'cryptographic' can be left out if the rouines from the library 38: * being used are not cryptographic related :-). 39: * 4. If you include any Windows specific code (or a derivative thereof) from 40: * the apps directory (application code) you must include an acknowledgement: 41: * "This product includes software written by Tim Hudson ([email protected])" 42: * 43: * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 44: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 45: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 46: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 47: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 48: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 49: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 50: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 51: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 52: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 53: * SUCH DAMAGE. 54: * 55: * The licence and distribution terms for any publically available version or 56: * derivative of this code cannot be changed. i.e. this code cannot simply be 57: * copied and put under another distribution licence 58: * [including the GNU Public Licence.] 59: */ 60: 61: /* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 62: * 63: * Always modify des_locl.org since des_locl.h is automatically generated from 64: * it during SSLeay configuration. 65: * 66: * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 67: */ 68: 69: #ifndef HEADER_DES_LOCL_H 70: #define HEADER_DES_LOCL_H 71: 72: #if defined(WIN32) || defined(WIN16) 73: #ifndef MSDOS 74: #define MSDOS 75: #endif 76: #endif 77: 1.1.1.2 root 78: #ifndef LINUX_DRIVER 1.1 root 79: #include <stdio.h> 80: #include <stdlib.h> 81: #ifndef MSDOS 82: #include <unistd.h> 83: #endif 1.1.1.2 root 84: #endif 85: #include "Des.h" 1.1 root 86: 87: #ifndef DES_DEFAULT_OPTIONS 88: /* the following is tweaked from a config script, that is why it is a 89: * protected undef/define */ 90: #ifndef DES_PTR 91: #define DES_PTR 92: #endif 93: 94: /* This helps C compiler generate the correct code for multiple functional 95: * units. It reduces register dependancies at the expense of 2 more 96: * registers */ 97: #ifndef DES_RISC1 98: #define DES_RISC1 99: #endif 100: 101: #ifndef DES_RISC2 102: #undef DES_RISC2 103: #endif 104: 105: #if defined(DES_RISC1) && defined(DES_RISC2) 106: YOU SHOULD NOT HAVE BOTH DES_RISC1 AND DES_RISC2 DEFINED!!!!! 107: #endif 108: 109: /* Unroll the inner loop, this sometimes helps, sometimes hinders. 110: * Very mucy CPU dependant */ 111: #ifndef DES_UNROLL 112: #define DES_UNROLL 113: #endif 114: 115: /* These default values were supplied by 116: * Peter Gutman <[email protected]> 117: * They are only used if nothing else has been defined */ 118: #if !defined(DES_PTR) && !defined(DES_RISC1) && !defined(DES_RISC2) && !defined(DES_UNROLL) 119: /* Special defines which change the way the code is built depending on the 120: CPU and OS. For SGI machines you can use _MIPS_SZLONG (32 or 64) to find 121: even newer MIPS CPU's, but at the moment one size fits all for 122: optimization options. Older Sparc's work better with only UNROLL, but 123: there's no way to tell at compile time what it is you're running on */ 124: 125: #if defined( sun ) /* Newer Sparc's */ 126: #define DES_PTR 127: #define DES_RISC1 128: #define DES_UNROLL 129: #elif defined( __ultrix ) /* Older MIPS */ 130: #define DES_PTR 131: #define DES_RISC2 132: #define DES_UNROLL 133: #elif defined( __osf1__ ) /* Alpha */ 134: #define DES_PTR 135: #define DES_RISC2 136: #elif defined ( _AIX ) /* RS6000 */ 137: /* Unknown */ 138: #elif defined( __hpux ) /* HP-PA */ 139: /* Unknown */ 140: #elif defined( __aux ) /* 68K */ 141: /* Unknown */ 142: #elif defined( __dgux ) /* 88K (but P6 in latest boxes) */ 143: #define DES_UNROLL 144: #elif defined( __sgi ) /* Newer MIPS */ 145: #define DES_PTR 146: #define DES_RISC2 147: #define DES_UNROLL 148: #elif defined( i386 ) /* x86 boxes, should be gcc */ 149: #define DES_PTR 150: #define DES_RISC1 151: #define DES_UNROLL 152: #endif /* Systems-specific speed defines */ 153: #endif 154: 155: #endif /* DES_DEFAULT_OPTIONS */ 156: 157: #ifdef MSDOS /* Visual C++ 2.1 (Windows NT/95) */ 158: #include <stdlib.h> 159: #include <errno.h> 160: #include <time.h> 161: #include <io.h> 162: #ifndef RAND 163: #define RAND 164: #endif 165: #undef NOPROTO 166: #endif 167: 168: #if defined(__STDC__) || defined(VMS) || defined(M_XENIX) || defined(MSDOS) 1.1.1.2 root 169: #ifndef LINUX_DRIVER 1.1 root 170: #include <string.h> 171: #endif 1.1.1.2 root 172: #endif 1.1 root 173: 174: #ifndef RAND 175: #define RAND 176: #endif 177: 178: #ifdef linux 179: #undef RAND 180: #endif 181: 182: #ifdef MSDOS 183: #define getpid() 2 184: #define RAND 185: #undef NOPROTO 186: #endif 187: 188: #if defined(NOCONST) 189: #define const 190: #endif 191: 192: #ifdef __STDC__ 193: #undef NOPROTO 194: #endif 195: 196: #ifdef RAND 197: #define srandom(s) srand(s) 198: #define random rand 199: #endif 200: 201: #define ITERATIONS 16 202: #define HALF_ITERATIONS 8 203: 204: /* used in des_read and des_write */ 205: #define MAXWRITE (1024*16) 206: #define BSIZE (MAXWRITE+4) 207: 208: #define c2l(c,l) (l =((DES_LONG)(*((c)++))) , \ 209: l|=((DES_LONG)(*((c)++)))<< 8L, \ 210: l|=((DES_LONG)(*((c)++)))<<16L, \ 211: l|=((DES_LONG)(*((c)++)))<<24L) 212: 213: /* NOTE - c is not incremented as per c2l */ 214: #define c2ln(c,l1,l2,n) { \ 215: c+=n; \ 216: l1=l2=0; \ 217: switch (n) { \ 218: case 8: l2 =((DES_LONG)(*(--(c))))<<24L; \ 219: case 7: l2|=((DES_LONG)(*(--(c))))<<16L; \ 220: case 6: l2|=((DES_LONG)(*(--(c))))<< 8L; \ 221: case 5: l2|=((DES_LONG)(*(--(c)))); \ 222: case 4: l1 =((DES_LONG)(*(--(c))))<<24L; \ 223: case 3: l1|=((DES_LONG)(*(--(c))))<<16L; \ 224: case 2: l1|=((DES_LONG)(*(--(c))))<< 8L; \ 225: case 1: l1|=((DES_LONG)(*(--(c)))); \ 226: } \ 227: } 228: 229: #define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \ 230: *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \ 231: *((c)++)=(unsigned char)(((l)>>16L)&0xff), \ 232: *((c)++)=(unsigned char)(((l)>>24L)&0xff)) 233: 234: /* replacements for htonl and ntohl since I have no idea what to do 235: * when faced with machines with 8 byte longs. */ 236: #define HDRSIZE 4 237: 238: #define n2l(c,l) (l =((DES_LONG)(*((c)++)))<<24L, \ 239: l|=((DES_LONG)(*((c)++)))<<16L, \ 240: l|=((DES_LONG)(*((c)++)))<< 8L, \ 241: l|=((DES_LONG)(*((c)++)))) 242: 243: #define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \ 244: *((c)++)=(unsigned char)(((l)>>16L)&0xff), \ 245: *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \ 246: *((c)++)=(unsigned char)(((l) )&0xff)) 247: 248: /* NOTE - c is not incremented as per l2c */ 249: #define l2cn(l1,l2,c,n) { \ 250: c+=n; \ 251: switch (n) { \ 252: case 8: *(--(c))=(unsigned char)(((l2)>>24L)&0xff); \ 253: case 7: *(--(c))=(unsigned char)(((l2)>>16L)&0xff); \ 254: case 6: *(--(c))=(unsigned char)(((l2)>> 8L)&0xff); \ 255: case 5: *(--(c))=(unsigned char)(((l2) )&0xff); \ 256: case 4: *(--(c))=(unsigned char)(((l1)>>24L)&0xff); \ 257: case 3: *(--(c))=(unsigned char)(((l1)>>16L)&0xff); \ 258: case 2: *(--(c))=(unsigned char)(((l1)>> 8L)&0xff); \ 259: case 1: *(--(c))=(unsigned char)(((l1) )&0xff); \ 260: } \ 261: } 262: 263: //#if defined(WIN32) 264: //#define ROTATE(a,n) (_lrotr(a,n)) 265: //#else 266: #define ROTATE(a,n) (((a)>>(n))+((a)<<(32-(n)))) 267: //#endif 268: 269: /* Don't worry about the LOAD_DATA() stuff, that is used by 270: * fcrypt() to add it's little bit to the front */ 271: 272: #ifdef DES_FCRYPT 273: 274: #define LOAD_DATA_tmp(R,S,u,t,E0,E1) \ 275: { DES_LONG tmp; LOAD_DATA(R,S,u,t,E0,E1,tmp); } 276: 277: #define LOAD_DATA(R,S,u,t,E0,E1,tmp) \ 278: t=R^(R>>16L); \ 279: u=t&E0; t&=E1; \ 280: tmp=(u<<16); u^=R^s[S ]; u^=tmp; \ 281: tmp=(t<<16); t^=R^s[S+1]; t^=tmp 282: #else 283: #define LOAD_DATA_tmp(a,b,c,d,e,f) LOAD_DATA(a,b,c,d,e,f,g) 284: #define LOAD_DATA(R,S,u,t,E0,E1,tmp) \ 285: u=R^s[S ]; \ 286: t=R^s[S+1] 287: #endif 288: 289: /* The changes to this macro may help or hinder, depending on the 290: * compiler and the achitecture. gcc2 always seems to do well :-). 291: * Inspired by Dana How <[email protected]> 292: * DO NOT use the alternative version on machines with 8 byte longs. 293: * It does not seem to work on the Alpha, even when DES_LONG is 4 294: * bytes, probably an issue of accessing non-word aligned objects :-( */ 295: #ifdef DES_PTR 296: 297: /* It recently occured to me that 0^0^0^0^0^0^0 == 0, so there 298: * is no reason to not xor all the sub items together. This potentially 299: * saves a register since things can be xored directly into L */ 300: 301: #if defined(DES_RISC1) || defined(DES_RISC2) 302: #ifdef DES_RISC1 303: #define D_ENCRYPT(LL,R,S) { \ 304: unsigned int u1,u2,u3; \ 305: LOAD_DATA(R,S,u,t,E0,E1,u1); \ 306: u2=(int)u>>8L; \ 307: u1=(int)u&0xfc; \ 308: u2&=0xfc; \ 309: t=ROTATE(t,4); \ 310: u>>=16L; \ 311: LL^= *(DES_LONG *)((unsigned char *)des_SP +u1); \ 312: LL^= *(DES_LONG *)((unsigned char *)des_SP+0x200+u2); \ 313: u3=(int)(u>>8L); \ 314: u1=(int)u&0xfc; \ 315: u3&=0xfc; \ 316: LL^= *(DES_LONG *)((unsigned char *)des_SP+0x400+u1); \ 317: LL^= *(DES_LONG *)((unsigned char *)des_SP+0x600+u3); \ 318: u2=(int)t>>8L; \ 319: u1=(int)t&0xfc; \ 320: u2&=0xfc; \ 321: t>>=16L; \ 322: LL^= *(DES_LONG *)((unsigned char *)des_SP+0x100+u1); \ 323: LL^= *(DES_LONG *)((unsigned char *)des_SP+0x300+u2); \ 324: u3=(int)t>>8L; \ 325: u1=(int)t&0xfc; \ 326: u3&=0xfc; \ 327: LL^= *(DES_LONG *)((unsigned char *)des_SP+0x500+u1); \ 328: LL^= *(DES_LONG *)((unsigned char *)des_SP+0x700+u3); } 329: #endif 330: #ifdef DES_RISC2 331: #define D_ENCRYPT(LL,R,S) { \ 332: unsigned int u1,u2,s1,s2; \ 333: LOAD_DATA(R,S,u,t,E0,E1,u1); \ 334: u2=(int)u>>8L; \ 335: u1=(int)u&0xfc; \ 336: u2&=0xfc; \ 337: t=ROTATE(t,4); \ 338: LL^= *(DES_LONG *)((unsigned char *)des_SP +u1); \ 339: LL^= *(DES_LONG *)((unsigned char *)des_SP+0x200+u2); \ 340: s1=(int)(u>>16L); \ 341: s2=(int)(u>>24L); \ 342: s1&=0xfc; \ 343: s2&=0xfc; \ 344: LL^= *(DES_LONG *)((unsigned char *)des_SP+0x400+s1); \ 345: LL^= *(DES_LONG *)((unsigned char *)des_SP+0x600+s2); \ 346: u2=(int)t>>8L; \ 347: u1=(int)t&0xfc; \ 348: u2&=0xfc; \ 349: LL^= *(DES_LONG *)((unsigned char *)des_SP+0x100+u1); \ 350: LL^= *(DES_LONG *)((unsigned char *)des_SP+0x300+u2); \ 351: s1=(int)(t>>16L); \ 352: s2=(int)(t>>24L); \ 353: s1&=0xfc; \ 354: s2&=0xfc; \ 355: LL^= *(DES_LONG *)((unsigned char *)des_SP+0x500+s1); \ 356: LL^= *(DES_LONG *)((unsigned char *)des_SP+0x700+s2); } 357: #endif 358: #else 359: #define D_ENCRYPT(LL,R,S) { \ 360: LOAD_DATA_tmp(R,S,u,t,E0,E1); \ 361: t=ROTATE(t,4); \ 362: LL^= \ 363: *(DES_LONG *)((unsigned char *)des_SP +((u )&0xfc))^ \ 364: *(DES_LONG *)((unsigned char *)des_SP+0x200+((u>> 8L)&0xfc))^ \ 365: *(DES_LONG *)((unsigned char *)des_SP+0x400+((u>>16L)&0xfc))^ \ 366: *(DES_LONG *)((unsigned char *)des_SP+0x600+((u>>24L)&0xfc))^ \ 367: *(DES_LONG *)((unsigned char *)des_SP+0x100+((t )&0xfc))^ \ 368: *(DES_LONG *)((unsigned char *)des_SP+0x300+((t>> 8L)&0xfc))^ \ 369: *(DES_LONG *)((unsigned char *)des_SP+0x500+((t>>16L)&0xfc))^ \ 370: *(DES_LONG *)((unsigned char *)des_SP+0x700+((t>>24L)&0xfc)); } 371: #endif 372: 373: #else /* original version */ 374: 375: #if defined(DES_RISC1) || defined(DES_RISC2) 376: #ifdef DES_RISC1 377: #define D_ENCRYPT(LL,R,S) {\ 378: unsigned int u1,u2,u3; \ 379: LOAD_DATA(R,S,u,t,E0,E1,u1); \ 380: u>>=2L; \ 381: t=ROTATE(t,6); \ 382: u2=(int)u>>8L; \ 383: u1=(int)u&0x3f; \ 384: u2&=0x3f; \ 385: u>>=16L; \ 386: LL^=des_SPtrans[0][u1]; \ 387: LL^=des_SPtrans[2][u2]; \ 388: u3=(int)u>>8L; \ 389: u1=(int)u&0x3f; \ 390: u3&=0x3f; \ 391: LL^=des_SPtrans[4][u1]; \ 392: LL^=des_SPtrans[6][u3]; \ 393: u2=(int)t>>8L; \ 394: u1=(int)t&0x3f; \ 395: u2&=0x3f; \ 396: t>>=16L; \ 397: LL^=des_SPtrans[1][u1]; \ 398: LL^=des_SPtrans[3][u2]; \ 399: u3=(int)t>>8L; \ 400: u1=(int)t&0x3f; \ 401: u3&=0x3f; \ 402: LL^=des_SPtrans[5][u1]; \ 403: LL^=des_SPtrans[7][u3]; } 404: #endif 405: #ifdef DES_RISC2 406: #define D_ENCRYPT(LL,R,S) {\ 407: unsigned int u1,u2,s1,s2; \ 408: LOAD_DATA(R,S,u,t,E0,E1,u1); \ 409: u>>=2L; \ 410: t=ROTATE(t,6); \ 411: u2=(int)u>>8L; \ 412: u1=(int)u&0x3f; \ 413: u2&=0x3f; \ 414: LL^=des_SPtrans[0][u1]; \ 415: LL^=des_SPtrans[2][u2]; \ 416: s1=(int)u>>16L; \ 417: s2=(int)u>>24L; \ 418: s1&=0x3f; \ 419: s2&=0x3f; \ 420: LL^=des_SPtrans[4][s1]; \ 421: LL^=des_SPtrans[6][s2]; \ 422: u2=(int)t>>8L; \ 423: u1=(int)t&0x3f; \ 424: u2&=0x3f; \ 425: LL^=des_SPtrans[1][u1]; \ 426: LL^=des_SPtrans[3][u2]; \ 427: s1=(int)t>>16; \ 428: s2=(int)t>>24L; \ 429: s1&=0x3f; \ 430: s2&=0x3f; \ 431: LL^=des_SPtrans[5][s1]; \ 432: LL^=des_SPtrans[7][s2]; } 433: #endif 434: 435: #else 436: 437: #define D_ENCRYPT(LL,R,S) {\ 438: LOAD_DATA_tmp(R,S,u,t,E0,E1); \ 439: t=ROTATE(t,4); \ 440: LL^=\ 441: des_SPtrans[0][(u>> 2L)&0x3f]^ \ 442: des_SPtrans[2][(u>>10L)&0x3f]^ \ 443: des_SPtrans[4][(u>>18L)&0x3f]^ \ 444: des_SPtrans[6][(u>>26L)&0x3f]^ \ 445: des_SPtrans[1][(t>> 2L)&0x3f]^ \ 446: des_SPtrans[3][(t>>10L)&0x3f]^ \ 447: des_SPtrans[5][(t>>18L)&0x3f]^ \ 448: des_SPtrans[7][(t>>26L)&0x3f]; } 449: #endif 450: #endif 451: 452: /* IP and FP 453: * The problem is more of a geometric problem that random bit fiddling. 454: 0 1 2 3 4 5 6 7 62 54 46 38 30 22 14 6 455: 8 9 10 11 12 13 14 15 60 52 44 36 28 20 12 4 456: 16 17 18 19 20 21 22 23 58 50 42 34 26 18 10 2 457: 24 25 26 27 28 29 30 31 to 56 48 40 32 24 16 8 0 458: 459: 32 33 34 35 36 37 38 39 63 55 47 39 31 23 15 7 460: 40 41 42 43 44 45 46 47 61 53 45 37 29 21 13 5 461: 48 49 50 51 52 53 54 55 59 51 43 35 27 19 11 3 462: 56 57 58 59 60 61 62 63 57 49 41 33 25 17 9 1 463: 464: The output has been subject to swaps of the form 465: 0 1 -> 3 1 but the odd and even bits have been put into 466: 2 3 2 0 467: different words. The main trick is to remember that 468: t=((l>>size)^r)&(mask); 469: r^=t; 470: l^=(t<<size); 471: can be used to swap and move bits between words. 472: 473: So l = 0 1 2 3 r = 16 17 18 19 474: 4 5 6 7 20 21 22 23 475: 8 9 10 11 24 25 26 27 476: 12 13 14 15 28 29 30 31 477: becomes (for size == 2 and mask == 0x3333) 478: t = 2^16 3^17 -- -- l = 0 1 16 17 r = 2 3 18 19 479: 6^20 7^21 -- -- 4 5 20 21 6 7 22 23 480: 10^24 11^25 -- -- 8 9 24 25 10 11 24 25 481: 14^28 15^29 -- -- 12 13 28 29 14 15 28 29 482: 483: Thanks for hints from Richard Outerbridge - he told me IP&FP 484: could be done in 15 xor, 10 shifts and 5 ands. 485: When I finally started to think of the problem in 2D 486: I first got ~42 operations without xors. When I remembered 487: how to use xors :-) I got it to its final state. 488: */ 489: #define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\ 490: (b)^=(t),\ 491: (a)^=((t)<<(n))) 492: 493: #define IP(l,r) \ 494: { \ 495: register DES_LONG tt; \ 496: PERM_OP(r,l,tt, 4,0x0f0f0f0fL); \ 497: PERM_OP(l,r,tt,16,0x0000ffffL); \ 498: PERM_OP(r,l,tt, 2,0x33333333L); \ 499: PERM_OP(l,r,tt, 8,0x00ff00ffL); \ 500: PERM_OP(r,l,tt, 1,0x55555555L); \ 501: } 502: 503: #define FP(l,r) \ 504: { \ 505: register DES_LONG tt; \ 506: PERM_OP(l,r,tt, 1,0x55555555L); \ 507: PERM_OP(r,l,tt, 8,0x00ff00ffL); \ 508: PERM_OP(l,r,tt, 2,0x33333333L); \ 509: PERM_OP(r,l,tt,16,0x0000ffffL); \ 510: PERM_OP(l,r,tt, 4,0x0f0f0f0fL); \ 511: } 512: 513: extern const DES_LONG des_SPtrans[8][64]; 514: 515: #ifndef NOPROTO 516: void fcrypt_body(DES_LONG *out,des_key_schedule ks, 517: DES_LONG Eswap0, DES_LONG Eswap1); 518: #else 519: void fcrypt_body(); 520: #endif 521: 522: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.