X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=libcitadel%2Flib%2Fstringbuf.c;h=8830ffc60c557308cf9f9fb42c3f3e90cb668bd1;hb=c997e60cc46af764600014690b26a04cf61fd84c;hp=5e89ea2f19b48f8c38edd1b5835f3754109f3379;hpb=e2c97f4b0f5420b21f491d6e61dca580f8772d39;p=citadel.git diff --git a/libcitadel/lib/stringbuf.c b/libcitadel/lib/stringbuf.c index 5e89ea2f1..8830ffc60 100644 --- a/libcitadel/lib/stringbuf.c +++ b/libcitadel/lib/stringbuf.c @@ -1,20 +1,18 @@ -/* - * Copyright (c) 1987-2013 by the citadel.org team - * - * This program is open source software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ +// Copyright (c) 1987-2022 by the citadel.org team +// +// This program is open source software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define _GNU_SOURCE #include "sysdep.h" @@ -54,6 +52,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; @@ -250,7 +254,7 @@ void dbg_Init(StrBuf *Buf) * @param A First one * @param B second one */ -static inline void SwapBuffers(StrBuf *A, StrBuf *B) +static inline void iSwapBuffers(StrBuf *A, StrBuf *B) { StrBuf C; @@ -260,6 +264,12 @@ static inline void SwapBuffers(StrBuf *A, StrBuf *B) } +void SwapBuffers(StrBuf *A, StrBuf *B) +{ + iSwapBuffers(A, B); +} + + /** * @ingroup StrBuf_Cast * @brief Cast operator to Plain String @@ -288,38 +298,37 @@ inline int StrLength(const StrBuf *Str) return (Str != NULL) ? Str->BufUsed : 0; } -/** - * @ingroup StrBuf_DeConstructors - * @brief local utility function to resize the buffer - * @param Buf the buffer whichs storage we should increase - * @param KeepOriginal should we copy the original buffer or just start over with a new one - * @param DestSize what should fit in after? - */ -static int IncreaseBuf(StrBuf *Buf, int KeepOriginal, int DestSize) -{ +// local utility function to resize the buffer +// Buf the buffer whichs storage we should increase +// KeepOriginal should we copy the original buffer or just start over with a new one +// DestSize what should fit in after? +static int IncreaseBuf(StrBuf *Buf, int KeepOriginal, int DestSize) { char *NewBuf; size_t NewSize = Buf->BufSize * 2; - if (Buf->ConstBuf) + if (Buf->ConstBuf) { return -1; + } - if (DestSize > 0) - while ((NewSize <= DestSize) && (NewSize != 0)) + if (DestSize > 0) { + while ((NewSize <= DestSize) && (NewSize != 0)) { NewSize *= 2; + } + } - if (NewSize == 0) + if (NewSize == 0) { return -1; + } - NewBuf= (char*) malloc(NewSize); - if (NewBuf == NULL) + NewBuf = (char*) malloc(NewSize); + if (NewBuf == NULL) { return -1; + } - if (KeepOriginal && (Buf->BufUsed > 0)) - { + if (KeepOriginal && (Buf->BufUsed > 0)) { memcpy(NewBuf, Buf->buf, Buf->BufUsed); } - else - { + else { NewBuf[0] = '\0'; Buf->BufUsed = 0; } @@ -332,18 +341,13 @@ static int IncreaseBuf(StrBuf *Buf, int KeepOriginal, int DestSize) return Buf->BufSize; } -/** - * @ingroup StrBuf_DeConstructors - * @brief shrink / increase an _EMPTY_ buffer to NewSize. Buffercontent is thoroughly ignored and flushed. - * @param Buf Buffer to shrink (has to be empty) - * @param ThreshHold if the buffer is bigger then this, its readjusted - * @param NewSize if we Shrink it, how big are we going to be afterwards? - */ -void ReAdjustEmptyBuf(StrBuf *Buf, long ThreshHold, long NewSize) -{ - if ((Buf != NULL) && - (Buf->BufUsed == 0) && - (Buf->BufSize < ThreshHold)) { + +// shrink / increase an _EMPTY_ buffer to NewSize. Buffercontent is thoroughly ignored and flushed. +// Buf Buffer to shrink (has to be empty) +// ThreshHold if the buffer is bigger then this, its readjusted +// NewSize if we Shrink it, how big are we going to be afterwards? +void ReAdjustEmptyBuf(StrBuf *Buf, long ThreshHold, long NewSize) { + if ((Buf != NULL) && (Buf->BufUsed == 0) && (Buf->BufSize < ThreshHold)) { free(Buf->buf); Buf->buf = (char*) malloc(NewSize); Buf->BufUsed = 0; @@ -351,6 +355,7 @@ void ReAdjustEmptyBuf(StrBuf *Buf, long ThreshHold, long NewSize) } } + /** * @ingroup StrBuf_DeConstructors * @brief shrink long term buffers to their real size so they don't waste memory @@ -504,7 +509,7 @@ void NewStrBufDupAppendFlush(StrBuf **CreateRelpaceMe, StrBuf *CopyFlushMe, cons } else NewBuf = *CreateRelpaceMe; - SwapBuffers (NewBuf, CopyFlushMe); + iSwapBuffers (NewBuf, CopyFlushMe); } if (!KeepOriginal) FlushStrBuf(CopyFlushMe); @@ -852,42 +857,37 @@ void StrBufAppendBuf(StrBuf *Buf, const StrBuf *AppendBuf, unsigned long Offset) return; if (Buf->BufSize - Offset < AppendBuf->BufUsed + Buf->BufUsed + 1) - IncreaseBuf(Buf, - (Buf->BufUsed > 0), - AppendBuf->BufUsed + Buf->BufUsed); + IncreaseBuf(Buf, (Buf->BufUsed > 0), AppendBuf->BufUsed + Buf->BufUsed); - memcpy(Buf->buf + Buf->BufUsed, - AppendBuf->buf + Offset, - AppendBuf->BufUsed - Offset); + memcpy(Buf->buf + Buf->BufUsed, AppendBuf->buf + Offset, AppendBuf->BufUsed - Offset); Buf->BufUsed += AppendBuf->BufUsed - Offset; Buf->buf[Buf->BufUsed] = '\0'; } -/** - * @ingroup StrBuf_Filler - * @brief Append a C-String to the buffer - * @param Buf Buffer to modify - * @param AppendBuf Buffer to copy at the end of our buffer - * @param AppendSize number of bytes to copy; set to -1 if we should count it in advance - * @param Offset Should we start copying from an offset? - */ -void StrBufAppendBufPlain(StrBuf *Buf, const char *AppendBuf, long AppendSize, unsigned long Offset) -{ +// Append a C-String to the buffer +// Buf Buffer to modify +// AppendBuf Buffer to copy at the end of our buffer +// AppendSize number of bytes to copy; set to -1 if we should count it in advance +// Offset Should we start copying from an offset? +void StrBufAppendBufPlain(StrBuf *Buf, const char *AppendBuf, long AppendSize, unsigned long Offset) { long aps; long BufSizeRequired; if ((AppendBuf == NULL) || (Buf == NULL)) return; - if (AppendSize < 0 ) + if (AppendSize < 0) { aps = strlen(AppendBuf + Offset); - else + } + else { aps = AppendSize - Offset; + } BufSizeRequired = Buf->BufUsed + aps + 1; - if (Buf->BufSize <= BufSizeRequired) + if (Buf->BufSize <= BufSizeRequired) { IncreaseBuf(Buf, (Buf->BufUsed > 0), BufSizeRequired); + } memcpy(Buf->buf + Buf->BufUsed, AppendBuf + Offset, @@ -896,7 +896,7 @@ void StrBufAppendBufPlain(StrBuf *Buf, const char *AppendBuf, long AppendSize, u Buf->buf[Buf->BufUsed] = '\0'; } -/** +/* * @ingroup StrBuf_Filler * @brief sprintf like function appending the formated string to the buffer * vsnprintf version to wrap into own calls @@ -2000,32 +2000,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 +2804,8 @@ int StrBufDecodeBase64(StrBuf *Buf) free(Buf->buf); Buf->buf = xferbuf; Buf->BufUsed = siz; + + Buf->buf[Buf->BufUsed] = '\0'; return siz; } @@ -2838,7 +2821,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 +2829,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) + { + case eBase64Encode: { - pIn = In->buf; - pInLen = In->BufUsed; + /// 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) + { + IncreaseBuf(Target, 1, Target->BufUsed + ExpectLen + 1); + } - if (Target->BufSize - Target->BufUsed < ExpectLen) + 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) + )) + { + iSwapBuffers(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; - ExpectLen = base64_decode_block(pIn, pInLen, Target->buf + Target->BufUsed, state); - Target->BufUsed += ExpectLen; - Target->buf[Target->BufUsed] = '\0'; + 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) iSwapBuffers(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 rc; } /** @@ -3510,7 +3761,7 @@ TRYAGAIN: TmpBuf->buf[TmpBuf->BufUsed] = '\0'; /* little card game: wheres the red lady? */ - SwapBuffers(ConvertBuf, TmpBuf); + iSwapBuffers(ConvertBuf, TmpBuf); FlushStrBuf(TmpBuf); } #endif @@ -3879,11 +4130,11 @@ long StrBuf_Utf8StrCut(StrBuf *Buf, int maxlen) n++; aptr++; } - if (n > maxlen) { + if (n >= maxlen) { *aptr = '\0'; Buf->BufUsed = aptr - Buf->buf; return Buf->BufUsed; - } + } } return Buf->BufUsed; @@ -3897,10 +4148,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 +4158,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", @@ -4248,421 +4494,6 @@ long IOBufferStrLength(IOBuffer *FB) return StrLength(FB->Buf) - (FB->ReadWritePointer - FB->Buf->buf); } -inline static void FDIOBufferFlush(FDIOBuffer *FDB) -{ - memset(FDB, 0, sizeof(FDIOBuffer)); - FDB->OtherFD = -1; - FDB->SplicePipe[0] = -1; - FDB->SplicePipe[1] = -1; -} - -void FDIOBufferInit(FDIOBuffer *FDB, IOBuffer *IO, int FD, long TotalSendSize) -{ - FDIOBufferFlush(FDB); - - 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->OtherFD = FD; -} - -void FDIOBufferDelete(FDIOBuffer *FDB) -{ -#ifdef LINUX_SPLICE - if (EnableSplice) - { - if (FDB->SplicePipe[0] > 0) - close(FDB->SplicePipe[0]); - if (FDB->SplicePipe[1] > 0) - close(FDB->SplicePipe[1]); - } - else -#endif - FreeStrBuf(&FDB->ChunkBuffer); - - if (FDB->OtherFD > 0) - close(FDB->OtherFD); - FDIOBufferFlush(FDB); -} - -int FileSendChunked(FDIOBuffer *FDB, const char **Err) -{ - ssize_t sent, pipesize; - - if (FDB->TotalSendSize > 0) - { -#ifdef LINUX_SPLICE - if (EnableSplice) - { - if (FDB->PipeSize == 0) - { - pipesize = splice(FDB->OtherFD, - &FDB->TotalSentAlready, - FDB->SplicePipe[1], - NULL, - FDB->ChunkSendRemain, - SPLICE_F_MOVE); - - 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 sent; - } - 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)) - { - 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; - } - } - } - else - { -#ifdef LINUX_SPLICE - if (EnableSplice) - { - 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; - } - 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->ChunkBuffer->BufUsed - FDB->TotalSentAlready); - - 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; - } - } - } -} - -int FileRecvChunked(FDIOBuffer *FDB, const char **Err) -{ - ssize_t sent, pipesize; - -#ifdef LINUX_SPLICE - if (EnableSplice) - { - if (FDB->PipeSize == 0) - { - pipesize = splice(FDB->IOB->fd, - NULL, - FDB->SplicePipe[1], - NULL, - FDB->ChunkSendRemain, - SPLICE_F_MORE | SPLICE_F_MOVE|SPLICE_F_NONBLOCK); - - if (pipesize == -1) - { - *Err = strerror(errno); - return pipesize; - } - FDB->PipeSize = pipesize; - } - - sent = splice(FDB->SplicePipe[0], - NULL, - FDB->OtherFD, - &FDB->TotalSentAlready, - FDB->PipeSize, - SPLICE_F_MORE | SPLICE_F_MOVE); - - if (sent == -1) - { - *Err = strerror(errno); - return sent; - } - FDB->PipeSize -= sent; - FDB->ChunkSendRemain -= sent; - return sent; - } - else -#endif - { - sent = read(FDB->IOB->fd, FDB->ChunkBuffer->buf, FDB->ChunkSendRemain); - if (sent > 0) { - int nWritten = 0; - int rc; - - FDB->ChunkBuffer->BufUsed = sent; - - while (nWritten < FDB->ChunkBuffer->BufUsed) { - rc = write(FDB->OtherFD, FDB->ChunkBuffer->buf + nWritten, FDB->ChunkBuffer->BufUsed - nWritten); - if (rc < 0) { - *Err = strerror(errno); - return rc; - } - nWritten += rc; - - } - FDB->ChunkBuffer->BufUsed = 0; - FDB->TotalSentAlready += sent; - FDB->ChunkSendRemain -= sent; - return FDB->ChunkSendRemain; - } - else if (sent < 0) { - *Err = strerror(errno); - return sent; - } - return 0; - } -} - -int FileMoveChunked(FDIOBuffer *FDB, const char **Err) -{ - ssize_t sent, pipesize; - -#ifdef LINUX_SPLICE - if (EnableSplice) - { - if (FDB->PipeSize == 0) - { - pipesize = splice(FDB->IOB->fd, - &FDB->TotalReadAlready, - FDB->SplicePipe[1], - NULL, - FDB->ChunkSendRemain, - SPLICE_F_MORE | SPLICE_F_MOVE|SPLICE_F_NONBLOCK); - - if (pipesize == -1) - { - *Err = strerror(errno); - return pipesize; - } - FDB->PipeSize = pipesize; - } - - sent = splice(FDB->SplicePipe[0], - NULL, - FDB->OtherFD, - &FDB->TotalSentAlready, - FDB->PipeSize, - SPLICE_F_MORE | SPLICE_F_MOVE); - - if (sent == -1) - { - *Err = strerror(errno); - return sent; - } - FDB->PipeSize -= sent; - FDB->ChunkSendRemain -= sent; - return sent; - } - else -#endif - { - sent = read(FDB->IOB->fd, FDB->ChunkBuffer->buf, FDB->ChunkSendRemain); - if (sent > 0) { - int nWritten = 0; - int rc; - - FDB->ChunkBuffer->BufUsed = sent; - - while (nWritten < FDB->ChunkBuffer->BufUsed) { - rc = write(FDB->OtherFD, FDB->ChunkBuffer->buf + nWritten, FDB->ChunkBuffer->BufUsed - nWritten); - if (rc < 0) { - *Err = strerror(errno); - return rc; - } - nWritten += rc; - - } - FDB->ChunkBuffer->BufUsed = 0; - FDB->TotalSentAlready += sent; - FDB->ChunkSendRemain -= sent; - return FDB->ChunkSendRemain; - } - else if (sent < 0) { - *Err = strerror(errno); - return sent; - } - return 0; - } -} - -eReadState WriteIOBAlreadyRead(FDIOBuffer *FDB, const char **Error) -{ - int IsNonBlock; - int fdflags; - long rlen; - long should_write; - int nSuccessLess = 0; - struct timeval tv; - fd_set rfds; - - fdflags = fcntl(FDB->OtherFD, F_GETFL); - IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK; - - while ((FDB->IOB->ReadWritePointer - FDB->IOB->Buf->buf < FDB->IOB->Buf->BufUsed) && - (FDB->ChunkSendRemain > 0)) - { - if (IsNonBlock){ - tv.tv_sec = 1; /* selectresolution; */ - tv.tv_usec = 0; - - FD_ZERO(&rfds); - FD_SET(FDB->OtherFD, &rfds); - if (select(FDB->OtherFD + 1, NULL, &rfds, NULL, &tv) == -1) { - *Error = strerror(errno); - return eReadFail; - } - } - if (IsNonBlock && ! FD_ISSET(FDB->OtherFD, &rfds)) { - nSuccessLess ++; - continue; - } - - should_write = FDB->IOB->Buf->BufUsed - - (FDB->IOB->ReadWritePointer - FDB->IOB->Buf->buf); - if (should_write > FDB->ChunkSendRemain) - should_write = FDB->ChunkSendRemain; - - rlen = write(FDB->OtherFD, - FDB->IOB->ReadWritePointer, - should_write); - if (rlen < 1) { - *Error = strerror(errno); - - return eReadFail; - } - FDB->TotalSentAlready += rlen; - FDB->IOB->ReadWritePointer += rlen; - FDB->ChunkSendRemain -= rlen; - } - if (FDB->IOB->ReadWritePointer >= FDB->IOB->Buf->buf + FDB->IOB->Buf->BufUsed) - { - FlushStrBuf(FDB->IOB->Buf); - FDB->IOB->ReadWritePointer = NULL; - } - - if (FDB->ChunkSendRemain == 0) - return eReadSuccess; - else - return eMustReadMore; -} /******************************************************************************* * File I/O; Prefer buffered read since its faster! * @@ -4716,6 +4547,7 @@ int StrBufTCP_read_line(StrBuf *buf, int *fd, int append, const char **Error) return len - slen; } + /** * @ingroup StrBuf_BufferedIO * @brief Read a line from socket @@ -5145,14 +4977,13 @@ int StrBufReadBLOBBuffered(StrBuf *Blob, pos = *Pos; - if (pos != NULL) + if (pos != NULL) { rlen = pos - IOBuf->buf; + } rlen = IOBuf->BufUsed - rlen; - if ((IOBuf->BufUsed > 0) && - (pos != NULL) && - (pos < IOBuf->buf + IOBuf->BufUsed)) + if ((IOBuf->BufUsed > 0) && (pos != NULL) && (pos < IOBuf->buf + IOBuf->BufUsed)) { if (rlen < nBytes) { memcpy(Blob->buf + Blob->BufUsed, pos, rlen); @@ -5177,8 +5008,9 @@ int StrBufReadBLOBBuffered(StrBuf *Blob, FlushStrBuf(IOBuf); *Pos = NULL; - if (IOBuf->BufSize < nBytes - nRead) + if (IOBuf->BufSize < nBytes - nRead) { IncreaseBuf(IOBuf, 0, nBytes - nRead); + } ptr = IOBuf->buf; fdflags = fcntl(*fd, F_GETFL); @@ -5190,11 +5022,8 @@ int StrBufReadBLOBBuffered(StrBuf *Blob, nBytes -= nRead; nRead = 0; - while ((nSuccessLess < MaxTries) && - (nRead < nBytes) && - (*fd != -1)) { - if (IsNonBlock) - { + while ((nSuccessLess < MaxTries) && (nRead < nBytes) && (*fd != -1)) { + if (IsNonBlock) { tv.tv_sec = 1; tv.tv_usec = 0; @@ -5204,8 +5033,9 @@ int StrBufReadBLOBBuffered(StrBuf *Blob, *Error = strerror(errno); close (*fd); *fd = -1; - if (*Error == NULL) + if (*Error == NULL) { *Error = ErrRBLF_SelectFailed; + } return -1; } if (! FD_ISSET(*fd, &rfds) != 0) { @@ -5213,20 +5043,16 @@ int StrBufReadBLOBBuffered(StrBuf *Blob, continue; } } - rlen = read(*fd, - ptr, - IOBuf->BufSize - (ptr - IOBuf->buf)); - if (rlen == -1) { + rlen = read(*fd, ptr, IOBuf->BufSize - (ptr - IOBuf->buf)); + // if (rlen == -1) { 2021feb27 ajc changed this, apparently we will always get at least 1 byte unless the connection is broken + if (rlen < 1) { close(*fd); *fd = -1; *Error = strerror(errno); return rlen; } else if (rlen == 0){ - if ((check == NNN_TERM) && - (nRead > 5) && - (strncmp(IOBuf->buf + IOBuf->BufUsed - 5, "\n000\n", 5) == 0)) - { + if ((check == NNN_TERM) && (nRead > 5) && (strncmp(IOBuf->buf + IOBuf->BufUsed - 5, "\n000\n", 5) == 0)) { StrBufPlain(Blob, HKEY("\n000\n")); StrBufCutRight(Blob, 5); return Blob->BufUsed; @@ -5364,3 +5190,44 @@ void StrBufStripSlashes(StrBuf *Dir, int RemoveTrailingSlash) } +/* + * Decode a quoted-printable encoded StrBuf buffer "in place" + * This is possible because the decoded will always be shorter than the encoded + * so we don't have to worry about the buffer being to small. + */ +void StrBufDecodeQP(StrBuf *Buf) +{ + if (!Buf) { // sanity check #1 + return; + } + + int source_len = StrLength(Buf); + if (source_len < 1) { // sanity check #2 + return; + } + + int spos = 0; // source position + int tpos = 0; // target position + + while (spos < source_len) { + if (!strncmp(&Buf->buf[spos], "=\r\n", 3)) { + spos += 3; + } + else if (!strncmp(&Buf->buf[spos], "=\n", 2)) { + spos += 2; + } + else if (Buf->buf[spos] == '=') { + ++spos; + int ch; + sscanf(&Buf->buf[spos], "%02x", &ch); + Buf->buf[tpos++] = ch; + spos +=2; + } + else { + Buf->buf[tpos++] = Buf->buf[spos++]; + } + } + + Buf->buf[tpos] = 0; + Buf->BufUsed = tpos; +}