#include #include #include #include #include #include "junk.h" #include "grb2.h" #include "wgrib2.h" #include "fnlist.h" /* * mem_buffers.c 5/2015 Public Domain Wesley Ebisuzaki * * memory buffer(s) to store grib messages * */ /* * want memory buffers defined before wgrib2 is run * so with callable wgrib2, program could initialize * a memory buffer before calling wgrib2 * ex. set @mem:0 to a grib message * call wgrib2 to decode grib message * get @mem:1 with the decoded grib message * * to check for compile-use init_mem_buffers */ /* * data structure for memory buffers * * unsigned char *mem_buffer[N_mem_buffers]; // data for @mem:n * size_t mem_buffer_size[N_mem_buffers]; // file size of @mem:N * size_t mem_buffer_allocated[N_mem_buffers]; // allocated memory for @mem:N >= buffer size * size_t mem_buffer_pos[N_mem_buffers]; // position * * to reduce calls to realloc/malloc, more memory is allocated than needed for the write */ unsigned char *mem_buffer[N_mem_buffers] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; size_t mem_buffer_size[N_mem_buffers] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; size_t mem_buffer_allocated[N_mem_buffers] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; size_t mem_buffer_pos[N_mem_buffers] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; extern int file_append; void init_mem_buffers(void) { if (sizeof(mem_buffer) / sizeof (unsigned char *) != N_mem_buffers) fatal_error("Mem_buffer.c: mem_buffer improper initialization",""); if (sizeof(mem_buffer_size) / sizeof (size_t) != N_mem_buffers) fatal_error("Mem_buffer.c: mem_buffer_size improper initialization",""); if (sizeof(mem_buffer_allocated) / sizeof (size_t) != N_mem_buffers) fatal_error("Mem_buffer.c: mem_buffer_allocated improper initialization",""); if (sizeof(mem_buffer_pos) / sizeof (size_t) != N_mem_buffers) fatal_error("Mem_buffer.c: mem_buffer_pos improper initialization",""); return; } void free_mem_buffer(int n) { if (n < 0 || n >= N_mem_buffers) return; if (mem_buffer[n] != NULL) { free(mem_buffer[n]); mem_buffer[n] = NULL; mem_buffer_pos[n] = mem_buffer_allocated[n] = mem_buffer_size[n] = 0; } return; } unsigned char *new_mem_buffer(int n, size_t size) { size_t new_size; if (n < 0 || n >= N_mem_buffers) return NULL; if (size <= mem_buffer_allocated[n]) { mem_buffer_size[n] = size; mem_buffer_pos[n] = 0; return mem_buffer[n]; } if (mem_buffer[n] == NULL) { new_size = size / 4096; new_size = (new_size + 1 + new_size/10)*4096 + 16*4096; } else { new_size = size / 4096; new_size = (new_size + 1 + new_size/10)*4096 + 16*4096; free(mem_buffer[n]); } mem_buffer[n] = (unsigned char *) malloc(new_size); if (mem_buffer[n]) { mem_buffer_size[n] = size; mem_buffer_allocated[n] = new_size; } else { mem_buffer_size[n] = mem_buffer_allocated[n] = 0; } mem_buffer_pos[n] = 0; return mem_buffer[n]; } /* * realloc_mem_buffer(n, size) * change mem_buffer[n] to size * keep contents */ unsigned char *realloc_mem_buffer(int n, size_t size) { size_t new_size; unsigned char *p; if (n < 0 || n >= N_mem_buffers) return NULL; if (mem_buffer[n] == NULL) { new_size = size / 4096; new_size = (new_size + 1 + new_size/10)*4096 + 16*4096; mem_buffer[n] = (unsigned char *) malloc(new_size); if (mem_buffer[n]) { mem_buffer_size[n] = size; mem_buffer_allocated[n] = new_size; } else { mem_buffer_pos[n] = mem_buffer_size[n] = mem_buffer_allocated[n] = 0; } } else { new_size = size / 4096; new_size = (new_size + 1 + new_size/10)*4096 + 16*4096; if ((p = realloc(mem_buffer[n], size)) == NULL) { free(mem_buffer[n]); mem_buffer_pos[n] = mem_buffer_size[n] = mem_buffer_allocated[n] = 0; } else { mem_buffer_size[n] = size; mem_buffer_allocated[n] = new_size; } mem_buffer[n] = p; } return mem_buffer[n]; } /* * to support memory files, need standard i/o routine * such as fread, fwrite, fseek, ftell, fgets */ /* * fwrite for memory file n */ size_t fwrite_mem(const void *ptr, size_t size, size_t nmemb, int n) { size_t nwrite, old_size, new_size; if (n < 0 || n >= N_mem_buffers) return 0; nwrite = size * nmemb; old_size = mem_buffer_size[n]; new_size = mem_buffer_pos[n] + nwrite; if (new_size > old_size) { realloc_mem_buffer(n, new_size); } if (mem_buffer[n] == NULL) return (size_t) 0; memcpy(mem_buffer[n] + mem_buffer_pos[n], ptr, nwrite); mem_buffer_size[n] = mem_buffer_pos[n] += nwrite; return nmemb; } /* * fread for memory file n */ size_t fread_mem(void *ptr, size_t size, size_t nmemb, int n) { size_t nread, i; if (n < 0 || n >= N_mem_buffers) return 0; nread = (mem_buffer_size[n] - mem_buffer_pos[n]) / size; if (nread > nmemb) nread = nmemb; i = nread * size; memcpy((void *) ptr, (void *) mem_buffer[n] + mem_buffer_pos[n], i); mem_buffer_pos[n] += i; return nread; } /* * fseek for memory file n */ int fseek_mem(int n, long position, int whence) { if (n < 0 || n >= N_mem_buffers) return -1; if (whence == SEEK_SET) { mem_buffer_pos[n] = position; } else if (whence == SEEK_END) { mem_buffer_pos[n] = mem_buffer_size[n] + position; } else if (whence == SEEK_CUR) { mem_buffer_pos[n] += position; } if (mem_buffer_pos[n] > mem_buffer_size[n]) { mem_buffer_pos[n] = 0; return -1; } return 0; } /* * ftell for memory file n */ long ftell_mem(int n) { if (n < 0 || n >= N_mem_buffers) return -1; return mem_buffer_pos[n]; } /* * fgets for memory file n */ char *fgets_mem(char *s, int size, int n) { char *p; if (n < 0 || n >= N_mem_buffers) return NULL; p = s; while (size > 1 && (mem_buffer_pos[n] < mem_buffer_size[n]) ) { size--; if ( (*p++ = mem_buffer[n][mem_buffer_pos[n]++]) == '\n') break; } *p = '\0'; return s; } size_t wgrib2_get_mem_buffer_size(int n) { if (n < 0 || n >= N_mem_buffers) return -1; return mem_buffer_size[n]; } int wgrib2_get_mem_buffer(int n, size_t size, unsigned char *my_buffer) { if (n < 0 || n >= N_mem_buffers) return 1; if (size != mem_buffer_size[n]) { fprintf(stderr,"*** error get_mem_buffer buffer(%d) size=%ld to %ld\n", n, mem_buffer_size[n], size); return 2; } memcpy(my_buffer, mem_buffer[n], size); return 0; } int wgrib2_set_mem_buffer(int n, size_t size, unsigned char *my_buffer) { if (n < 0 || n >= N_mem_buffers) return 1; if (size <= 0) { mem_buffer_size[n] = 0; } else { if (size > mem_buffer_allocated[n]) { if (mem_buffer[n] != NULL) free(mem_buffer[n]); mem_buffer[n] = (unsigned char *) malloc(size); if (mem_buffer[n] == NULL) { fprintf(stderr,"*** ERROR wgrib2_set_mem_buffer memory allocation failed (%ld)\n",(long int) size); return 2; } mem_buffer_allocated[n] = size; } memcpy(mem_buffer[n], my_buffer, size); mem_buffer_size[n] = size; } return 0; } /* * HEADER:100:mem_final:misc:2:write mem file X to file Y at cleanup step */ int f_mem_final(ARG2) { int i, n; i = 0; if (mode == -1) { n = atoi(arg1); if (n < 0 || n >= N_mem_buffers) fatal_error_i("mem_final: n should be 0..%d", N_mem_buffers-1); *local = (void *) ffopen(arg2, file_append ? "a+b" : "w+b"); if (*local == NULL) fatal_error("Could not open %s", arg2); } else if (mode == -2) { n = atoi(arg1); if (mem_buffer_size[n] > 0) { i = fwrite(mem_buffer[n], sizeof(unsigned char), mem_buffer_size[n], (FILE *) *local) != mem_buffer_size[n]; ffclose((FILE *) *local); } } return i; } /* * HEADER:100:mem_init:misc:2:read mem file X from file Y (on initialization) */ int f_mem_init(ARG2) { FILE *in; int n; long size; if (mode == -1) { n = atoi(arg1); if (n < 0 || n >= N_mem_buffers) fatal_error_i("mem_init: n should be 0..%d", N_mem_buffers-1); in = fopen(arg2,"rb"); if (in == NULL) fatal_error("Could not open %s", arg2); fseek(in, 0L, SEEK_END); size = ftell(in); fseek(in, 0L, SEEK_SET); if (new_mem_buffer(n, (size_t) size) == NULL) { fclose(in); fatal_error("Could not allocate memory mem_init %s", arg2); } if (fread(mem_buffer[n], sizeof(unsigned char), size, in) != size) { fclose(in); mem_buffer_size[n] = 0; fatal_error("Could not read %s", arg2); } fclose(in); } return 0; } /* * HEADER:100:mem_del:misc:1:delete mem file X */ int f_mem_del(ARG1) { int n; if (mode >= 0) { n = atoi(arg1); if (n < 0 || n >= N_mem_buffers) fatal_error_i("mem_del: illegal memory buffer %d", n); /* probably going to reuse memory file, so keep buffers allocated */ if (mem_buffer[n] == NULL) return 0; mem_buffer_size[n] = 0; mem_buffer_pos[n] = 0; } return 0; }