Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / workbench / libs / codesetslib / src / base64.c
blobe72f7318c9937027d1cf0aa517546128eda1c552
1 /***************************************************************************
3 codesets.library - Amiga shared library for handling different codesets
4 Copyright (C) 2001-2005 by Alfonso [alfie] Ranieri <alforan@tin.it>.
5 Copyright (C) 2005-2009 by codesets.library Open Source Team
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 codesets.library project: http://sourceforge.net/projects/codesetslib/
19 $Id$
21 ***************************************************************************/
23 #include "lib.h"
24 #include "debug.h"
26 /****************************************************************************/
28 struct b64
30 APTR in;
31 APTR out;
32 ULONG flags;
33 int inIndex;
34 int inAvailable;
35 int outIndex;
36 int maxLineLen;
37 int lineCounter;
38 const char *eols;
39 LONG error;
42 enum
44 B64FLG_SourceFile = 1<<0,
45 B64FLG_DestFile = 1<<1,
46 B64FLG_Unix = 1<<2,
49 /****************************************************************************/
51 #define MAXLINELEN 72
53 #ifndef EOF
54 #define EOF (-1)
55 #endif
57 /****************************************************************************/
59 static const UBYTE etable[] =
61 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
62 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
63 85, 86, 87, 88, 89, 90, 97, 98, 99, 100,
64 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
65 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
66 121, 122, 48, 49, 50, 51, 52, 53, 54, 55,
67 56, 57, 43, 47, 0, 0, 0, 0, 0, 0,
68 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
69 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
70 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
71 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
72 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
73 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
74 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
75 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
76 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
77 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
78 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
79 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
80 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
81 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
82 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
83 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
84 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
85 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
86 0, 0, 0, 0, 0, 0
89 static const UBYTE dtable[] =
91 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
92 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
93 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
94 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
95 128, 128, 128, 62, 128, 128, 128, 63, 52, 53,
96 54, 55, 56, 57, 58, 59, 60, 61, 128, 128,
97 128, 0, 128, 128, 128, 0, 1, 2, 3, 4,
98 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
99 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
100 25, 128, 128, 128, 128, 128, 128, 26, 27, 28,
101 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
102 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
103 49, 50, 51, 128, 128, 128, 128, 128, 128, 128,
104 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
105 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
106 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
107 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
108 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
109 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
110 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
111 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
112 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
113 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
114 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
115 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
116 128, 128, 128, 128, 128, 0
119 /****************************************************************************/
121 #if defined(__amigaos4__)
122 static BPTR
123 openIn(STRPTR name, int64 *size)
125 BPTR file = 0;
126 struct ExamineData *exd;
128 ENTER();
130 if((exd = ExamineObjectTags(EX_StringNameInput, name, TAG_END)) != NULL)
132 if(EXD_IS_FILE(exd))
134 if((file = Open(name, MODE_OLDFILE)))
135 *size = exd->FileSize;
138 FreeDosObject(DOS_EXAMINEDATA, exd);
141 RETURN(file);
142 return file;
145 #elif defined(__MORPHOS__)
146 static BPTR
147 openIn(STRPTR name, ULONG * size)
149 struct FileInfoBlock fib;
150 BPTR file;
152 ENTER();
154 if((file = Open(name,MODE_OLDFILE)))
156 if(!ExamineFH(file,&fib))
158 Close(file);
159 file = 0;
161 else
163 *size = fib.fib_Size;
167 RETURN(file);
168 return file;
170 #else
171 static BPTR
172 openIn(STRPTR name, ULONG * size)
174 struct FileInfoBlock *fib;
175 BPTR file;
177 ENTER();
179 if((fib = AllocDosObject(DOS_FIB,NULL)))
181 if((file = Open(name,MODE_OLDFILE)))
183 if(!ExamineFH(file,fib))
185 Close(file);
186 file = 0;
188 else
190 *size = fib->fib_Size;
194 FreeDosObject(DOS_FIB,fib);
196 else
197 file = 0;
199 RETURN(file);
200 return file;
202 #endif
204 /****************************************************************************/
206 static int
207 inchar(struct b64 *b64)
209 int c;
211 ENTER();
213 if(b64->flags & B64FLG_SourceFile)
215 if((c = FGetC((BPTR)b64->in))==EOF)
217 if(IoErr())
218 b64->error = CSR_B64_ERROR_DOS;
221 else
223 if(!b64->inAvailable)
225 RETURN(EOF);
226 return EOF;
229 c = ((STRPTR)b64->in)[b64->inIndex++];
230 b64->inAvailable--;
233 RETURN(c);
234 return c;
237 /****************************************************************************/
239 static int
240 ochar(struct b64 *b64,int c)
242 ENTER();
244 if(b64->flags & B64FLG_DestFile)
246 int r = 0;
248 if(b64->maxLineLen && (b64->lineCounter>=b64->maxLineLen))
250 r = FPuts((BPTR)b64->out,b64->eols);
251 b64->lineCounter = 0;
254 if(!r)
256 r = FPutC((BPTR)b64->out,c);
259 if(r==EOF)
261 b64->error = CSR_B64_ERROR_DOS;
263 RETURN(EOF);
264 return EOF;
267 b64->lineCounter++;
269 else
271 ((STRPTR)b64->out)[b64->outIndex++] = c;
274 RETURN(0);
275 return 0;
278 /****************************************************************************/
280 static int
281 ostring(struct b64 *b64,UBYTE * buf,int s)
283 int i;
285 ENTER();
287 if(b64->flags & B64FLG_DestFile)
289 int r;
291 for(r = i = 0; (r!=EOF) && (i<s); i++)
293 r = FPutC((BPTR)b64->out,buf[i]);
296 if(r==EOF)
298 b64->error = CSR_B64_ERROR_DOS;
300 RETURN(EOF);
301 return EOF;
304 else
306 for(i = 0; i<s; i++)
307 ((STRPTR)b64->out)[b64->outIndex++] = buf[i];
310 RETURN(0);
311 return 0;
314 /****************************************************************************/
316 static int
317 insig(struct b64 *b64)
319 int c;
321 for(;;)
323 c = inchar(b64);
325 if((c==EOF) || (c>' '))
327 RETURN(c);
328 return c;
333 /****************************************************************************/
335 ULONG LIBFUNC
336 CodesetsEncodeB64A(REG(a0, struct TagItem *attrs))
338 struct b64 b64;
339 struct TagItem *tag;
340 STRPTR source;
341 APTR dest, in, out;
342 ULONG totSize, stop, flags;
343 #if defined(__amigaos4__)
344 int64 size;
345 #else
346 ULONG size;
347 #endif
348 int sourceLen = 0, maxLineLen;
350 flags = 0;
352 if((tag = FindTagItem(CSA_B64SourceFile,attrs)))
354 source = (STRPTR)tag->ti_Data;
355 flags |= B64FLG_SourceFile;
357 else
359 if((!(source = (STRPTR)GetTagData(CSA_B64SourceString, 0, attrs))))
361 RETURN(CSR_B64_ERROR_MEM);
362 return CSR_B64_ERROR_MEM;
365 if((tag = FindTagItem(CSA_B64SourceLen,attrs)))
366 sourceLen = tag->ti_Data;
367 else
368 sourceLen = strlen(source);
371 if((tag = FindTagItem(CSA_B64DestFile,attrs)))
373 dest = (APTR)tag->ti_Data;
374 flags |= B64FLG_DestFile;
376 else
378 if((!(dest = (APTR)GetTagData(CSA_B64DestPtr, 0, attrs))))
380 RETURN(CSR_B64_ERROR_MEM);
381 return CSR_B64_ERROR_MEM;
385 maxLineLen = GetTagData(CSA_B64MaxLineLen,0,attrs);
386 if(maxLineLen<=0 || maxLineLen>=256)
387 maxLineLen = MAXLINELEN;
389 if(GetTagData(CSA_B64Unix,TRUE,attrs))
390 flags |= B64FLG_Unix;
392 /* source */
393 if(flags & B64FLG_SourceFile)
395 if(!(in = (APTR)openIn(source,&size)))
397 RETURN(CSR_B64_ERROR_DOS);
398 return CSR_B64_ERROR_DOS;
401 b64.inAvailable = 0;
403 else
405 in = source;
406 size = sourceLen;
407 b64.inAvailable = size;
410 totSize = size<<1;
412 /* dest */
413 if(flags & B64FLG_DestFile)
415 if(!(out = (APTR)Open(dest,MODE_NEWFILE)))
417 RETURN(CSR_B64_ERROR_DOS);
418 return CSR_B64_ERROR_DOS;
421 else
423 if(!totSize)
424 totSize = 8;
426 if(!(out = allocArbitrateVecPooled(totSize)))
428 if(flags & B64FLG_SourceFile)
429 Close((BPTR)in);
431 RETURN(CSR_B64_ERROR_MEM);
432 return CSR_B64_ERROR_MEM;
435 *((STRPTR *)dest) = out;
438 /* set globals */
439 b64.in = in;
440 b64.out = out;
441 b64.flags = flags;
442 b64.inIndex = 0;
443 b64.outIndex = 0;
444 b64.maxLineLen = maxLineLen;
445 b64.lineCounter = 0;
446 b64.eols = (flags & B64FLG_Unix) ? "\n" : "\r\n";
447 b64.error = 0;
449 /* encode */
450 stop = FALSE;
451 while(!stop)
453 UBYTE igroup[3], ogroup[4];
454 int i, c, n;
456 igroup[0] = igroup[1] = igroup[2] = 0;
458 for(n = 0; n<3; n++)
460 c = inchar(&b64);
461 if(c==EOF)
463 stop = TRUE;
464 break;
467 igroup[n] = (UBYTE) c;
470 if(n>0)
472 ogroup[0] = etable[igroup[0]>>2];
473 ogroup[1] = etable[((igroup[0] & 3)<<4) | (igroup[1]>>4)];
474 ogroup[2] = etable[((igroup[1] & 0xF)<<2) | (igroup[2]>>6)];
475 ogroup[3] = etable[igroup[2] & 0x3F];
477 if(n<3)
479 ogroup[3] = '=';
480 if(n<2)
481 ogroup[2] = '=';
484 for(i=0; i<4; i++)
486 c = ochar(&b64,ogroup[i]);
487 if(c==EOF)
489 stop = TRUE;
490 break;
496 if(!(b64.flags & B64FLG_DestFile))
497 ((STRPTR)out)[b64.outIndex] = 0;
499 /* close source */
500 if(flags & B64FLG_SourceFile)
501 Close((BPTR)in);
503 /* flush and close dest */
504 if(flags & B64FLG_DestFile)
506 if(!b64.error)
508 if(FPuts((BPTR)out,b64.eols)==EOF)
509 b64.error = CSR_B64_ERROR_DOS;
511 #if defined(__amigaos4__)
512 FFlush((BPTR)out);
513 #else
514 Flush((BPTR)out);
515 #endif
518 Close((BPTR)out);
520 else
522 if(b64.error)
523 freeArbitrateVecPooled(out);
526 RETURN((ULONG)b64.error);
527 return (ULONG)b64.error;
530 /****************************************************************************/
532 ULONG LIBFUNC
533 CodesetsDecodeB64A(REG(a0, struct TagItem *attrs))
535 struct b64 b64;
536 struct TagItem *tag;
537 STRPTR source;
538 APTR dest, in, out;
539 ULONG totSize, flags, errcheck;
540 #if defined(__amigaos4__)
541 int64 size;
542 #else
543 ULONG size;
544 #endif
545 int sourceLen = 0;
547 ENTER();
549 flags = 0;
551 if((tag = FindTagItem(CSA_B64SourceFile,attrs)))
553 source = (STRPTR)tag->ti_Data;
554 flags |= B64FLG_SourceFile;
556 else
558 if (!(source = (STRPTR)GetTagData(CSA_B64SourceString,0,attrs)))
560 RETURN(CSR_B64_ERROR_MEM);
561 return CSR_B64_ERROR_MEM;
564 if((tag = FindTagItem(CSA_B64SourceLen,attrs)))
565 sourceLen = tag->ti_Data;
566 else
567 sourceLen = strlen(source);
570 if((tag = FindTagItem(CSA_B64DestFile,attrs)))
572 dest = (APTR)tag->ti_Data;
573 flags |= B64FLG_DestFile;
575 else
577 if(!(dest = (APTR)GetTagData(CSA_B64DestPtr, 0, attrs)))
579 RETURN(CSR_B64_ERROR_MEM);
580 return CSR_B64_ERROR_MEM;
584 /* source */
585 if(flags & B64FLG_SourceFile)
587 if(!(in = (APTR)openIn(source,&size)))
589 RETURN(CSR_B64_ERROR_DOS);
590 return CSR_B64_ERROR_DOS;
593 b64.inAvailable = 0;
595 else
597 in = source;
598 size = sourceLen;
599 b64.inAvailable = size;
602 totSize = size<<1;
604 /* dest */
605 if(flags & B64FLG_DestFile)
607 if(!(out = (APTR)Open(dest,MODE_NEWFILE)))
609 RETURN(CSR_B64_ERROR_DOS);
610 return CSR_B64_ERROR_DOS;
613 else
615 if(!totSize)
616 totSize = 8;
618 if(!(out = allocArbitrateVecPooled(totSize)))
620 if(flags & B64FLG_SourceFile)
621 Close((BPTR)in);
623 RETURN(CSR_B64_ERROR_MEM);
624 return CSR_B64_ERROR_MEM;
627 *((STRPTR *)dest) = out;
630 b64.in = in;
631 b64.out = out;
632 b64.flags = flags;
633 b64.inIndex = 0;
634 b64.outIndex = 0;
635 b64.maxLineLen = 0;
636 b64.lineCounter = 0;
637 b64.eols = NULL;
638 b64.error = 0;
640 /* parse error check */
641 errcheck = !GetTagData(CSA_B64FLG_NtCheckErr,FALSE,attrs);
643 /* decode */
644 for(;;)
646 UBYTE a[4], b[4], o[3];
647 int i;
649 for(i = 0; i<4; i++)
651 int c = insig (&b64);
653 if(c==EOF)
655 if(!(b64.flags & B64FLG_DestFile))
656 ((STRPTR)out)[b64.outIndex] = 0;
658 if(!b64.error && errcheck && (i>0))
659 b64.error = CSR_B64_ERROR_INCOMPLETE;
661 goto end;
664 if(dtable[c] & 0x80)
666 if(errcheck)
668 b64.error = CSR_B64_ERROR_ILLEGAL;
670 goto end;
673 i--;
674 continue;
677 a[i] = (UBYTE) c;
678 b[i] = (UBYTE) dtable[c];
681 o[0] = (b[0]<<2) | (b[1]>>4);
682 o[1] = (b[1]<<4) | (b[2]>>2);
683 o[2] = (b[2]<<6) | b[3];
685 i = a[2]=='=' ? 1 : (a[3]=='=' ? 2 : 3);
687 if(ostring(&b64,o,i)==EOF || i < 3)
688 goto end;
691 end:
693 /* close source */
694 if(flags & B64FLG_SourceFile)
695 Close((BPTR)in);
697 /* flush and close dest */
698 if(flags & B64FLG_DestFile)
700 if(!b64.error)
702 if(FPuts((BPTR)out,b64.eols)==EOF)
703 b64.error = CSR_B64_ERROR_DOS;
705 #if defined(__amigaos4__)
706 FFlush((BPTR)out);
707 #else
708 Flush((BPTR)out);
709 #endif
712 Close((BPTR)out);
714 else
716 if(b64.error)
717 freeArbitrateVecPooled(out);
720 RETURN((ULONG)b64.error);
721 return (ULONG)b64.error;
724 /****************************************************************************/