a couple of changes; but some parts are now broken
[gnupg.git] / util / iobuf.c
index ad98219..65efc0e 100644 (file)
@@ -40,6 +40,7 @@ typedef struct {
     int usage;
     size_t size;
     size_t count;
+    int partial;  /* 1 = partial header, 2 in last partial packet */
     int eof;
 } block_filter_ctx_t;
 
@@ -143,20 +144,64 @@ block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len)
            rc = -1;
        while( !rc && size ) {
            if( !a->size ) { /* get the length bytes */
-               c = iobuf_get(chain);
-               a->size = c << 8;
-               c = iobuf_get(chain);
-               a->size |= c;
-               if( c == -1 ) {
-                   log_error("block_filter: error reading length info\n");
-                   rc = G10ERR_READ_FILE;
-               }
-               if( !a->size ) {
+               if( a->partial == 2 ) {
                    a->eof = 1;
                    if( !n )
                        rc = -1;
                    break;
                }
+               else if( a->partial ) {
+                   if( (c = iobuf_get(chain)) == -1 ) {
+                       log_error("block_filter: 1st length byte missing\n");
+                       rc = G10ERR_READ_FILE;
+                       break;
+                   }
+                   if( c < 192 ) {
+                       a->size = c;
+                       a->partial = 2;
+                       if( !a->size ) {
+                           a->eof = 1;
+                           if( !n )
+                               rc = -1;
+                           break;
+                       }
+                   }
+                   else if( c < 224 ) {
+                       a->size = (c - 192) * 256;
+                       if( (c = iobuf_get(chain)) == -1 ) {
+                           log_error("block_filter: 2nd length byte missing\n");
+                           rc = G10ERR_READ_FILE;
+                           break;
+                       }
+                       a->size += c + 192;
+                       a->partial = 2;
+                       if( !a->size ) {
+                           a->eof = 1;
+                           if( !n )
+                               rc = -1;
+                           break;
+                       }
+                   }
+                   else { /* next partial body length */
+                       a->size = 1 << (c & 0x1f);
+                   }
+               }
+               else {
+                   c = iobuf_get(chain);
+                   a->size = c << 8;
+                   c = iobuf_get(chain);
+                   a->size |= c;
+                   if( c == -1 ) {
+                       log_error("block_filter: error reading length info\n");
+                       rc = G10ERR_READ_FILE;
+                   }
+                   if( !a->size ) {
+                       a->eof = 1;
+                       if( !n )
+                           rc = -1;
+                       break;
+                   }
+               }
            }
 
            for(; !rc && size && a->size; size--, a->size-- ) {
@@ -176,6 +221,7 @@ block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len)
     else if( control == IOBUFCTRL_FLUSH ) {
        size_t avail, n;
 
+       assert( !a->partial );
        for(p=buf; !rc && size; ) {
            n = size;
            avail = a->size - a->count;
@@ -205,7 +251,9 @@ block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len)
     else if( control == IOBUFCTRL_INIT ) {
        if( DBG_IOBUF )
            log_debug("init block_filter %p\n", a );
-       if( a->usage == 1 )
+       if( a->partial )
+           a->count = 0;
+       else if( a->usage == 1 )
            a->count = a->size = 0;
        else
            a->count = a->size; /* force first length bytes */
@@ -216,8 +264,12 @@ block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len)
     }
     else if( control == IOBUFCTRL_FREE ) {
        if( a->usage == 2 ) { /* write the end markers */
-           iobuf_writebyte(chain, 0);
-           iobuf_writebyte(chain, 0);
+           if( a->partial ) {
+           }
+           else {
+               iobuf_writebyte(chain, 0);
+               iobuf_writebyte(chain, 0);
+           }
        }
        else if( a->size ) {
            log_error("block_filter: pending bytes!\n");
@@ -261,7 +313,7 @@ iobuf_close( IOBUF a )
     size_t dummy_len;
     int rc=0;
 
-    for( ; a; a = a2 ) {
+    for( ; a && !rc ; a = a2 ) {
        a2 = a->chain;
        if( a->usage == 2 && (rc=iobuf_flush(a)) )
            log_error("iobuf_flush failed on close: %s\n", g10_errstr(rc));
@@ -648,6 +700,15 @@ iobuf_readbyte(IOBUF a)
 {
     int c;
 
+    /* nlimit does not work together with unget */
+    /* nbytes is also not valid! */
+    if( a->unget.buf ) {
+       if( a->unget.start < a->unget.len )
+           return a->unget.buf[a->unget.start++];
+       m_free(a->unget.buf);
+       a->unget.buf = NULL;
+    }
+
     if( a->nlimit && a->nbytes >= a->nlimit )
        return -1; /* forced EOF */
 
@@ -663,6 +724,26 @@ iobuf_readbyte(IOBUF a)
 
 
 int
+iobuf_read(IOBUF a, byte *buf, unsigned buflen )
+{
+    int c, n;
+
+    for(n=0 ; n < buflen; n++, buf++ ) {
+       if( (c = iobuf_readbyte(a)) == -1 ) {
+           if( !n )
+               return -1; /* eof */
+           break;
+       }
+       else
+           *buf = c;
+    }
+    return n;
+}
+
+
+
+
+int
 iobuf_writebyte(IOBUF a, unsigned c)
 {
     if( a->d.len == a->d.size )
@@ -718,6 +799,27 @@ iobuf_temp_to_buffer( IOBUF a, byte *buffer, size_t buflen )
     return n;
 }
 
+/****************
+ * unget the contents of the temp io stream to A and close temp
+ * Could be optimized!!
+ */
+void
+iobuf_unget_and_close_temp( IOBUF a, IOBUF temp )
+{
+    if( a->unget.buf ) {
+       if( a->unget.start < a->unget.len )
+           log_fatal("cannot do any more ungets on this buffer\n");
+       /* not yet cleaned up; do it now */
+       m_free(a->unget.buf);
+       a->unget.buf = NULL;
+    }
+    a->unget.size = temp->d.len;
+    a->unget.buf = m_alloc( a->unget.size );
+    a->unget.len = temp->d.len;
+    memcpy( a->unget.buf, temp->d.buf, a->unget.len );
+    iobuf_close(temp);
+}
+
 
 /****************
  * Set a limit, how much bytes may be read from the input stream A.
@@ -784,7 +886,10 @@ iobuf_seek( IOBUF a, ulong newpos )
        return -1;
     }
     a->ntotal = newpos;
-    /* FIXME: flush all buffers (and remove filters?)*/
+    /* remove filters, but the last */
+    while( a->chain )
+       iobuf_pop_filter( a, a->filter, NULL );
+
 
     return 0;
 }
@@ -800,8 +905,6 @@ iobuf_seek( IOBUF a, ulong newpos )
 const char *
 iobuf_get_fname( IOBUF a )
 {
-    struct stat st;
-
     for( ; a; a = a->chain )
        if( !a->chain && a->filter == file_filter ) {
            file_filter_ctx_t *b = a->filter_ov;
@@ -832,6 +935,27 @@ iobuf_set_block_mode( IOBUF a, size_t n )
     }
 }
 
+/****************
+ * enable patial block mode as descriped in the OpenPGP draft.
+ * LEN is the first length
+ */
+void
+iobuf_set_partial_block_mode( IOBUF a, size_t len )
+{
+    block_filter_ctx_t *ctx = m_alloc_clear( sizeof *ctx );
+
+    assert( a->usage == 1 || a->usage == 2 );
+    ctx->usage = a->usage;
+    if( !len ) {
+       iobuf_pop_filter(a, block_filter, NULL );
+    }
+    else {
+       ctx->partial = 1;
+       ctx->size = len;
+       iobuf_push_filter(a, block_filter, ctx );
+    }
+}
+
 
 /****************
  * Checks wether the stream is in block mode
@@ -841,7 +965,7 @@ int
 iobuf_in_block_mode( IOBUF a )
 {
     if( a && a->filter == block_filter )
-           return 1; /* yes */
+       return 1; /* yes */
     return 0; /* no */
 }