X-Git-Url: https://code.citadel.org/?p=citadel.git;a=blobdiff_plain;f=libcitadel%2Flib%2Fstringbuf.c;h=7b2c663656e08fd874d788250c80a5333acd2877;hp=dd15b0801807788bff5a248e45c5584253cfb86e;hb=a9876b7a9950d597b18716250fcd39856efa3153;hpb=6ae0819ac13984a0dfa583281fc0081af735c77d diff --git a/libcitadel/lib/stringbuf.c b/libcitadel/lib/stringbuf.c index dd15b0801..7b2c66365 100644 --- a/libcitadel/lib/stringbuf.c +++ b/libcitadel/lib/stringbuf.c @@ -32,6 +32,9 @@ #include "libcitadel.h" +#include "b64/cencode.h" +#include "b64/cdecode.h" + #ifdef HAVE_ICONV #include #endif @@ -51,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; @@ -2820,9 +2829,328 @@ int StrBufDecodeBase64(StrBuf *Buf) free(Buf->buf); Buf->buf = xferbuf; Buf->BufUsed = siz; + + Buf->buf[Buf->BufUsed] = '\0'; return siz; } +/** + * @ingroup StrBuf_DeEnCoder + * @brief decode a buffer from base 64 encoding; expects targetbuffer + * @param BufIn Buffor to transform + * @param BufOut Buffer to put result into + */ +int StrBufDecodeBase64To(const StrBuf *BufIn, StrBuf *BufOut) +{ + if ((BufIn == NULL) || (BufOut == NULL)) + return -1; + + if (BufOut->BufSize < BufIn->BufUsed) + IncreaseBuf(BufOut, BufIn->BufUsed, 0); + + BufOut->BufUsed = CtdlDecodeBase64(BufOut->buf, + BufIn->buf, + BufIn->BufUsed); + return BufOut->BufUsed; +} + +typedef struct __z_enc_stream { + StrBuf OutBuf; + z_stream zstream; +} z_enc_stream; + +void *StrBufNewStreamContext(eStreamType type) +{ + base64_decodestate *state;; + + switch (type) + { + case eBase64Decode: + case eBase64Encode: + state = (base64_decodestate*) malloc(sizeof(base64_decodestate)); + base64_init_decodestate(state); + return 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, (void**)&stream); + return NULL; + } + return 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, (void**) &stream); + return NULL; + } + return stream; + } + case eEmtyCodec: + /// TODO + + break; + } + return NULL; +} + +void StrBufDestroyStreamContext(eStreamType type, void **vStream) +{ + if (*vStream) { + return; + } + switch (type) + { + case eBase64Encode: + case eBase64Decode: + 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; + free(stream->OutBuf.buf); + free(stream); +// todo more? + *vStream = NULL; + break; + } + case eEmtyCodec: + break; /// TODO + } +} + +int StrBufStreamTranscode(eStreamType type, IOBuffer *Target, IOBuffer *In, const char* pIn, long pInLen, void *vStream, int LastChunk) +{ + + switch (type) + { + 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'; +*/ + } + 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) + { + 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: + { + z_enc_stream *stream = (z_enc_stream *)vStream; + int org_outbuf_len = stream->zstream.total_out; + 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); + /// todo + 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); + } + } + return (LastChunk && (err != Z_FINISH)); + + } + 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: + fprintf(stderr, "sanoteuh\n"); + 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: { + + } + break; /// TODO + } + return 0; +} + /** * @ingroup StrBuf_DeEnCoder * @brief decode a buffer from base 64 encoding; destroys original @@ -2977,7 +3305,6 @@ int StrBufRFC2047encode(StrBuf **target, const StrBuf *source) ch = (unsigned char) source->buf[i]; if ((ch < 32) || (ch > 126) || - (ch == 61) || (ch == '=') || (ch == '?') || (ch == '_') || @@ -3037,20 +3364,17 @@ StrBuf *StrBufRFC2047encodeMessage(const StrBuf *EncodeMe) Optr = OutBuf->buf + Offset; OEptr = OutBuf->buf + OutBuf->BufSize; } - if ((*ptr == '\r') || (*ptr == '\n')) + if (*ptr == '\r') { /* ignore carriage returns */ ptr ++; } - else if (*ptr == 10) { + else if (*ptr == '\n') { /* hard line break */ - if ((LinePos > 0) && (isspace(*(Optr-1)))) - { - memcpy(Optr, HKEY("=0A")); - Optr += 3; - } + memcpy(Optr, HKEY("=0A")); + Optr += 3; + LinePos += 3; ptr ++; - LinePos = 0; } else if (( (*ptr >= 32) && (*ptr <= 60) ) || ( (*ptr >= 62) && (*ptr <= 126) )) @@ -3828,10 +4152,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 @@ -3842,14 +4162,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", @@ -4190,15 +4509,23 @@ inline static void FDIOBufferFlush(FDIOBuffer *FDB) void FDIOBufferInit(FDIOBuffer *FDB, IOBuffer *IO, int FD, long TotalSendSize) { FDIOBufferFlush(FDB); - FDB->ChunkSize = - FDB->TotalSendSize = TotalSendSize; + + FDB->TotalSendSize = TotalSendSize; + if (TotalSendSize > 0) + FDB->ChunkSize = TotalSendSize; + else + { + TotalSendSize = SIZ * 10; + FDB->ChunkSize = TotalSendSize; + } FDB->IOB = IO; + #ifdef LINUX_SPLICE if (EnableSplice) pipe(FDB->SplicePipe); else #endif - FDB->ChunkBuffer = NewStrBufPlain(NULL, TotalSendSize + 1); + FDB->ChunkBuffer = NewStrBufPlain(NULL, TotalSendSize+ 1); FDB->OtherFD = FD; } @@ -4225,68 +4552,159 @@ void FDIOBufferDelete(FDIOBuffer *FDB) int FileSendChunked(FDIOBuffer *FDB, const char **Err) { ssize_t sent, pipesize; -#ifdef LINUX_SPLICE - if (EnableSplice) + + if (FDB->TotalSendSize > 0) { - if (FDB->PipeSize == 0) +#ifdef LINUX_SPLICE + if (EnableSplice) { - pipesize = splice(FDB->OtherFD, - &FDB->TotalSentAlready, - FDB->SplicePipe[1], - NULL, - FDB->ChunkSendRemain, - SPLICE_F_MOVE); + if (FDB->PipeSize == 0) + { + pipesize = splice(FDB->OtherFD, + &FDB->TotalSentAlready, + FDB->SplicePipe[1], + NULL, + FDB->ChunkSendRemain, + SPLICE_F_MOVE); - if (pipesize == -1) + if (pipesize == -1) + { + *Err = strerror(errno); + return pipesize; + } + FDB->PipeSize = pipesize; + } + sent = splice(FDB->SplicePipe[0], + NULL, + FDB->IOB->fd, + NULL, + FDB->PipeSize, + SPLICE_F_MORE | SPLICE_F_MOVE | SPLICE_F_NONBLOCK); + if (sent == -1) { *Err = strerror(errno); - return pipesize; + return sent; } - FDB->PipeSize = pipesize; + FDB->PipeSize -= sent; + FDB->ChunkSendRemain -= sent; + return sent; } - sent = splice(FDB->SplicePipe[0], - NULL, - FDB->IOB->fd, - NULL, - FDB->PipeSize, - SPLICE_F_MORE | SPLICE_F_MOVE | SPLICE_F_NONBLOCK); - if (sent == -1) + else +#endif { - *Err = strerror(errno); - return sent; + char *pRead; + long nRead = 0; + + pRead = FDB->ChunkBuffer->buf; + while ((FDB->ChunkBuffer->BufUsed < FDB->TotalSendSize) && (nRead >= 0)) + { + nRead = read(FDB->OtherFD, pRead, FDB->TotalSendSize - FDB->ChunkBuffer->BufUsed); + if (nRead > 0) { + FDB->ChunkBuffer->BufUsed += nRead; + FDB->ChunkBuffer->buf[FDB->ChunkBuffer->BufUsed] = '\0'; + } + else if (nRead == 0) {} + else return nRead; + } + + nRead = write(FDB->IOB->fd, + FDB->ChunkBuffer->buf + FDB->TotalSentAlready, + FDB->ChunkBuffer->BufUsed - FDB->TotalSentAlready); + + if (nRead >= 0) { + FDB->TotalSentAlready += nRead; + FDB->ChunkSendRemain -= nRead; + return FDB->ChunkSendRemain; + } + else { + return nRead; + } } - FDB->PipeSize -= sent; - FDB->ChunkSendRemain -= sent; - return sent; } else -#endif { - char *pRead; - long nRead = 0; - - pRead = FDB->ChunkBuffer->buf; - while ((FDB->ChunkBuffer->BufUsed < FDB->TotalSendSize) && (nRead >= 0)) +#ifdef LINUX_SPLICE + if (EnableSplice) { - nRead = read(FDB->OtherFD, pRead, FDB->TotalSendSize - FDB->ChunkBuffer->BufUsed); - if (nRead > 0) { - FDB->ChunkBuffer->BufUsed += nRead; - FDB->ChunkBuffer->buf[FDB->ChunkBuffer->BufUsed] = '\0'; + if (FDB->PipeSize == 0) + { + pipesize = splice(FDB->OtherFD, + &FDB->TotalSentAlready, + FDB->SplicePipe[1], + NULL, + SIZ * 10, + SPLICE_F_MOVE); + + if (pipesize == -1) + { + *Err = strerror(errno); + return pipesize; + } + FDB->PipeSize = pipesize; + if (pipesize == 0) + return -1; } - else if (nRead == 0) {} - else return nRead; - + sent = splice(FDB->SplicePipe[0], + NULL, + FDB->IOB->fd, + NULL, + FDB->PipeSize, + SPLICE_F_MORE | SPLICE_F_MOVE | SPLICE_F_NONBLOCK); + if (sent == -1) + { + *Err = strerror(errno); + return sent; + } + FDB->PipeSize -= sent; + FDB->ChunkSendRemain -= sent; + return sent; } + else +#endif + { + char *pRead; + long nRead = 0; + + pRead = FDB->ChunkBuffer->buf; + while ((FDB->ChunkSendRemain == 0) && + (FDB->ChunkBuffer->BufUsed < FDB->ChunkBuffer->BufSize) && + (nRead >= 0)) + { + FDB->TotalSentAlready = 0; + nRead = read(FDB->OtherFD, pRead, FDB->ChunkBuffer->BufSize - FDB->ChunkBuffer->BufUsed); + if (nRead > 0) { + FDB->ChunkBuffer->BufUsed += nRead; + FDB->ChunkBuffer->buf[FDB->ChunkBuffer->BufUsed] = '\0'; + FDB->ChunkSendRemain += nRead; + } + else if (nRead == 0) + { + return -1; + } + else + { + *Err = strerror(errno); + return nRead; + } + } - nRead = write(FDB->IOB->fd, FDB->ChunkBuffer->buf + FDB->TotalSentAlready, FDB->ChunkSendRemain); + nRead = write(FDB->IOB->fd, + FDB->ChunkBuffer->buf + FDB->TotalSentAlready, + FDB->ChunkBuffer->BufUsed - FDB->TotalSentAlready); - if (nRead >= 0) { - FDB->TotalSentAlready += nRead; - FDB->ChunkSendRemain -= nRead; - return FDB->ChunkSendRemain; - } - else { - return nRead; + if (nRead >= 0) { + FDB->TotalSentAlready += nRead; + FDB->ChunkSendRemain -= nRead; + if (FDB->ChunkSendRemain == 0) + { + FDB->ChunkBuffer->BufUsed = 0; + FDB->TotalSentAlready = 0; + } + return FDB->ChunkSendRemain; + } + else { + return nRead; + } } } }