Index: doc/src/sgml/datatype.sgml
===================================================================
RCS file: /home/cvs/pgsql/pgsql/doc/src/sgml/datatype.sgml,v
retrieving revision 1.55
diff --unified -r1.55 datatype.sgml
--- doc/src/sgml/datatype.sgml	2001/05/22 16:37:15	1.55
+++ doc/src/sgml/datatype.sgml	2001/06/22 20:09:08
@@ -48,6 +48,12 @@
 
      
       
+       bytea
+       
+       a variable-length raw string, could contain nulls
+      
+
+      
        bigint
        int8
        signed eight-byte integer
Index: doc/src/sgml/func.sgml
===================================================================
RCS file: /home/cvs/pgsql/pgsql/doc/src/sgml/func.sgml,v
retrieving revision 1.61
diff --unified -r1.61 func.sgml
--- doc/src/sgml/func.sgml	2001/06/15 21:03:07	1.61
+++ doc/src/sgml/func.sgml	2001/06/22 20:19:41
@@ -1037,6 +1037,32 @@
       a23x5
      
       
 
+     
+      
+       base64_encode(string bytea)
+      
+      text
+      
+       Uses base64 algorithm to encode binary data in string.
+       Returns text value guaranteed to contain only printable string
+      
+      base64_encode('123\\000\\001')
+      MTIzAAE=
+     
       
+
+     
+      
+       base64_decode(string text)
+      
+      bytea
+      
+       Decodes binary data from string previously 
+       encoded with base64 algorithm.
+      
+      base64_decode('MTIzAAE=')
+      123\000\001
+     
       
+
     
    
   
Index: src/backend/utils/adt/varlena.c
===================================================================
RCS file: /home/cvs/pgsql/pgsql/src/backend/utils/adt/varlena.c,v
retrieving revision 1.70
diff --unified -r1.70 varlena.c
--- src/backend/utils/adt/varlena.c	2001/05/03 19:00:36	1.70
+++ src/backend/utils/adt/varlena.c	2001/06/22 21:12:51
@@ -20,7 +20,14 @@
 #include "miscadmin.h"
 #include "utils/builtins.h"
 
+static char base64_dtable[256];
+static char base64_etable[256];
+static bool base64_tables_set=false;
+
 static int	text_cmp(text *arg1, text *arg2);
+static void init_base64_tables(void);
+static int do_base64_encode(char *in, int maxlen, char *out);
+static int do_base64_decode(char *in, int maxlen, char *out);
 
 
 /*****************************************************************************
@@ -875,3 +882,172 @@
 
 	PG_RETURN_TEXT_P(result);
 }
+
+/* base64_encode()
+ * Converts a bytea value to  base-64 encoded 'text' string
+ */
+Datum
+base64_encode(PG_FUNCTION_ARGS)
+{
+	bytea *s = PG_GETARG_BYTEA_P(0);
+	text  *result;
+	int    lenin, lenout;
+
+	lenin = VARSIZE(s) - VARHDRSZ;
+
+	result = (text *) palloc(lenin*4/3+10+VARHDRSZ);
+
+        lenout=do_base64_encode(VARDATA(s), lenin, VARDATA(result));
+
+	VARATT_SIZEP(result) = lenout+VARHDRSZ;
+
+	PG_RETURN_TEXT_P(result);
+}
+
+/* base64_decode()
+ * Converts base-64 encoded 'text' string to bytea value
+ */
+Datum
+base64_decode(PG_FUNCTION_ARGS)
+{
+	text *	s = PG_GETARG_TEXT_P(0);
+	bytea *result;
+	int    lenin, lenout;
+
+	lenin = VARSIZE(s) - VARHDRSZ;
+
+	result = (bytea *) palloc((int) lenin*3/4+10+VARHDRSZ);
+
+        lenout = do_base64_decode(VARDATA(s), lenin, VARDATA(result));
+
+	VARATT_SIZEP(result) = lenout+VARHDRSZ; 
+
+	PG_RETURN_BYTEA_P(result);
+}
+
+/* most of code lifted from public-domain base64 by John Walker */
+
+void init_base64_tables(void) {
+    int i;
+    if (base64_tables_set) return;
+
+    for (i = 0; i < 26; i++) {
+        base64_etable[i] = 'A' + i;
+        base64_etable[26 + i] = 'a' + i;
+    }
+    for (i = 0; i < 10; i++) {
+        base64_etable[52 + i] = '0' + i;
+    }
+    base64_etable[62] = '+';
+    base64_etable[63] = '/';
+
+    for (i = 0; i < 255; i++) {
+        base64_dtable[i] = 0x80;
+    }
+    for (i = 'A'; i <= 'Z'; i++) {
+        base64_dtable[i] = 0 + (i - 'A');
+    }
+    for (i = 'a'; i <= 'z'; i++) {
+        base64_dtable[i] = 26 + (i - 'a');
+    }
+    for (i = '0'; i <= '9'; i++) {
+        base64_dtable[i] = 52 + (i - '0');
+    }
+
+    base64_dtable['+'] = 62;
+    base64_dtable['/'] = 63;
+    base64_dtable['='] = 0;
+
+    base64_tables_set=true;
+}
+
+
+/* this function requires out to be already allocated, 
+   it must have (maxlen*4/3)+3 bytes 
+   returns number of characters in out
+*/
+int do_base64_encode(char *in, int maxlen, char *out)
+{
+    int i; 
+    bool hiteof = false; /* read the last character */
+    int p; 		/* index of current character */
+    char *s=out;
+    char igroup[3];
+    char ogroup[4];
+    int n;
+
+    init_base64_tables();
+
+    for(p=0;p 0) {
+            ogroup[0] = base64_etable[igroup[0] >> 2];
+            ogroup[1] = base64_etable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
+            ogroup[2] = base64_etable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
+            ogroup[3] = base64_etable[igroup[2] & 0x3F];
+
+            /* Replace characters in output stream with "=" pad
+               characters if fewer than three characters were
+               read from the end of the input stream. */
+
+            if (n < 3) {
+                ogroup[3] = '=';
+                if (n < 2) {
+                    ogroup[2] = '=';
+                }
+            }
+            for (i = 0; i < 4; i++) {
+                *s++=ogroup[i];
+            }
+        }
+    }
+    return s-out;
+}
+
+
+int do_base64_decode(char *in, int maxlen, char *out)
+{
+    int p=0;
+    int i,j;
+    char *s=out;
+    init_base64_tables();
+    while (true) {
+        char a[4], b[4], o[3];
+ 	int c;
+
+        for (i = 0; i < 4; i++) {
+            while (true) { /* get a printable character*/
+		if (p==maxlen) { /* end of string */
+                  if (i > 0) 
+		      elog(ERROR, "base64_decode: Input string incomplete");
+                  return s-out; /* done */
+                }
+                c = in[p++];
+                if ( c > ' ' ) break;
+            }
+
+            if ( (base64_dtable[c] & 0x80) || (!isprint(c)) ) 
+                    elog(ERROR, "base64_decode: Illegal character '%c' in input string.\n", c);
+            a[i] = c;
+            b[i] = base64_dtable[c];
+        }
+        o[0] = (b[0] << 2) | (b[1] >> 4);
+        o[1] = (b[1] << 4) | (b[2] >> 2);
+        o[2] = (b[2] << 6) | b[3];
+        i = a[2] == '=' ? 1 : (a[3] == '=' ? 2 : 3);
+
+        for (j=0;j