-/*
- * Copyright (c) 1987-2011 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"
#include "libcitadel.h"
+#include "b64/cencode.h"
+#include "b64/cdecode.h"
+
#ifdef HAVE_ICONV
#include <iconv.h>
#endif
#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;
* @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;
}
+void SwapBuffers(StrBuf *A, StrBuf *B)
+{
+ iSwapBuffers(A, B);
+}
+
+
/**
* @ingroup StrBuf_Cast
* @brief Cast operator to Plain String
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;
}
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;
}
}
+
/**
* @ingroup StrBuf_DeConstructors
* @brief shrink long term buffers to their real size so they don't waste memory
}
else
NewBuf = *CreateRelpaceMe;
- SwapBuffers (NewBuf, CopyFlushMe);
+ iSwapBuffers (NewBuf, CopyFlushMe);
}
if (!KeepOriginal)
FlushStrBuf(CopyFlushMe);
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,
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
void StrBufStripAllBut(StrBuf *Buf, char leftboundary, char rightboundary)
{
- const char *pBuff;
const char *pLeft;
const char *pRight;
- if ((Buf == NULL) || (Buf->buf == NULL))
+ if ((Buf == NULL) || (Buf->buf == NULL)) {
return;
- pLeft = pBuff = Buf->buf;
- while (pBuff != NULL) {
- pLeft = pBuff;
- pBuff = strchr(pBuff, leftboundary);
- if (pBuff != NULL)
- pBuff++;
}
-
- if (pLeft != NULL)
- pBuff = pLeft;
- else
- pBuff = Buf->buf;
- pRight = strchr(pBuff, rightboundary);
- if (pRight != NULL)
+
+ pRight = strchr(Buf->buf, rightboundary);
+ if (pRight != NULL) {
StrBufCutAt(Buf, 0, pRight);
- if (pLeft != NULL)
- StrBufCutLeft(Buf, pLeft - Buf->buf);
+ }
+
+ pLeft = strrchr(ChrPtr(Buf), leftboundary);
+ if (pLeft != NULL) {
+ StrBufCutLeft(Buf, pLeft - Buf->buf + 1);
+ }
}
*pt = '\0';
}
+/**
+ * @ingroup StrBuf_DeEnCoder
+ * @brief append a string with characters having a special meaning in xml encoded to the buffer
+ * @param OutBuf the output buffer
+ * @param In Buffer to encode
+ * @param PlainIn way in from plain old c strings
+ * @param PlainInLen way in from plain old c strings; maybe you've got binary data or know the length?
+ * @param OverrideLowChars should chars < 0x20 be replaced by _ or escaped as xml entity?
+ */
+void StrBufXMLEscAppend(StrBuf *OutBuf,
+ const StrBuf *In,
+ const char *PlainIn,
+ long PlainInLen,
+ int OverrideLowChars)
+{
+ const char *pch, *pche;
+ char *pt, *pte;
+ int IsUtf8Sequence;
+ int len;
+
+ if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
+ return;
+ if (PlainIn != NULL) {
+ if (PlainInLen < 0)
+ len = strlen((const char*)PlainIn);
+ else
+ len = PlainInLen;
+ pch = PlainIn;
+ pche = pch + len;
+ }
+ else {
+ pch = (const char*)In->buf;
+ pche = pch + In->BufUsed;
+ len = In->BufUsed;
+ }
+
+ if (len == 0)
+ return;
+
+ pt = OutBuf->buf + OutBuf->BufUsed;
+ /**< we max append 6 chars at once plus the \0 */
+ pte = OutBuf->buf + OutBuf->BufSize - 6;
+
+ while (pch < pche) {
+ if (pt >= pte) {
+ OutBuf->BufUsed = pt - OutBuf->buf;
+ IncreaseBuf(OutBuf, 1, -1);
+ pte = OutBuf->buf + OutBuf->BufSize - 6;
+ /**< we max append 3 chars at once plus the \0 */
+
+ pt = OutBuf->buf + OutBuf->BufUsed;
+ }
+
+ if (*pch == '<') {
+ memcpy(pt, HKEY("<"));
+ pt += 4;
+ pch ++;
+ }
+ else if (*pch == '>') {
+ memcpy(pt, HKEY(">"));
+ pt += 4;
+ pch ++;
+ }
+ else if (*pch == '&') {
+ memcpy(pt, HKEY("&"));
+ pt += 5;
+ pch++;
+ }
+ else if ((*pch >= 0x20) && (*pch <= 0x7F)) {
+ *pt = *pch;
+ pt++; pch++;
+ }
+ else {
+ IsUtf8Sequence = Ctdl_GetUtf8SequenceLength(pch, pche);
+ if (IsUtf8Sequence)
+ {
+ while ((IsUtf8Sequence > 0) &&
+ (pch < pche))
+ {
+ *pt = *pch;
+ pt ++;
+ pch ++;
+ --IsUtf8Sequence;
+ }
+ }
+ else
+ {
+ *pt = '&';
+ pt++;
+ *pt = HexList[*(unsigned char*)pch][0];
+ pt ++;
+ *pt = HexList[*(unsigned char*)pch][1];
+ pt ++; pch ++;
+ *pt = '&';
+ pt++;
+ pch ++;
+ }
+ }
+ }
+ *pt = '\0';
+ OutBuf->BufUsed = pt - OutBuf->buf;
+}
+
+
/**
* @ingroup StrBuf_DeEnCoder
* @brief append a string in hex encoding to the buffer
*pt = '\0';
}
+void StrBufBase64Append(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn, long PlainInLen, int linebreaks)
+{
+ const char *pch;
+ char *pt;
+ int len;
+ long ExpectLen;
+
+ if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
+ return;
+ if (PlainIn != NULL) {
+ if (PlainInLen < 0)
+ len = strlen(PlainIn);
+ else
+ len = PlainInLen;
+ pch = PlainIn;
+ }
+ else {
+ pch = In->buf;
+ len = In->BufUsed;
+ }
+
+ if (len == 0)
+ return;
+
+ ExpectLen = ((len * 134) / 100) + OutBuf->BufUsed;
+
+ if (ExpectLen > OutBuf->BufSize)
+ if (IncreaseBuf(OutBuf, 1, ExpectLen) < ExpectLen)
+ return;
+
+ pt = OutBuf->buf + OutBuf->BufUsed;
+
+ len = CtdlEncodeBase64(pt, pch, len, linebreaks);
+
+ pt += len;
+ OutBuf->BufUsed += len;
+ *pt = '\0';
+}
+
/**
* @ingroup StrBuf_DeEnCoder
* @brief append a string in hex encoding to the buffer
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, 0, BufIn->BufUsed);
+
+ 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;
+
+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 (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;
+}
+
+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(*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;
+}
+
+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:
+ {
+ /// 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->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;
+
+ 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;
+}
+
/**
* @ingroup StrBuf_DeEnCoder
* @brief decode a buffer from base 64 encoding; destroys original
ch = (unsigned char) source->buf[i];
if ((ch < 32) ||
(ch > 126) ||
- (ch == 61) ||
(ch == '=') ||
(ch == '?') ||
(ch == '_') ||
return (*target)->BufUsed;;
}
+/**
+ * @ingroup StrBuf_DeEnCoder
+ * @brief Quoted-Printable encode a message; make it < 80 columns width.
+ * @param source Source string to be encoded.
+ * @returns buffer with encoded message.
+ */
+StrBuf *StrBufRFC2047encodeMessage(const StrBuf *EncodeMe)
+{
+ StrBuf *OutBuf;
+ char *Optr, *OEptr;
+ const char *ptr, *eptr;
+ unsigned char ch;
+ int LinePos;
+
+ OutBuf = NewStrBufPlain(NULL, StrLength(EncodeMe) * 4);
+ Optr = OutBuf->buf;
+ OEptr = OutBuf->buf + OutBuf->BufSize;
+ ptr = EncodeMe->buf;
+ eptr = EncodeMe->buf + EncodeMe->BufUsed;
+ LinePos = 0;
+
+ while (ptr < eptr)
+ {
+ if (Optr + 4 >= OEptr)
+ {
+ long Offset;
+ Offset = Optr - OutBuf->buf;
+ OutBuf->BufUsed = Optr - OutBuf->buf;
+ IncreaseBuf(OutBuf, 1, 0);
+ Optr = OutBuf->buf + Offset;
+ OEptr = OutBuf->buf + OutBuf->BufSize;
+ }
+ if (*ptr == '\r')
+ {
+ /* ignore carriage returns */
+ ptr ++;
+ }
+ else if (*ptr == '\n') {
+ /* hard line break */
+ memcpy(Optr, HKEY("=0A"));
+ Optr += 3;
+ LinePos += 3;
+ ptr ++;
+ }
+ else if (( (*ptr >= 32) && (*ptr <= 60) ) ||
+ ( (*ptr >= 62) && (*ptr <= 126) ))
+ {
+ *Optr = *ptr;
+ Optr ++;
+ ptr ++;
+ LinePos ++;
+ }
+ else {
+ ch = *ptr;
+ *Optr = '=';
+ Optr ++;
+ *Optr = HexList[ch][0];
+ Optr ++;
+ *Optr = HexList[ch][1];
+ Optr ++;
+ LinePos += 3;
+ ptr ++;
+ }
+
+ if (LinePos > 72) {
+ /* soft line break */
+ if (isspace(*(Optr - 1))) {
+ ch = *(Optr - 1);
+ Optr --;
+ *Optr = '=';
+ Optr ++;
+ *Optr = HexList[ch][0];
+ Optr ++;
+ *Optr = HexList[ch][1];
+ Optr ++;
+ LinePos += 3;
+ }
+ *Optr = '=';
+ Optr ++;
+ *Optr = '\n';
+ Optr ++;
+ LinePos = 0;
+ }
+ }
+ *Optr = '\0';
+ OutBuf->BufUsed = Optr - OutBuf->buf;
+
+ return OutBuf;
+}
static void AddRecipient(StrBuf *Target,
TmpBuf->buf[TmpBuf->BufUsed] = '\0';
/* little card game: wheres the red lady? */
- SwapBuffers(ConvertBuf, TmpBuf);
+ iSwapBuffers(ConvertBuf, TmpBuf);
FlushStrBuf(TmpBuf);
}
#endif
n++;
aptr++;
}
- if (n > maxlen) {
+ if (n >= maxlen) {
*aptr = '\0';
Buf->BufUsed = aptr - Buf->buf;
return Buf->BufUsed;
- }
+ }
}
return Buf->BufUsed;
* 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
* @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",
return StrLength(FB->Buf) - (FB->ReadWritePointer - FB->Buf->buf);
}
-void FDIOBufferInit(FDIOBuffer *FDB, IOBuffer *IO, int FD, long TotalSendSize)
-{
- memset(FDB, 0, sizeof(FDIOBuffer));
- FDB->ChunkSize =
- FDB->TotalSendSize = 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)
- {
- close(FDB->SplicePipe[0]);
- close(FDB->SplicePipe[1]);
- }
- else
-#endif
- FreeStrBuf(&FDB->ChunkBuffer);
-
- close(FDB->OtherFD);
- memset(FDB, 0, sizeof(FDIOBuffer));
-}
-
-int FileSendChunked(FDIOBuffer *FDB, const char **Err)
-{
- ssize_t sent, pipesize;
-#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->ChunkSendRemain);
-
- if (nRead >= 0) {
- FDB->TotalSentAlready += nRead;
- FDB->ChunkSendRemain -= nRead;
- 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! *
return len - slen;
}
+
/**
* @ingroup StrBuf_BufferedIO
* @brief Read a line from socket
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);
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);
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;
*Error = strerror(errno);
close (*fd);
*fd = -1;
- if (*Error == NULL)
+ if (*Error == NULL) {
*Error = ErrRBLF_SelectFailed;
+ }
return -1;
}
if (! FD_ISSET(*fd, &rfds) != 0) {
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;
}
+/*
+ * 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;
+}