Fix swap of parameters when decoding base64; this could have lead to eventually to...
[citadel.git] / libcitadel / lib / stringbuf.c
index 5e89ea2f19b48f8c38edd1b5835f3754109f3379..0340ce4d44fb51e6edd50578e5d31c3a90eef890 100644 (file)
@@ -54,6 +54,12 @@ int ZEXPORT compress_gzip(Bytef * dest, size_t * destLen,
 #endif
 int BaseStrBufSize = 64;
 int EnableSplice = 0;
+int ZLibCompressionRatio = -1; /* defaults to 6 */
+#ifdef HAVE_ZLIB
+#define DEF_MEM_LEVEL 8 /*< memlevel??? */
+#define OS_CODE 0x03   /*< unix */
+const int gz_magic[2] = { 0x1f, 0x8b };        /* gzip magic header */
+#endif
 
 const char *StrBufNOTNULL = ((char*) NULL) - 1;
 
@@ -2000,32 +2006,13 @@ void StrBufXMLEscAppend(StrBuf *OutBuf,
                        *pt = *pch;
                        pt++; pch++;
                }
-               else if (*pch < 0x20) {
-                       /* we probably shouldn't be doing this */
-                       if (OverrideLowChars)
-                       {
-                               *pt = '_';
-                               pt ++;
-                               pch ++;
-                       }
-                       else
-                       {
-                               *pt = '&';
-                               pt++;
-                               *pt = HexList[*(unsigned char*)pch][0];
-                               pt ++;
-                               *pt = HexList[*(unsigned char*)pch][1];
-                               pt ++; pch ++;
-                               *pt = '&';
-                               pt++;
-                               pch ++;
-                       }
-               }
                else {
                        IsUtf8Sequence =  Ctdl_GetUtf8SequenceLength(pch, pche);
                        if (IsUtf8Sequence)
                        {
-                               while (IsUtf8Sequence > 0){
+                               while ((IsUtf8Sequence > 0) && 
+                                      (pch < pche))
+                               {
                                        *pt = *pch;
                                        pt ++;
                                        pch ++;
@@ -2823,6 +2810,8 @@ int StrBufDecodeBase64(StrBuf *Buf)
        free(Buf->buf);
        Buf->buf = xferbuf;
        Buf->BufUsed = siz;
+
+       Buf->buf[Buf->BufUsed] = '\0';
        return siz;
 }
 
@@ -2838,7 +2827,7 @@ int StrBufDecodeBase64To(const StrBuf *BufIn, StrBuf *BufOut)
                return -1;
 
        if (BufOut->BufSize < BufIn->BufUsed)
-               IncreaseBuf(BufOut, BufIn->BufUsed, 0);
+               IncreaseBuf(BufOut, 0, BufIn->BufUsed);
 
        BufOut->BufUsed = CtdlDecodeBase64(BufOut->buf,
                                           BufIn->buf,
@@ -2846,54 +2835,322 @@ int StrBufDecodeBase64To(const StrBuf *BufIn, StrBuf *BufOut)
        return BufOut->BufUsed;
 }
 
-void *StrBufNewStreamContext(eStreamType type)
+typedef struct __z_enc_stream {
+       StrBuf OutBuf;
+       z_stream zstream;
+} z_enc_stream;
+
+vStreamT *StrBufNewStreamContext(eStreamType type, const char **Err)
 {
        base64_decodestate *state;;
+       *Err = NULL;
 
        switch (type)
        {
        case eBase64Decode:
+       case eBase64Encode:
                state = (base64_decodestate*) malloc(sizeof(base64_decodestate));
                base64_init_decodestate(state);
-               return state;
+               return (vStreamT*) state;
+               break;
+       case eZLibDecode:
+       {
+
+               z_enc_stream *stream;
+               int err;
+
+               stream = (z_enc_stream *) malloc(sizeof(z_enc_stream));
+               memset(stream, 0, sizeof(z_enc_stream));
+               stream->OutBuf.BufSize = 4*SIZ; /// TODO 64
+               stream->OutBuf.buf = (char*)malloc(stream->OutBuf.BufSize);
+
+               err = inflateInit(&stream->zstream);
+
+               if (err != Z_OK) {
+                       StrBufDestroyStreamContext(type, (vStreamT**) &stream, Err);
+                       *Err = zError(err);
+                       return NULL;
+               }
+               return (vStreamT*) stream;
+
+       }
+       case eZLibEncode:
+       {
+               z_enc_stream *stream;
+               int err;
+
+               stream = (z_enc_stream *) malloc(sizeof(z_enc_stream));
+               memset(stream, 0, sizeof(z_enc_stream));
+               stream->OutBuf.BufSize = 4*SIZ; /// todo 64
+               stream->OutBuf.buf = (char*)malloc(stream->OutBuf.BufSize);
+               /* write gzip header */
+               stream->OutBuf.BufUsed = snprintf
+                       (stream->OutBuf.buf,
+                        stream->OutBuf.BufSize, 
+                        "%c%c%c%c%c%c%c%c%c%c",
+                        gz_magic[0], gz_magic[1], Z_DEFLATED,
+                        0 /*flags */ , 0, 0, 0, 0 /*time */ , 0 /* xflags */ ,
+                        OS_CODE);
+
+               err = deflateInit2(&stream->zstream,
+                                  ZLibCompressionRatio,
+                                  Z_DEFLATED,
+                                  -MAX_WBITS,
+                                  DEF_MEM_LEVEL,
+                                  Z_DEFAULT_STRATEGY);
+               if (err != Z_OK) {
+                       StrBufDestroyStreamContext(type, (vStreamT**) &stream, Err);
+                       *Err = zError(err);
+                       return NULL;
+               }
+               return (vStreamT*) stream;
+       }
+       case eEmtyCodec:
+               /// TODO
+
                break;
        }
        return NULL;
 }
 
-void StrBufDestroyStreamContext(eStreamType type, void **Stream)
+int StrBufDestroyStreamContext(eStreamType type, vStreamT **vStream, const char **Err)
 {
+       int err;
+       int rc = 0;
+       *Err = NULL;
+       
+       if ((vStream == NULL) || (*vStream==NULL)) {
+               *Err = strerror(EINVAL);
+               return EINVAL;
+       }
        switch (type)
        {
+       case eBase64Encode:
        case eBase64Decode:
-               free(*Stream);
-               *Stream = NULL;
+               free(*vStream);
+               *vStream = NULL;
                break;
+       case eZLibDecode:
+       {
+               z_enc_stream *stream = (z_enc_stream *)*vStream;
+               (void)inflateEnd(&stream->zstream);
+               free(stream->OutBuf.buf);
+               free(stream);
+       }
+       case eZLibEncode:
+       {
+               z_enc_stream *stream = (z_enc_stream *)*vStream;
+               err = deflateEnd(&stream->zstream);
+               if (err != Z_OK) {
+                       *Err = zError(err);
+                       rc = -1;
+               }
+               free(stream->OutBuf.buf);
+               free(stream);
+               *vStream = NULL;
+               break;
+       }
+       case eEmtyCodec: 
+               break; /// TODO
        }
+       return rc;
 }
-void StrBufStreamDecodeTo(StrBuf *Target, const StrBuf *In, const char* pIn, long pInLen, void *Stream)
-{
-       base64_decodestate *state = Stream;
-       long ExpectLen;
 
-       if (In != NULL)
+int StrBufStreamTranscode(eStreamType type, IOBuffer *Target, IOBuffer *In, const char* pIn, long pInLen, vStreamT *vStream, int LastChunk, const char **Err)
+{
+       int rc = 0;
+       switch (type)
        {
-               pIn = In->buf;
-               pInLen = In->BufUsed;
+       case eBase64Encode:
+       {
+               /// TODO
+/*
+               // base64_decodestate *state = (base64_decodestate*)vStream;
+               long ExpectLen;
+               
+               if (In != NULL)
+               {
+                       pIn = In->buf;
+                       pInLen = In->BufUsed;
+               }
+               if ((In == NULL) || (vStream == NULL))
+                       return;
+               
+               ExpectLen = (pInLen / 4) * 3;
+
+               if (Target->BufSize - Target->BufUsed < ExpectLen)
+               {
+                       IncreaseBuf(Target, 1, Target->BufUsed + ExpectLen + 1);
+               }
+
+               ////    ExpectLen = base64_encode_block(pIn, pInLen, Target->buf + Target->BufUsed, state);
+               Target->BufUsed += ExpectLen;
+               Target->buf[Target->BufUsed] = '\0';
+*/
        }
-       if ((pIn == NULL) || (Stream == NULL))
-               return;
-       
-       ExpectLen = (pInLen / 4) * 3;
+       break;
+       case eBase64Decode:
+       {
+/*
+               base64_decodestate *state = (base64_decodestate *)vStream;
+               long ExpectLen;
+               
+               if (In != NULL)
+               {
+                       pIn = In->buf;
+                       pInLen = In->BufUsed;
+               }
+               if ((pIn == NULL) || (vStream == NULL))
+                       return;
+               
+               ExpectLen = (pInLen / 4) * 3;
 
-       if (Target->BufSize - Target->BufUsed < ExpectLen)
+               if (Target->BufSize - Target->BufUsed < ExpectLen)
+               {
+                       IncreaseBuf(Target, 1, Target->BufUsed + ExpectLen + 1);
+               }
+
+               ExpectLen = base64_decode_block(pIn, pInLen, Target->buf + Target->BufUsed, state);
+               Target->BufUsed += ExpectLen;
+               Target->buf[Target->BufUsed] = '\0';
+*/
+       }
+       break;
+       case eZLibEncode:
        {
-               IncreaseBuf(Target, 1, Target->BufUsed + ExpectLen + 1);
+               z_enc_stream *stream = (z_enc_stream *)vStream;
+               int org_outbuf_len = stream->OutBuf.BufUsed;
+               int err;
+               unsigned int chunkavail;
+
+               if (In->ReadWritePointer != NULL)
+               {
+                       stream->zstream.next_in = (Bytef *) In->ReadWritePointer;
+                       stream->zstream.avail_in = (uInt) In->Buf->BufUsed - 
+                               (In->ReadWritePointer - In->Buf->buf);
+               }
+               else
+               {
+                       stream->zstream.next_in = (Bytef *) In->Buf->buf;
+                       stream->zstream.avail_in = (uInt) In->Buf->BufUsed;
+               }
+               
+               stream->zstream.next_out = (unsigned char*)stream->OutBuf.buf + stream->OutBuf.BufUsed;
+               stream->zstream.avail_out = chunkavail = (uInt) stream->OutBuf.BufSize - stream->OutBuf.BufUsed;
+
+               err = deflate(&stream->zstream,  (LastChunk) ? Z_FINISH : Z_NO_FLUSH);
+
+               stream->OutBuf.BufUsed += (chunkavail - stream->zstream.avail_out);
+
+               if (Target && 
+                   (LastChunk ||
+                    (stream->OutBuf.BufUsed != org_outbuf_len)
+                           ))
+               {
+                       SwapBuffers(Target->Buf, &stream->OutBuf);
+               }
+
+               if (stream->zstream.avail_in == 0)
+               {
+                       FlushStrBuf(In->Buf);
+                       In->ReadWritePointer = NULL;
+               }
+               else
+               {
+                       if (stream->zstream.avail_in < 64)
+                       {
+                               memmove(In->Buf->buf,
+                                       In->Buf->buf + In->Buf->BufUsed - stream->zstream.avail_in,
+                                       stream->zstream.avail_in);
+
+                               In->Buf->BufUsed = stream->zstream.avail_in;
+                               In->Buf->buf[In->Buf->BufUsed] = '\0';
+                       }
+                       else
+                       {
+                               
+                               In->ReadWritePointer = In->Buf->buf + 
+                                       (In->Buf->BufUsed - stream->zstream.avail_in);
+                       }
+               }
+               rc = (LastChunk && (err != Z_FINISH));
+               if (!rc && (err != Z_OK)) {
+                       *Err = zError(err);
+               }
+               
+       }
+       break;
+       case eZLibDecode: {
+               z_enc_stream *stream = (z_enc_stream *)vStream;
+               int org_outbuf_len = stream->zstream.total_out;
+               int err;
+
+               if ((stream->zstream.avail_out != 0) && (stream->zstream.next_in != NULL)) {
+                       if (In->ReadWritePointer != NULL)
+                       {
+                               stream->zstream.next_in = (Bytef *) In->ReadWritePointer;
+                               stream->zstream.avail_in = (uInt) In->Buf->BufUsed - 
+                                       (In->ReadWritePointer - In->Buf->buf);
+                       }
+                       else
+                       {
+                               stream->zstream.next_in = (Bytef *) In->Buf->buf;
+                               stream->zstream.avail_in = (uInt) In->Buf->BufUsed;
+                       }
+               }
+
+               stream->zstream.next_out = (unsigned char*)stream->OutBuf.buf + stream->OutBuf.BufUsed;
+               stream->zstream.avail_out = (uInt) stream->OutBuf.BufSize - stream->OutBuf.BufUsed;
+
+               err = inflate(&stream->zstream, Z_NO_FLUSH);
+
+               ///assert(ret != Z_STREAM_ERROR);  /* state not clobbered * /
+               switch (err) {
+               case Z_NEED_DICT:
+                       err = Z_DATA_ERROR;     /* and fall through */
+
+               case Z_DATA_ERROR:
+                       *Err = zError(err);
+               case Z_MEM_ERROR:
+                       (void)inflateEnd(&stream->zstream);
+                       return err;
+               }
+
+               stream->OutBuf.BufUsed += stream->zstream.total_out + org_outbuf_len;
+
+               if (Target) SwapBuffers(Target->Buf, &stream->OutBuf);
+
+               if (stream->zstream.avail_in == 0)
+               {
+                       FlushStrBuf(In->Buf);
+                       In->ReadWritePointer = NULL;
+               }
+               else
+               {
+                       if (stream->zstream.avail_in < 64)
+                       {
+                               memmove(In->Buf->buf,
+                                       In->Buf->buf + In->Buf->BufUsed - stream->zstream.avail_in,
+                                       stream->zstream.avail_in);
+
+                               In->Buf->BufUsed = stream->zstream.avail_in;
+                               In->Buf->buf[In->Buf->BufUsed] = '\0';
+                       }
+                       else
+                       {
+                               
+                               In->ReadWritePointer = In->Buf->buf + 
+                                       (In->Buf->BufUsed - stream->zstream.avail_in);
+                       }
+               }
        }
+               break;
+       case eEmtyCodec: {
 
-       ExpectLen = base64_decode_block(pIn, pInLen, Target->buf + Target->BufUsed, state);
-       Target->BufUsed += ExpectLen;
-       Target->buf[Target->BufUsed] = '\0';
+       }
+               break; /// TODO
+       }
+       return rc;
 }
 
 /**
@@ -3897,10 +4154,6 @@ long StrBuf_Utf8StrCut(StrBuf *Buf, int maxlen)
  *                               wrapping ZLib                                 *
  *******************************************************************************/
 
-#ifdef HAVE_ZLIB
-#define DEF_MEM_LEVEL 8 /*< memlevel??? */
-#define OS_CODE 0x03   /*< unix */
-
 /**
  * @ingroup StrBuf_DeEnCoder
  * @brief uses the same calling syntax as compress2(), but it
@@ -3911,14 +4164,13 @@ long StrBuf_Utf8StrCut(StrBuf *Buf, int maxlen)
  * @param sourceLen length of source to encode 
  * @param level compression level
  */
+#ifdef HAVE_ZLIB
 int ZEXPORT compress_gzip(Bytef * dest,
                          size_t * destLen,
                          const Bytef * source,
                          uLong sourceLen,     
                          int level)
 {
-       const int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */
-
        /* write gzip header */
        snprintf((char *) dest, *destLen, 
                 "%c%c%c%c%c%c%c%c%c%c",