X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=libcitadel%2Flib%2Fstringbuf.c;h=770cb3eb575893357592c83869fc68a543ab9ad8;hb=3cfffe2479a77433a5e0801d24b902b33b0078f3;hp=5d196112385d5a11883126692be869720b585d90;hpb=cb9b83d5083a4ee3ef9a8783a3524d87cfa25ca3;p=citadel.git diff --git a/libcitadel/lib/stringbuf.c b/libcitadel/lib/stringbuf.c index 5d1961123..770cb3eb5 100644 --- a/libcitadel/lib/stringbuf.c +++ b/libcitadel/lib/stringbuf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1987-2013 by the citadel.org team + * Copyright (c) 1987-2018 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 @@ -256,7 +256,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; @@ -266,6 +266,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 @@ -510,7 +516,7 @@ void NewStrBufDupAppendFlush(StrBuf **CreateRelpaceMe, StrBuf *CopyFlushMe, cons } else NewBuf = *CreateRelpaceMe; - SwapBuffers (NewBuf, CopyFlushMe); + iSwapBuffers (NewBuf, CopyFlushMe); } if (!KeepOriginal) FlushStrBuf(CopyFlushMe); @@ -2006,32 +2012,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 ++; @@ -2846,7 +2833,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, @@ -2859,9 +2846,10 @@ typedef struct __z_enc_stream { z_stream zstream; } z_enc_stream; -void *StrBufNewStreamContext(eStreamType type) +vStreamT *StrBufNewStreamContext(eStreamType type, const char **Err) { base64_decodestate *state;; + *Err = NULL; switch (type) { @@ -2869,7 +2857,7 @@ void *StrBufNewStreamContext(eStreamType type) case eBase64Encode: state = (base64_decodestate*) malloc(sizeof(base64_decodestate)); base64_init_decodestate(state); - return state; + return (vStreamT*) state; break; case eZLibDecode: { @@ -2884,9 +2872,12 @@ void *StrBufNewStreamContext(eStreamType type) err = inflateInit(&stream->zstream); - if (err != Z_OK) - return NULL;/// tODO cleanup - return stream; + if (err != Z_OK) { + StrBufDestroyStreamContext(type, (vStreamT**) &stream, Err); + *Err = zError(err); + return NULL; + } + return (vStreamT*) stream; } case eZLibEncode: @@ -2898,28 +2889,27 @@ void *StrBufNewStreamContext(eStreamType type) 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 * / + /* 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 * / , + 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); -*/ - err = deflateInit(&stream->zstream, - ZLibCompressionRatio); - - if (err != Z_OK) - return NULL;/// tODO cleanup - return stream; + if (err != Z_OK) { + StrBufDestroyStreamContext(type, (vStreamT**) &stream, Err); + *Err = zError(err); + return NULL; + } + return (vStreamT*) stream; } case eEmtyCodec: /// TODO @@ -2929,8 +2919,16 @@ void *StrBufNewStreamContext(eStreamType type) return NULL; } -void StrBufDestroyStreamContext(eStreamType type, void **vStream) +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: @@ -2948,20 +2946,25 @@ void StrBufDestroyStreamContext(eStreamType type, void **vStream) 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); -// todo more? *vStream = NULL; break; } case eEmtyCodec: break; /// TODO } + return rc; } -void StrBufStreamTranscode(eStreamType type, IOBuffer *Target, IOBuffer *In, const char* pIn, long pInLen, void *vStream, int LastChunk) +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: @@ -3022,7 +3025,7 @@ void StrBufStreamTranscode(eStreamType type, IOBuffer *Target, IOBuffer *In, con case eZLibEncode: { z_enc_stream *stream = (z_enc_stream *)vStream; - int org_outbuf_len = stream->zstream.total_out; + int org_outbuf_len = stream->OutBuf.BufUsed; int err; unsigned int chunkavail; @@ -3044,9 +3047,14 @@ void StrBufStreamTranscode(eStreamType type, IOBuffer *Target, IOBuffer *In, con 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 (Target && + (LastChunk || + (stream->OutBuf.BufUsed != org_outbuf_len) + )) + { + iSwapBuffers(Target->Buf, &stream->OutBuf); + } if (stream->zstream.avail_in == 0) { @@ -3071,7 +3079,11 @@ void StrBufStreamTranscode(eStreamType type, IOBuffer *Target, IOBuffer *In, con (In->Buf->BufUsed - stream->zstream.avail_in); } } - + rc = (LastChunk && (err != Z_FINISH)); + if (!rc && (err != Z_OK)) { + *Err = zError(err); + } + } break; case eZLibDecode: { @@ -3104,7 +3116,7 @@ void StrBufStreamTranscode(eStreamType type, IOBuffer *Target, IOBuffer *In, con err = Z_DATA_ERROR; /* and fall through */ case Z_DATA_ERROR: - fprintf(stderr, "sanoteuh\n"); + *Err = zError(err); case Z_MEM_ERROR: (void)inflateEnd(&stream->zstream); return err; @@ -3112,7 +3124,7 @@ void StrBufStreamTranscode(eStreamType type, IOBuffer *Target, IOBuffer *In, con stream->OutBuf.BufUsed += stream->zstream.total_out + org_outbuf_len; - if (Target) SwapBuffers(Target->Buf, &stream->OutBuf); + if (Target) iSwapBuffers(Target->Buf, &stream->OutBuf); if (stream->zstream.avail_in == 0) { @@ -3144,6 +3156,7 @@ void StrBufStreamTranscode(eStreamType type, IOBuffer *Target, IOBuffer *In, con } break; /// TODO } + return rc; } /** @@ -3760,7 +3773,7 @@ TRYAGAIN: TmpBuf->buf[TmpBuf->BufUsed] = '\0'; /* little card game: wheres the red lady? */ - SwapBuffers(ConvertBuf, TmpBuf); + iSwapBuffers(ConvertBuf, TmpBuf); FlushStrBuf(TmpBuf); } #endif @@ -4129,11 +4142,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; @@ -4493,421 +4506,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! * @@ -4961,6 +4559,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 @@ -5609,3 +5208,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; +}