summaryrefslogtreecommitdiff
path: root/src/quotprint.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/quotprint.c')
-rw-r--r--src/quotprint.c177
1 files changed, 159 insertions, 18 deletions
diff --git a/src/quotprint.c b/src/quotprint.c
index c5c7719..dbb06cc 100644
--- a/src/quotprint.c
+++ b/src/quotprint.c
@@ -39,7 +39,7 @@
#define STR_QUOT(S) STR_QUOT_(S)
-typedef struct FalseSharingBarrier { void* _[64/sizeof(void*)]; } FalseSharingBarrier;
+typedef struct FalseSharingBarrier { char _[64]; } FalseSharingBarrier;
typedef struct Buf {
@@ -255,7 +255,7 @@ mainOfInputThread( void*_ ){
}
-INLINE(void*)
+PRIVATE(void*)
mainOfEncode( void*_ ){
DEFINE_App(this, _);
int err, iSrc = 0, iDst = 0, lineBeg = 0;
@@ -294,7 +294,9 @@ mainOfEncode( void*_ ){
goto onDstBufFull;
}
for(;;){
- if( iDst + 3 >= DST_CAP )
+ /* MUST have some headroom at end so we can properly handle
+ * special-cases. */
+ if( iDst + 8 >= DST_CAP )
{ goto onDstBufFull; }
if( iSrc >= LEN_SRC )
{ goto onSrcBufDrained; }
@@ -302,12 +304,11 @@ mainOfEncode( void*_ ){
#define IS_WHITESP(C) (C == 0x09 || C == 0x0A || C == 0x0D || C == 0x20)
#define NEXT_SRC_CHR (BUF_SRC[iSrc])
#define IS_NEXT_CHR_PRESENT (iSrc + 1 < LEN_SRC)
- #define IS_DST_SPACE_AT_LEAST(N) (iDst + (N) < DST_CAP)
#define IS_BINARY_MODE ((this->flg & FLG_isBinary)==0)
#define IS_EBCDIC_RISKY(C) (C == 0x21 || C == 0x23 || C == 0x24 || C == 0x34 \
|| C == 0x40 || C == 0x5B || C == 0x5C || C == 0x5D || C == 0x5E || C == 0x60 \
|| C == 0x7B || C == 0x7C || C == 0x7D || C == 0x7E)
- int const isCrLfRaw = (c == 0x0D && IS_NEXT_CHR_PRESENT && IS_DST_SPACE_AT_LEAST(2)
+ int const isCrLfRaw = (c == 0x0D && IS_NEXT_CHR_PRESENT
&& NEXT_SRC_CHR == 0x0A && IS_BINARY_MODE);
int const isRawOk = 0
/* A CRLF sequence if a special case, as it CAN be
@@ -325,8 +326,7 @@ mainOfEncode( void*_ ){
* mode given, as I do NOT want to introduce yet-another-bullshit-flag*/
|| (IS_EBCDIC_RISKY(c) && !IS_BINARY_MODE)
/*space MUST NOT be at endOfLine, so check some more conditions*/
- || (c == 0x20 && IS_NEXT_CHR_PRESENT && IS_DST_SPACE_AT_LEAST(4)
- && !IS_WHITESP(NEXT_SRC_CHR))
+ || (c == 0x20 && IS_NEXT_CHR_PRESENT && !IS_WHITESP(NEXT_SRC_CHR))
;
#undef IS_WHITESP
#undef NEXT_SRC_CHR
@@ -382,7 +382,7 @@ mainOfEncode( void*_ ){
}onSrcBufDrained:{
err = pthread_mutex_lock(&this->mutxSrc); assert(!err);
while( this->srcBufReadyToFill )
- { pthread_cond_wait(&this->condSrc, &this->mutxSrc); }
+ { err = pthread_cond_wait(&this->condSrc, &this->mutxSrc); assert(!err); }
this->srcBufReadyToFill = BUF_SRC;
LEN_SRC = 0;
BUF_SRC = NULL;
@@ -415,12 +415,156 @@ mainOfEncode( void*_ ){
}
-INLINE(int)
-quotPrintDecode( App*this ){
- assert(!"TODO_i5TKHBVqBa0lRhqy");
- /* Cited from RFC: when decoding a Quoted-Printable body, any
- * trailing white space on a line must be deleted, as it will
- * necessarily have been added by intermediate transport agents */
+PRIVATE(void*)
+mainOfDecode( void*_ ){
+ int err, iSrc = 0, iDst = 0;
+ DEFINE_App(this, _);
+ {
+ #define BUF_DST (this->dstBufReadyToFill)
+ #define DST_CAP BUF_CAP
+ #define LEN_DST (*(int*)(((uintptr_t)0) \
+ + ((uintptr_t)(BUF_DST == this->dstBufOne.buf) * (uintptr_t)&this->dstBufOne.len) \
+ + ((uintptr_t)(BUF_DST != this->dstBufOne.buf) * (uintptr_t)&this->dstBufTwo.len) \
+ ))
+ #define BUF_SRC (this->srcBufReadyToConsume)
+ #define SRC_CAP BUF_CAP
+ #define LEN_SRC (*(int*)(((uintptr_t)0) \
+ + ((uintptr_t)(BUF_SRC == this->srcBufOne.buf) * (uintptr_t)&this->srcBufOne.len) \
+ + ((uintptr_t)(BUF_SRC == this->srcBufTwo.buf) * (uintptr_t)&this->srcBufTwo.len) \
+ ))
+ }awaitBuffers:{
+ LOGD("decoder - await DST buf\n");
+ err = pthread_mutex_lock(&this->mutxDst); assert(!err);
+ while( !BUF_DST )
+ pthread_cond_wait(&this->condDst, &this->mutxDst);
+ err = pthread_mutex_unlock(&this->mutxDst); assert(!err);
+ }{
+ LOGD("decoder - await SRC buf\n");
+ err = pthread_mutex_lock(&this->mutxSrc); assert(!err);
+ while( !BUF_SRC )
+ pthread_cond_wait(&this->condSrc, &this->mutxSrc);
+ err = pthread_mutex_unlock(&this->mutxSrc); assert(!err);
+ }{
+ LOGD("decoder - both buffers ready\n");
+ if( BUF_SRC == &endOfFile ){
+ /* input has ended. we MUST ensure that we really flush what
+ * we maybe still have in dst. So assert dst is full and handle it
+ * there. */
+ /* TODO should we ensure that output always ends with CRLF? */
+ goto onDstBufFull;
+ }
+ }{
+ for(;;){
+ if( iDst + 1 >= DST_CAP )
+ { goto onDstBufFull; }
+ if( iSrc >= LEN_SRC )
+ { goto onSrcBufDrained; }
+ uint_fast8_t const CHR0 = BUF_SRC[iSrc + 0];
+ #define CHR1 ((uint_fast8_t)BUF_SRC[iSrc + 1])
+ #define CHR2 ((uint_fast8_t)BUF_SRC[iSrc + 2])
+ #define IS_HEX(C) (0 \
+ || ((C) >= '0' && (C) <= '9') \
+ || ((C) >= 'A' && (C) <= 'F') \
+ || ((C) >= 'a' && (C) <= 'f') \
+ )
+ #define IS_WHITESP(C) (C == 0x09 || C == 0x0A || C == 0x0D || C == 0x20)
+ int const isSoftWrap = (CHR0 == '=' && (CHR1 == '\r' || CHR1 == '\n'));
+ if( isSoftWrap ){
+ if( CHR1 == '\n' ){ iSrc += 2; }
+ else if( CHR1 == '\r' && CHR2 == '\n' ){ iSrc += 3; }
+ else if( CHR1 == '\r' ){ iSrc += 2; }
+ continue;
+ }
+ // TODO /* Cited from RFC:
+ // TODO * > when decoding a Quoted-Printable body, any trailing white space on
+ // TODO * > a line must be deleted, as it will necessarily have been added by
+ // TODO * > intermediate transport agents.
+ // TODO * TODO: Below impl does not work when that whitespace crosses a buffer
+ // TODO * boundary. */
+ // TODO int trailSpsEnd;
+ // TODO for( trailSpsEnd = iSrc ;; ++trailSpsEnd){
+ // TODO if( trailSpsEnd >= LEN_SRC ) assert(!"TODO_wSiBu8mbRajrnTZp");
+ // TODO if( BUF_SRC[iSrc] == );
+ // TODO }
+ if( CHR0 != '=' ){
+ /*just a normal char*/
+ BUF_DST[iDst++] = CHR0;
+ iSrc += 1;
+ continue;
+ }
+ if( !IS_HEX(CHR1) || !IS_HEX(CHR2) ){
+ /*corrupt garbage. TODO: Should be handled with warning*/
+ BUF_DST[iDst++] = CHR0;
+ BUF_DST[iDst++] = CHR1;
+ BUF_DST[iDst++] = CHR2;
+ iSrc += 3;
+ continue;
+ }
+ /* decode from escape */
+ #define NIBL_OF_HEX_CHR(R, X) do{ \
+ uint_fast8_t c = (X); \
+ if( c >= '0' && c <= '9' ){ (R) = c - '0'; break; } \
+ if( c >= 'A' && c <= 'F' ){ (R) = c - 'A' + 10; break; } \
+ if( c >= 'a' && c <= 'f' ){ (R) = c - 'a' + 10; break; } \
+ assert(!"TODO_KwZPRb3XfwLIGOyq"); \
+ }while(0)
+ uint_fast8_t nibHi; NIBL_OF_HEX_CHR(nibHi, CHR1);
+ uint_fast8_t nibLo; NIBL_OF_HEX_CHR(nibLo, CHR2);
+ BUF_DST[iDst++] = (nibHi << 4) | nibLo;
+ iSrc += 3;
+ #undef CHR1
+ #undef CHR2
+ #undef IS_HEX
+ #undef IS_WHITESP
+ #undef NIBL_OF_HEX_CHR
+ }
+ }onSrcBufDrained:{
+ err = pthread_mutex_lock(&this->mutxSrc); assert(!err);
+ while( this->srcBufReadyToFill )
+ { err = pthread_cond_wait(&this->condSrc, &this->mutxSrc); assert(!err); }
+ this->srcBufReadyToFill = BUF_SRC;
+ LEN_SRC = 0;
+ BUF_SRC = NULL;
+ err = pthread_cond_broadcast(&this->condSrc); assert(!err);
+ err = pthread_mutex_unlock(&this->mutxSrc); assert(!err);
+ goto awaitBuffers;
+ }onDstBufFull:{
+ /* hand over dst buf as soon consumer is ready to take it */
+ err = pthread_mutex_lock(&this->mutxDst); assert(!err);
+ while( this->dstBufReadyToFlush )
+ { err = pthread_cond_wait(&this->condDst, &this->mutxDst); assert(!err); }
+ LOGD("decoder - dstBufReadyToFlush := dstBuf%s\n",
+ (BUF_DST==this->dstBufOne.buf)?"One":"Two");
+ LOGD("decoder - dstBuf%s.len := %d\n", (BUF_DST==this->dstBufOne.buf)?"One":"Two", iDst);
+ LOGD("decoder - dstBuf%s := NULL\n", (BUF_DST==this->dstBufOne.buf)?"One":"Two");
+ this->dstBufReadyToFlush = BUF_DST;
+ LEN_DST = iDst;
+ BUF_DST = NULL;
+ err = pthread_cond_broadcast(&this->condDst); assert(!err);
+ if( BUF_SRC == &endOfFile ){
+ /* src eof, so mark our eof too (as soon prev buffer is consumed) */
+ while( this->dstBufReadyToFlush )
+ { err = pthread_cond_wait(&this->condDst, &this->mutxDst); assert(!err); }
+ LOGD("decoder - src did report EOF. Therefore report EOF too\n");
+ this->dstBufReadyToFlush = &endOfFile;
+ err = pthread_cond_broadcast(&this->condDst); assert(!err);
+ err = pthread_mutex_unlock(&this->mutxDst); assert(!err);
+ err = 0; goto resolveWithErr;
+ }else{
+ err = pthread_mutex_unlock(&this->mutxDst); assert(!err);
+ }
+ goto awaitBuffers;
+ }resolveWithErr:{
+ assert(err == 0);
+ return NULL;
+ }{
+ #undef BUF_DST
+ #undef DST_CAP
+ #undef LEN_DST
+ #undef BUF_SRC
+ #undef SRC_CAP
+ #undef LEN_SRC
+ }
}
@@ -440,10 +584,7 @@ run( App*this ){
err = -err; goto resolveWithErr;
}
}/*launch a thread for processing*/{
- void *(*processor)(void*) = (this->flg & FLG_isEnc)
- ? mainOfEncode
- : NULL //TODO mainOfDecode
- ;
+ void *(*processor)(void*) = (this->flg & FLG_isEnc) ? mainOfEncode : mainOfDecode;
err = pthread_create(&this->thrdWr, NULL, processor, this);
if( err ){
assert(err > 0);