0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031 #define _BSD_SOURCE
0032 #define _NETBSD_SOURCE
0033
0034 #include <errno.h>
0035 #include <stdio.h>
0036 #include <stdlib.h>
0037 #include <string.h>
0038
0039 struct fmem_cookie {
0040 void *fmc_buffer;
0041 size_t fmc_index;
0042 size_t fmc_limit;
0043 };
0044
0045 static int
0046 fmem_read(void *cookie, char *buffer, int n)
0047 {
0048 struct fmem_cookie *const fmc = cookie;
0049
0050 if (n < 0) {
0051 errno = EINVAL;
0052 return -1;
0053 }
0054
0055 if (n > (fmc->fmc_limit - fmc->fmc_index))
0056 n = (fmc->fmc_limit - fmc->fmc_index);
0057
0058 (void)memcpy(buffer, (char *)fmc->fmc_buffer + fmc->fmc_index, n);
0059 fmc->fmc_index += n;
0060 return n;
0061 }
0062
0063 static int
0064 fmem_write(void *cookie, const char *buffer, int n)
0065 {
0066 struct fmem_cookie *const fmc = cookie;
0067
0068 if (n < 0) {
0069 errno = EINVAL;
0070 return -1;
0071 }
0072
0073 if (n > (fmc->fmc_limit - fmc->fmc_index))
0074 n = (fmc->fmc_limit - fmc->fmc_index);
0075
0076 (void)memcpy((char *)fmc->fmc_buffer + fmc->fmc_index, buffer, n);
0077 fmc->fmc_index += n;
0078 return n;
0079 }
0080
0081 static fpos_t
0082 fmem_seek(void *cookie, fpos_t offset, int cmd)
0083 {
0084 struct fmem_cookie *const fmc = cookie;
0085
0086 switch (cmd) {
0087 case SEEK_SET:
0088 if ((offset < 0) || (fmc->fmc_limit < offset))
0089 goto einval;
0090 fmc->fmc_index = offset;
0091 return 0;
0092
0093 case SEEK_CUR:
0094 if (offset < 0) {
0095
0096 if ((offset == ~(fpos_t)0) || (-offset > fmc->fmc_index))
0097 goto einval;
0098 } else {
0099 if (offset > (fmc->fmc_limit - fmc->fmc_index))
0100 goto einval;
0101 }
0102 fmc->fmc_index += offset;
0103 return 0;
0104
0105 case SEEK_END:
0106
0107 if ((offset >= 0) || (offset == ~(fpos_t)0) || (fmc->fmc_limit < -offset))
0108 goto einval;
0109 fmc->fmc_index = (fmc->fmc_limit + offset);
0110 return 0;
0111
0112 default:
0113 goto einval;
0114 }
0115
0116 einval:
0117 errno = EINVAL;
0118 return -1;
0119 }
0120
0121 static int
0122 fmem_close(void *cookie)
0123 {
0124 struct fmem_cookie *const fmc = cookie;
0125
0126 free(fmc);
0127
0128 return 0;
0129 }
0130
0131 FILE *
0132 fmemopen(void *buffer, size_t len, const char *mode)
0133 {
0134 struct fmem_cookie *fmc;
0135 FILE *file;
0136
0137 fmc = malloc(sizeof(*fmc));
0138 if (fmc == NULL)
0139 goto fail0;
0140
0141 (void)memset(fmc, 0, sizeof(*fmc));
0142 fmc->fmc_buffer = buffer;
0143 fmc->fmc_index = 0;
0144 fmc->fmc_limit = len;
0145
0146 file = funopen(fmc, &fmem_read, &fmem_write, &fmem_seek, &fmem_close);
0147 if (file == NULL)
0148 goto fail1;
0149
0150 return file;
0151
0152 fail1:
0153 free(fmc);
0154 fail0:
0155 return NULL;
0156 }