Return to boundary_fp.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / mpd / src / contrib / libpdel / io |
1.1 misho 1: 2: /* 3: * Copyright (c) 2001-2002 Packet Design, LLC. 4: * All rights reserved. 5: * 6: * Subject to the following obligations and disclaimer of warranty, 7: * use and redistribution of this software, in source or object code 8: * forms, with or without modifications are expressly permitted by 9: * Packet Design; provided, however, that: 10: * 11: * (i) Any and all reproductions of the source or object code 12: * must include the copyright notice above and the following 13: * disclaimer of warranties; and 14: * (ii) No rights are granted, in any manner or form, to use 15: * Packet Design trademarks, including the mark "PACKET DESIGN" 16: * on advertising, endorsements, or otherwise except as such 17: * appears in the above copyright notice or in the software. 18: * 19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND 20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO 21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING 22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED 23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE, 25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS 26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, 27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE 28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE 29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT, 30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL 31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF 32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF 33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF 36: * THE POSSIBILITY OF SUCH DAMAGE. 37: * 38: * Author: Archie Cobbs <archie@freebsd.org> 39: */ 40: 41: #include <sys/types.h> 42: #include <sys/param.h> 43: 44: #include <stdio.h> 45: #include <stdlib.h> 46: #include <stdarg.h> 47: #include <string.h> 48: #include <assert.h> 49: #include <errno.h> 50: 51: #include "structs/structs.h" 52: #include "structs/type/array.h" 53: 54: #include "util/typed_mem.h" 55: #include "io/boundary_fp.h" 56: 57: #define MEM_TYPE "boundary_fp" 58: 59: #define MAX_BOUNDARY 255 /* must be less than 256 */ 60: 61: /* Internal state per stream */ 62: struct boundary_fp { 63: FILE *fp; 64: char bdry[MAX_BOUNDARY]; /* boundary string */ 65: u_char fail[MAX_BOUNDARY]; /* failure function */ 66: u_char buf[MAX_BOUNDARY]; /* input buffer data */ 67: int closeit; /* close underlying stream */ 68: int blen; /* boundary string length */ 69: int nbuf; /* number chars in buffer */ 70: int nmatch; /* length of the longest suffix 71: of buffer data that matches 72: a prefix of the boundary */ 73: }; 74: 75: /* 76: * Internal functions 77: */ 78: static int boundary_read(void *cookie, char *buf, int len); 79: static int boundary_close(void *cookie); 80: 81: /* 82: * Create a FILE * that reads from another FILE *, stopping 83: * just after it reads in the supplied boundary string. 84: */ 85: FILE * 86: boundary_fopen(FILE *fp, const char *boundary, int closeit) 87: { 88: struct boundary_fp *m; 89: int blen; 90: int i, j; 91: 92: /* Sanity check */ 93: if ((blen = strlen(boundary)) > MAX_BOUNDARY) { 94: errno = EINVAL; 95: return (NULL); 96: } 97: 98: /* Create state structure */ 99: if ((m = MALLOC(MEM_TYPE, sizeof(*m))) == NULL) 100: return (NULL); 101: memset(m, 0, sizeof(*m)); 102: m->fp = fp; 103: m->blen = blen; 104: m->closeit = closeit; 105: memcpy(m->bdry, boundary, m->blen); 106: 107: /* Generate failure function (linear algorithms exist; this isn't) */ 108: for (i = 2; i < m->blen; i++) { 109: for (j = 1; j < i && strncmp(m->bdry, m->bdry + j, i - j); j++); 110: m->fail[i] = i - j; 111: } 112: 113: /* Create new stream using methods below */ 114: if ((fp = funopen(m, boundary_read, 115: NULL, NULL, boundary_close)) == NULL) { 116: FREE(MEM_TYPE, m); 117: return (NULL); 118: } 119: 120: /* Done */ 121: return (fp); 122: } 123: 124: /* 125: * Read method. 126: */ 127: static int 128: boundary_read(void *cookie, char *buf, int len) 129: { 130: struct boundary_fp *const m = cookie; 131: int nr; 132: int i; 133: 134: /* Sanity */ 135: assert(m->nmatch <= m->nbuf); 136: 137: /* Have we got a complete boundary sitting in the buffer? */ 138: if (m->nmatch == m->blen) 139: return (0); 140: 141: /* Return available data, if any (and shift buffer) */ 142: if (m->nbuf > m->nmatch) { 143: len = MIN(len, m->nbuf - m->nmatch); 144: memcpy(buf, m->buf, len); 145: m->nbuf -= len; 146: memmove(m->buf, m->buf + len, m->nbuf); 147: return (len); 148: } 149: 150: /* 151: * Try to fill up the buffer from underlying stream. It is not 152: * possible to read past the end of a boundary at this point. 153: */ 154: nr = fread(m->buf + m->nbuf, 1, m->blen - m->nbuf, m->fp); 155: 156: /* Check for EOF/error on underlying stream */ 157: if (nr == 0) { 158: if (!ferror(m->fp)) 159: errno = EFTYPE; /* no final boundary seen */ 160: return (-1); 161: } 162: 163: /* Recompute match counter using failure links and new data */ 164: for (i = m->nbuf; i < m->nbuf + nr; i++) { 165: while (m->nmatch > 0 && m->buf[i] != m->bdry[m->nmatch]) 166: m->nmatch = m->fail[m->nmatch]; 167: if (m->buf[i] == m->bdry[m->nmatch]) 168: m->nmatch++; 169: } 170: m->nbuf += nr; 171: 172: /* Try again */ 173: return (boundary_read(cookie, buf, len)); 174: } 175: 176: /* 177: * Close method. 178: */ 179: static int 180: boundary_close(void *cookie) 181: { 182: struct boundary_fp *const m = cookie; 183: 184: if (m->closeit) 185: fclose(m->fp); 186: FREE(MEM_TYPE, m); 187: return (0); 188: } 189: