home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Amiga / Workbench / Archivers / mpackPPC.lha / mpackPPC / src / part.c < prev    next >
C/C++ Source or Header  |  1998-04-08  |  8KB  |  307 lines

  1. /*
  2.  * Read MIME body-part, stopping on boundaries.
  3.  */
  4. /* (C) Copyright 1994 by Carnegie Mellon University
  5.  * All Rights Reserved.
  6.  *
  7.  * Permission to use, copy, modify, distribute, and sell this software
  8.  * and its documentation for any purpose is hereby granted without
  9.  * fee, provided that the above copyright notice appear in all copies
  10.  * and that both that copyright notice and this permission notice
  11.  * appear in supporting documentation, and that the name of Carnegie
  12.  * Mellon University not be used in advertising or publicity
  13.  * pertaining to distribution of the software without specific,
  14.  * written prior permission.  Carnegie Mellon University makes no
  15.  * representations about the suitability of this software for any
  16.  * purpose.  It is provided "as is" without express or implied
  17.  * warranty.
  18.  *
  19.  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
  20.  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  21.  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
  22.  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  23.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  24.  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  25.  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  26.  * SOFTWARE.
  27.  */
  28.  
  29. #include <stdio.h>
  30. #include <string.h>
  31.  
  32. #include "part.h"
  33. #include "xmalloc.h"
  34.  
  35. #define BUFSIZE 1024 /* must be > PART_MAX_BOUNDARY_LEN */
  36. #define GROWBOUNDARY 20
  37.  
  38. static int pendingboundary();
  39.  
  40. /*
  41.  * Create, initialize, and return a new struct part pointer
  42.  * for the input file 'infile'.
  43.  */
  44. struct part *part_init(infile)
  45. FILE *infile;
  46. {
  47.     static struct part zeropart;
  48.     struct part *newpart;
  49.  
  50.     newpart = (struct part *)xmalloc(sizeof(struct part));
  51.     *newpart = zeropart;
  52.     newpart->infile = infile;
  53.     newpart->buf = (unsigned char *)xmalloc(BUFSIZE);
  54.     newpart->buf_alloc = BUFSIZE;
  55.  
  56.     return newpart;
  57. }
  58.  
  59. /*
  60.  * Close and free 'part'.
  61.  */
  62. int part_close(part)
  63. struct part *part;
  64. {
  65.     fclose(part->infile);
  66.     if (part->buf) free(part->buf);
  67.     if (part->boundary) free(part->boundary);
  68. }
  69.  
  70. /*
  71.  * Return the multipart depth of 'part'.  Top-level is '0'.
  72.  */
  73. int
  74. part_depth(part)
  75. struct part *part;
  76. {
  77.     return part->boundary_num;
  78. }
  79.  
  80. /*
  81.  * Add to 'part' the multipart boundary 'boundary'.
  82.  */
  83. int
  84. part_addboundary(part, boundary)
  85. struct part *part;
  86. char *boundary;
  87. {
  88.     /* Grow boundary array if necessary */
  89.     if (part->boundary_num == part->boundary_alloc) {
  90.     part->boundary_alloc += GROWBOUNDARY;
  91.     part->boundary = (char (*)[PART_MAX_BOUNDARY_LEN+1])
  92.         xrealloc((char *)part->boundary,
  93.              part->boundary_alloc * (PART_MAX_BOUNDARY_LEN+1));
  94.     part->boundary_length = (int *)
  95.         xrealloc((char *)part->boundary_length,
  96.              part->boundary_alloc * sizeof(int));
  97.     }
  98.  
  99.     strncpy(part->boundary[part->boundary_num], boundary,
  100.         PART_MAX_BOUNDARY_LEN);
  101.     part->boundary[part->boundary_num][PART_MAX_BOUNDARY_LEN] = '\0';
  102.     part->boundary_length[part->boundary_num] =
  103.     strlen(part->boundary[part->boundary_num]);
  104.     part->boundary_num++;
  105.     if (part->boundary_seen+1 == part->boundary_num) {
  106.     part->boundary_seen++;
  107.     }
  108. }
  109.  
  110. /*
  111.  * Private function that is only called from the part_getc() macro.
  112.  *
  113.  * Fills the input buffer for 'part' if necessary.  Returns the next
  114.  * input character or EOF if at a boundary or end of file.
  115.  */
  116. int
  117. part_fill(part)
  118. struct part *part;
  119. {
  120.     /* part_getc() decremented this before calling us, put it back */
  121.     part->cnt++;
  122.  
  123.     /* Return EOF if we saw a boundary */
  124.     if (part->boundary_seen < part->boundary_num) return EOF;
  125.  
  126.     /* Fill buffer if it is empty */
  127.     if (part->cnt == 0) {
  128.     part->ptr = part->buf;
  129.     part->cnt = fread(part->buf, 1, part->buf_alloc, part->infile);
  130.     if (part->cnt == 0) {
  131.         part->boundary_seen = 0;
  132.         return EOF;
  133.     }
  134.     }
  135.  
  136.     /* If there is a newline, see if it is followed by a boundary */
  137.     if (part->ptr[0] == '\n' && pendingboundary(part)) {
  138.     return EOF;
  139.     }
  140.  
  141.     part->cnt--;
  142.     return *part->ptr++;
  143. }
  144.  
  145. /*
  146.  * Read a line into the array 's', of size 'n', from 'part'.
  147.  * Reads until 'n'-1 characters are read, a newline is read, or
  148.  * an EOF is encountered.  The array is then nul-terminated and returned.
  149.  * If the first character read is an EOF, then a null pointer is instead
  150.  * returned.
  151.  */
  152. char *
  153. part_gets(s, n, part)
  154. char *s;
  155. int n;
  156. struct part *part;
  157. {
  158.     int c;
  159.     char *p = s;
  160.     
  161.     if (n == 0) return 0;
  162.     n--;
  163.     while (n-- && (c = part_getc(part)) != EOF) {
  164.     *p++ = c;
  165.     if (c == '\n') break;
  166.     }
  167.     if (p == s) return 0;
  168.     *p++ = '\0';
  169.     return s;
  170. }
  171.  
  172. /*
  173.  * Push back the string 's' into the input buffer of 'part'.
  174.  * Leaves room in the input buffer to push back an additional single
  175.  * character using the prot_ungetc() macro.
  176.  */
  177. int
  178. part_ungets(s, part)
  179. char *s;
  180. struct part *part;
  181. {
  182.     int len = strlen(s);
  183.     int i;
  184.  
  185.     /* Grow buffer if necessary */
  186.     if (part->cnt + len + 1 > part->buf_alloc) {
  187.     i = part->ptr - part->buf;
  188.     part->buf_alloc = part->cnt + len + 1;
  189.     part->buf = (unsigned char *)
  190.         xrealloc((char *)part->buf, part->buf_alloc);
  191.     part->ptr = part->buf + i;
  192.     }
  193.  
  194.     /* Move current data down to make room for new data if necessary */
  195.     if (len + 1 > part->ptr - part->buf) {
  196.     for (i = part->cnt-1; i >= 0; i--) {
  197.         part->buf[len+1+i] = part->ptr[i];
  198.     }
  199.     part->ptr = part->buf + len + 1;
  200.     }
  201.  
  202.     /* Copy in the new data */
  203.     part->ptr -= len;
  204.     part->cnt += len;
  205.     for (i = 0; i < len; i++) {
  206.     part->ptr[i] = s[i];
  207.     }
  208. }
  209.  
  210. /*
  211.  * Reset the saw-boundary state of 'part' and set up to read next
  212.  * body-part Returns nonzero iff the pending boundary was a final
  213.  * boundary of the current multipart.
  214.  */
  215. int
  216. part_readboundary(part)
  217. struct part *part;
  218. {
  219.     int c;
  220.     int sawfinal = 0;
  221.  
  222.     if (part->boundary_seen < part->boundary_num-1) {
  223.     /* We saw an enclosing boundary.  Signal end of multipart, but
  224.      * don't skip over the boundary.
  225.      */
  226.     part->boundary_num--;
  227.     return 1;
  228.     }
  229.  
  230.     /* Deal with EOF on input stream */
  231.     if (part->cnt == 0) return 1;
  232.  
  233.     /* Skip over delimiter, reset the "saw boundary" state */
  234.     part->ptr += part->boundary_length[part->boundary_seen] + 3;
  235.     part->cnt -= part->boundary_length[part->boundary_seen] + 3;
  236.     part->boundary_seen = part->boundary_num;
  237.     
  238.     /* Check for two dashes, which indicate a final delimiter */
  239.     c = part_getc(part);
  240.     if (c == '-') {
  241.     c = part_getc(part);
  242.     if (c == '-') {
  243.         sawfinal = 1;
  244.         part->boundary_num--;
  245.     }
  246.     }
  247.  
  248.     /* Eat rest of the boundary line */
  249.     while (c != '\n' && c != EOF) {
  250.     c = part_getc(part);
  251.     }
  252.     
  253.     return sawfinal;
  254. }    
  255.  
  256.         
  257. /*
  258.  * Return nonzero and set the saw-boundary state iff 'part'
  259.  * is positioned at a boundary.
  260.  */
  261. static int
  262. pendingboundary(part)
  263. struct part *part;
  264. {
  265.     int bufleft;
  266.     int i;
  267.  
  268.     /* Fill buffer if we don't have enough to do our look ahead */
  269.     if (part->cnt < 3 ||
  270.     (part->cnt < PART_MAX_BOUNDARY_LEN+3 && part->ptr[1] == '-' &&
  271.      part->ptr[2] == '-')) {
  272.         
  273.     bufleft = part->buf_alloc - part->cnt - (part->ptr - part->buf);
  274.  
  275.     /* If not enough room, move everything to beginning of buffer */
  276.     if (part->ptr!=part->buf && bufleft + part->cnt < PART_MAX_BOUNDARY_LEN+3) {
  277.         for (i = 0; i < part->cnt; i++) {
  278.         part->buf[i] = part->ptr[i];
  279.         }
  280.         part->ptr = part->buf;
  281.         bufleft = part->buf_alloc - part->cnt;
  282.     }
  283.  
  284.     /* Read in more data */
  285.     part->cnt += fread(part->ptr+part->cnt, 1, bufleft, part->infile);
  286.     }
  287.  
  288.     /* If no "--", it's not a boundary */
  289.     if (part->cnt < 3 || part->ptr[1] != '-' || part->ptr[2] != '-') {
  290.     return 0;
  291.     }
  292.  
  293.     for (i = 0; i < part->boundary_num; i++) {
  294.     if (part->cnt - 3 >= part->boundary_length[i] &&
  295.         !strncmp((char *)part->ptr+3, part->boundary[i],
  296.              part->boundary_length[i])) {
  297.         break;
  298.     }
  299.     }
  300.  
  301.     if (i == part->boundary_num) return 0;
  302.  
  303.     /* Saw boundary, index 'i' */ 
  304.     part->boundary_seen = i;
  305.     return 1;
  306. }
  307.