added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / workbench / libs / codesetslib / src / base64.c
blob157cf750f9696beb6c3dbd4816e49172999535cb
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-2007 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"
25 #ifndef __AROS__
26 #include "SDI_stdarg.h"
27 #endif /* __AROS__ */
29 #include "debug.h"
31 /****************************************************************************/
33 struct b64
35 APTR in;
36 APTR out;
37 ULONG flags;
38 int inIndex;
39 int inAvailable;
40 int outIndex;
41 int maxLineLen;
42 int lineCounter;
43 const char *eols;
44 LONG error;
47 enum
49 B64FLG_SourceFile = 1<<0,
50 B64FLG_DestFile = 1<<1,
51 B64FLG_Unix = 1<<2,
54 /****************************************************************************/
56 #define MAXLINELEN 72
58 #ifndef EOF
59 #define EOF (-1)
60 #endif
62 /****************************************************************************/
64 static const UBYTE etable[] =
66 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
67 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
68 85, 86, 87, 88, 89, 90, 97, 98, 99, 100,
69 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
70 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
71 121, 122, 48, 49, 50, 51, 52, 53, 54, 55,
72 56, 57, 43, 47, 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, 0, 0, 0, 0,
87 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
88 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
89 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
90 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
91 0, 0, 0, 0, 0, 0
94 static const UBYTE dtable[] =
96 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
97 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
98 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
99 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
100 128, 128, 128, 62, 128, 128, 128, 63, 52, 53,
101 54, 55, 56, 57, 58, 59, 60, 61, 128, 128,
102 128, 0, 128, 128, 128, 0, 1, 2, 3, 4,
103 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
104 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
105 25, 128, 128, 128, 128, 128, 128, 26, 27, 28,
106 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
107 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
108 49, 50, 51, 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, 128, 128, 128, 128, 128,
117 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
118 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
119 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
120 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
121 128, 128, 128, 128, 128, 0
124 /****************************************************************************/
126 static BPTR
127 openIn(STRPTR name, ULONG * size)
129 struct FileInfoBlock *fib;
130 BPTR file;
132 ENTER();
134 if((fib = AllocDosObject(DOS_FIB,NULL)))
136 if((file = Open(name,MODE_OLDFILE)))
138 if(!ExamineFH(file,fib))
140 Close(file);
141 file = 0;
143 else
145 *size = fib->fib_Size;
149 FreeDosObject(DOS_FIB,fib);
151 else
152 file = 0;
154 RETURN(file);
155 return file;
158 /****************************************************************************/
160 static int
161 inchar(struct b64 *b64)
163 int c;
165 ENTER();
167 if(b64->flags & B64FLG_SourceFile)
169 if((c = FGetC((BPTR)b64->in))==EOF)
171 if(IoErr())
172 b64->error = CSR_B64_ERROR_DOS;
175 else
177 if(!b64->inAvailable)
179 RETURN(EOF);
180 return EOF;
183 c = ((STRPTR)b64->in)[b64->inIndex++];
184 b64->inAvailable--;
187 RETURN(c);
188 return c;
191 /****************************************************************************/
193 static int
194 ochar(struct b64 *b64,int c)
196 ENTER();
198 if(b64->flags & B64FLG_DestFile)
200 int r = 0;
202 if(b64->maxLineLen && (b64->lineCounter>=b64->maxLineLen))
204 r = FPuts((BPTR)b64->out,b64->eols);
205 b64->lineCounter = 0;
208 if(!r)
210 r = FPutC((BPTR)b64->out,c);
213 if(r==EOF)
215 b64->error = CSR_B64_ERROR_DOS;
217 RETURN(EOF);
218 return EOF;
221 b64->lineCounter++;
223 else
225 ((STRPTR)b64->out)[b64->outIndex++] = c;
228 RETURN(0);
229 return 0;
232 /****************************************************************************/
234 static int
235 ostring(struct b64 *b64,UBYTE * buf,int s)
237 int i;
239 ENTER();
241 if(b64->flags & B64FLG_DestFile)
243 int r;
245 for(r = i = 0; (r!=EOF) && (i<s); i++)
247 r = FPutC((BPTR)b64->out,buf[i]);
250 if(r==EOF)
252 b64->error = CSR_B64_ERROR_DOS;
254 RETURN(EOF);
255 return EOF;
258 else
260 for(i = 0; i<s; i++)
261 ((STRPTR)b64->out)[b64->outIndex++] = buf[i];
264 RETURN(0);
265 return 0;
268 /****************************************************************************/
270 static int
271 insig(struct b64 *b64)
273 int c;
275 for(;;)
277 c = inchar(b64);
279 if((c==EOF) || (c>' '))
281 RETURN(c);
282 return c;
287 /****************************************************************************/
289 #ifdef __AROS__
290 AROS_LH1(ULONG, CodesetsEncodeB64A,
291 AROS_LHA(struct TagItem *, attrs, A0),
292 struct LibraryHeader *, library, 21, Codesets
295 AROS_LIBFUNC_INIT
296 #else
297 ULONG LIBFUNC
298 CodesetsEncodeB64A(REG(a0, struct TagItem *attrs))
300 #endif
301 struct b64 b64;
302 struct TagItem *tag;
303 STRPTR source;
304 APTR dest, in, out;
305 ULONG totSize, stop, flags;
306 ULONG size;
307 int sourceLen = 0, maxLineLen;
309 flags = 0;
311 if((tag = FindTagItem(CSA_B64SourceFile,attrs)))
313 source = (STRPTR)tag->ti_Data;
314 flags |= B64FLG_SourceFile;
316 else
318 if((!(source = (STRPTR)GetTagData(CSA_B64SourceString, 0, attrs))))
320 RETURN(CSR_B64_ERROR_MEM);
321 return CSR_B64_ERROR_MEM;
324 if((tag = FindTagItem(CSA_B64SourceLen,attrs)))
325 sourceLen = tag->ti_Data;
326 else
327 sourceLen = strlen(source);
330 if((tag = FindTagItem(CSA_B64DestFile,attrs)))
332 dest = (APTR)tag->ti_Data;
333 flags |= B64FLG_DestFile;
335 else
337 if((!(dest = (APTR)GetTagData(CSA_B64DestPtr, 0, attrs))))
339 RETURN(CSR_B64_ERROR_MEM);
340 return CSR_B64_ERROR_MEM;
344 maxLineLen = GetTagData(CSA_B64MaxLineLen,0,attrs);
345 if(maxLineLen<=0 || maxLineLen>=256)
346 maxLineLen = MAXLINELEN;
348 if(GetTagData(CSA_B64Unix,TRUE,attrs))
349 flags |= B64FLG_Unix;
351 /* source */
352 if(flags & B64FLG_SourceFile)
354 if(!(in = (APTR)openIn(source,&size)))
356 RETURN(CSR_B64_ERROR_DOS);
357 return CSR_B64_ERROR_DOS;
360 b64.inAvailable = 0;
362 else
364 in = source;
365 size = sourceLen;
366 b64.inAvailable = size;
369 totSize = size<<1;
371 /* dest */
372 if(flags & B64FLG_DestFile)
374 if(!(out = (APTR)Open(dest,MODE_NEWFILE)))
376 RETURN(CSR_B64_ERROR_DOS);
377 return CSR_B64_ERROR_DOS;
380 else
382 if(!totSize)
383 totSize = 8;
385 if(!(out = allocArbitrateVecPooled(totSize)))
387 if(flags & B64FLG_SourceFile)
388 Close((BPTR)in);
390 RETURN(CSR_B64_ERROR_MEM);
391 return CSR_B64_ERROR_MEM;
394 *((STRPTR *)dest) = out;
397 /* set globals */
398 b64.in = in;
399 b64.out = out;
400 b64.flags = flags;
401 b64.inIndex = 0;
402 b64.outIndex = 0;
403 b64.maxLineLen = maxLineLen;
404 b64.lineCounter = 0;
405 b64.eols = (flags & B64FLG_Unix) ? "\n" : "\r\n";
406 b64.error = 0;
408 /* encode */
409 stop = FALSE;
410 while(!stop)
412 UBYTE igroup[3], ogroup[4];
413 int i, c, n;
415 igroup[0] = igroup[1] = igroup[2] = 0;
417 for(n = 0; n<3; n++)
419 c = inchar(&b64);
420 if(c==EOF)
422 stop = TRUE;
423 break;
426 igroup[n] = (UBYTE) c;
429 if(n>0)
431 ogroup[0] = etable[igroup[0]>>2];
432 ogroup[1] = etable[((igroup[0] & 3)<<4) | (igroup[1]>>4)];
433 ogroup[2] = etable[((igroup[1] & 0xF)<<2) | (igroup[2]>>6)];
434 ogroup[3] = etable[igroup[2] & 0x3F];
436 if(n<3)
438 ogroup[3] = '=';
439 if(n<2)
440 ogroup[2] = '=';
443 for(i=0; i<4; i++)
445 c = ochar(&b64,ogroup[i]);
446 if(c==EOF)
448 stop = TRUE;
449 break;
455 if(!(b64.flags & B64FLG_DestFile))
456 ((STRPTR)out)[b64.outIndex] = 0;
458 /* close source */
459 if(flags & B64FLG_SourceFile)
460 Close((BPTR)in);
462 /* flush and close dest */
463 if(flags & B64FLG_DestFile)
465 if(!b64.error)
467 if(FPuts((BPTR)out,b64.eols)==EOF)
468 b64.error = CSR_B64_ERROR_DOS;
470 #if defined(__amigaos4__)
471 FFlush((BPTR)out);
472 #else
473 Flush((BPTR)out);
474 #endif
477 Close((BPTR)out);
479 else
481 if(b64.error)
483 freeArbitratePooled(out,totSize);
487 RETURN((ULONG)b64.error);
488 return (ULONG)b64.error;
489 #ifdef __AROS__
490 AROS_LIBFUNC_EXIT
491 #endif
494 #ifndef __AROS__
495 LIBSTUB(CodesetsEncodeB64A, ULONG, REG(a0, struct TagItem *attrs))
497 #ifdef __MORPHOS__
498 return CodesetsEncodeB64A((struct TagItem *)REG_A0);
499 #else
500 return CodesetsEncodeB64A(attrs);
501 #endif
503 #endif
505 #ifdef __amigaos4__
506 LIBSTUBVA(CodesetsEncodeB64, ULONG, ...)
508 ULONG res;
509 VA_LIST args;
511 VA_START(args, self);
512 res = CodesetsEncodeB64A(VA_ARG(args, struct TagItem *));
513 VA_END(args);
515 return res;
517 #endif
519 /****************************************************************************/
521 #ifdef __AROS__
522 AROS_LH1(ULONG, CodesetsDecodeB64A,
523 AROS_LHA(struct TagItem *, attrs, A0),
524 struct LibraryHeader *, library, 22, Codesets
527 AROS_LIBFUNC_INIT
528 #else
529 ULONG LIBFUNC
530 CodesetsDecodeB64A(REG(a0, struct TagItem *attrs))
532 #endif
533 struct b64 b64;
534 struct TagItem *tag;
535 STRPTR source;
536 APTR dest, in, out;
537 ULONG totSize, flags, errcheck;
538 ULONG size;
539 int sourceLen = 0;
541 ENTER();
543 flags = 0;
545 if((tag = FindTagItem(CSA_B64SourceFile,attrs)))
547 source = (STRPTR)tag->ti_Data;
548 flags |= B64FLG_SourceFile;
550 else
552 if (!(source = (STRPTR)GetTagData(CSA_B64SourceString,0,attrs)))
554 RETURN(CSR_B64_ERROR_MEM);
555 return CSR_B64_ERROR_MEM;
558 if((tag = FindTagItem(CSA_B64SourceLen,attrs)))
559 sourceLen = tag->ti_Data;
560 else
561 sourceLen = strlen(source);
564 if((tag = FindTagItem(CSA_B64DestFile,attrs)))
566 dest = (APTR)tag->ti_Data;
567 flags |= B64FLG_DestFile;
569 else
571 if(!(dest = (APTR)GetTagData(CSA_B64DestPtr, 0, attrs)))
573 RETURN(CSR_B64_ERROR_MEM);
574 return CSR_B64_ERROR_MEM;
578 /* source */
579 if(flags & B64FLG_SourceFile)
581 if(!(in = (APTR)openIn(source,&size)))
583 RETURN(CSR_B64_ERROR_DOS);
584 return CSR_B64_ERROR_DOS;
587 b64.inAvailable = 0;
589 else
591 in = source;
592 size = sourceLen;
593 b64.inAvailable = size;
596 totSize = size<<1;
598 /* dest */
599 if(flags & B64FLG_DestFile)
601 if(!(out = (APTR)Open(dest,MODE_NEWFILE)))
603 RETURN(CSR_B64_ERROR_DOS);
604 return CSR_B64_ERROR_DOS;
607 else
609 if(!totSize)
610 totSize = 8;
612 if(!(out = allocArbitrateVecPooled(totSize)))
614 if(flags & B64FLG_SourceFile)
615 Close((BPTR)in);
617 RETURN(CSR_B64_ERROR_MEM);
618 return CSR_B64_ERROR_MEM;
621 *((STRPTR *)dest) = out;
624 b64.in = in;
625 b64.out = out;
626 b64.flags = flags;
627 b64.inIndex = 0;
628 b64.outIndex = 0;
629 b64.maxLineLen = 0;
630 b64.lineCounter = 0;
631 b64.eols = NULL;
632 b64.error = 0;
634 /* parse error check */
635 errcheck = !GetTagData(CSA_B64FLG_NtCheckErr,FALSE,attrs);
637 /* decode */
638 for(;;)
640 UBYTE a[4], b[4], o[3];
641 int i;
643 for(i = 0; i<4; i++)
645 int c = insig (&b64);
647 if(c==EOF)
649 if(!(b64.flags & B64FLG_DestFile))
650 ((STRPTR)out)[b64.outIndex] = 0;
652 if(!b64.error && errcheck && (i>0))
653 b64.error = CSR_B64_ERROR_INCOMPLETE;
655 goto end;
658 if(dtable[c] & 0x80)
660 if(errcheck)
662 b64.error = CSR_B64_ERROR_ILLEGAL;
664 goto end;
667 i--;
668 continue;
671 a[i] = (UBYTE) c;
672 b[i] = (UBYTE) dtable[c];
675 o[0] = (b[0]<<2) | (b[1]>>4);
676 o[1] = (b[1]<<4) | (b[2]>>2);
677 o[2] = (b[2]<<6) | b[3];
679 i = a[2]=='=' ? 1 : (a[3]=='=' ? 2 : 3);
681 if(ostring(&b64,o,i)==EOF || i < 3)
682 goto end;
685 end:
687 /* close source */
688 if(flags & B64FLG_SourceFile)
689 Close((BPTR)in);
691 /* flush and close dest */
692 if(flags & B64FLG_DestFile)
694 if(!b64.error)
696 if(FPuts((BPTR)out,b64.eols)==EOF)
697 b64.error = CSR_B64_ERROR_DOS;
699 #if defined(__amigaos4__)
700 FFlush((BPTR)out);
701 #else
702 Flush((BPTR)out);
703 #endif
706 Close((BPTR)out);
708 else
710 if(b64.error)
712 freeArbitratePooled(out,totSize);
716 RETURN((ULONG)b64.error);
717 return (ULONG)b64.error;
718 #ifdef __AROS__
719 AROS_LIBFUNC_EXIT
720 #endif
723 #ifndef __AROS__
724 LIBSTUB(CodesetsDecodeB64A, ULONG, REG(a0, struct TagItem *attrs))
726 #ifdef __MORPHOS__
727 return CodesetsDecodeB64A((struct TagItem *)REG_A0);
728 #else
729 return CodesetsDecodeB64A(attrs);
730 #endif
732 #endif
734 #ifdef __amigaos4__
735 LIBSTUBVA(CodesetsDecodeB64, ULONG, ...)
737 ULONG res;
738 VA_LIST args;
740 VA_START(args, self);
741 res = CodesetsDecodeB64A(VA_ARG(args, struct TagItem *));
742 VA_END(args);
744 return res;
746 #endif
748 /****************************************************************************/