2016-06-14 13:04:48 +00:00
|
|
|
#!/usr/bin/env python
|
|
|
|
from __future__ import print_function
|
|
|
|
import os
|
|
|
|
import re
|
|
|
|
import sys
|
2017-01-25 11:53:23 +00:00
|
|
|
import binascii
|
2016-06-14 13:04:48 +00:00
|
|
|
|
|
|
|
assert len(sys.argv) > 2
|
|
|
|
|
2018-03-16 16:47:07 +00:00
|
|
|
# For now exclude GRIB3 as it is still experimental
|
2019-05-01 16:51:57 +00:00
|
|
|
# The BUFR codetables is not used in the engine
|
2020-01-16 18:29:31 +00:00
|
|
|
# METAR and TAF are also experimental
|
|
|
|
EXCLUDED = ['grib3', 'codetables', 'taf', 'metar']
|
2018-03-16 16:47:07 +00:00
|
|
|
|
2020-04-16 11:44:40 +00:00
|
|
|
pos = 1
|
2020-03-12 15:14:38 +00:00
|
|
|
if sys.argv[1] == '-exclude':
|
2020-03-12 17:19:34 +00:00
|
|
|
product = sys.argv[2]
|
|
|
|
if product == 'bufr':
|
|
|
|
EXCLUDED.append(product)
|
|
|
|
elif product == 'grib':
|
|
|
|
EXCLUDED.extend(['grib1', 'grib2'])
|
|
|
|
else:
|
|
|
|
assert False, 'Invalid product %s' % product
|
2020-03-12 15:14:38 +00:00
|
|
|
pos = 3
|
|
|
|
|
|
|
|
dirs = [os.path.realpath(x) for x in sys.argv[pos:-1]]
|
|
|
|
print('Directories: ', dirs)
|
|
|
|
print('Excluding: ', EXCLUDED)
|
2016-06-14 13:04:48 +00:00
|
|
|
|
|
|
|
FILES = {}
|
2020-04-02 15:46:49 +00:00
|
|
|
SIZES = {}
|
2016-06-14 13:04:48 +00:00
|
|
|
NAMES = []
|
2020-04-16 11:44:40 +00:00
|
|
|
CHUNK = 5500 * 1000 # chunk size in bytes
|
2016-06-14 13:04:48 +00:00
|
|
|
|
2017-07-25 10:12:43 +00:00
|
|
|
# Binary to ASCII function. Different in Python 2 and 3
|
2017-07-23 07:08:54 +00:00
|
|
|
try:
|
2017-07-25 10:12:43 +00:00
|
|
|
str(b'\x23\x20','ascii')
|
|
|
|
ascii = lambda x: str(x, 'ascii') # Python 3
|
2017-07-23 07:08:54 +00:00
|
|
|
except:
|
2017-07-25 10:12:43 +00:00
|
|
|
ascii = lambda x: str(x) # Python 2
|
2017-07-23 07:08:54 +00:00
|
|
|
|
|
|
|
|
2020-04-15 21:19:44 +00:00
|
|
|
# The last argument is the base name of the generated C file(s)
|
2018-03-16 16:51:58 +00:00
|
|
|
output_file_path = sys.argv[-1]
|
2020-04-16 11:44:40 +00:00
|
|
|
totsize = 0 # amount written
|
2020-04-15 21:19:44 +00:00
|
|
|
fcount = 0
|
|
|
|
opath = output_file_path + "_" + str(fcount).zfill(3) + ".c"
|
2020-04-16 11:44:40 +00:00
|
|
|
print('MEMFS: Generating output: ', opath)
|
2020-04-15 21:19:44 +00:00
|
|
|
g = open(opath, "w")
|
2016-06-14 13:04:48 +00:00
|
|
|
|
|
|
|
for directory in dirs:
|
|
|
|
|
2020-04-16 11:44:40 +00:00
|
|
|
# print("MEMFS: directory=", directory)
|
2016-06-14 13:04:48 +00:00
|
|
|
dname = os.path.basename(directory)
|
|
|
|
NAMES.append(dname)
|
|
|
|
|
2018-08-22 16:37:56 +00:00
|
|
|
for dirpath, dirnames, files in os.walk(directory, followlinks=True):
|
2020-04-16 11:44:40 +00:00
|
|
|
# for ex in EXCLUDED:
|
|
|
|
# if ex in dirnames:
|
|
|
|
# print('Note: eccodes memfs.py script: %s/%s will not be included.' % (dirpath,ex))
|
2018-03-16 16:47:07 +00:00
|
|
|
|
|
|
|
# Prune the walk by modifying the dirnames in-place
|
2018-12-27 17:13:51 +00:00
|
|
|
dirnames[:] = [dirname for dirname in dirnames if dirname not in EXCLUDED]
|
2016-06-14 13:04:48 +00:00
|
|
|
for name in files:
|
2018-03-16 15:18:46 +00:00
|
|
|
full = '%s/%s' % (dirpath, name)
|
2016-06-14 13:04:48 +00:00
|
|
|
_, ext = os.path.splitext(full)
|
|
|
|
if ext not in ['.def', '.table', '.tmpl']:
|
|
|
|
continue
|
|
|
|
|
2020-04-02 15:46:49 +00:00
|
|
|
fsize = os.path.getsize(full)
|
2020-04-15 21:19:44 +00:00
|
|
|
totsize += fsize
|
2020-04-16 11:44:40 +00:00
|
|
|
full = full.replace("\\", "/")
|
2016-06-14 13:04:48 +00:00
|
|
|
fname = full[full.find("/%s/" % (dname,)):]
|
2020-04-16 11:44:40 +00:00
|
|
|
#print("MEMFS: Add ", fname)
|
2016-06-14 13:04:48 +00:00
|
|
|
name = re.sub(r'\W', '_', fname)
|
|
|
|
|
|
|
|
assert name not in FILES
|
2020-04-02 15:46:49 +00:00
|
|
|
assert name not in SIZES
|
2016-06-14 13:04:48 +00:00
|
|
|
FILES[name] = fname
|
2020-04-02 15:46:49 +00:00
|
|
|
SIZES[name] = fsize
|
2016-06-14 13:04:48 +00:00
|
|
|
|
2020-04-16 11:44:40 +00:00
|
|
|
print('const unsigned char %s[] = {' % (name,), file=g)
|
2016-06-14 13:04:48 +00:00
|
|
|
|
2017-01-25 11:53:23 +00:00
|
|
|
with open(full, 'rb') as f:
|
2016-06-14 13:04:48 +00:00
|
|
|
i = 0
|
2020-04-16 11:44:40 +00:00
|
|
|
# Python 2
|
2020-04-02 15:46:49 +00:00
|
|
|
#contents_hex = f.read().encode("hex")
|
2017-02-06 18:03:36 +00:00
|
|
|
|
2020-04-16 11:44:40 +00:00
|
|
|
# Python 2 and 3
|
2020-04-02 15:46:49 +00:00
|
|
|
contents_hex = binascii.hexlify(f.read())
|
2017-02-06 18:03:36 +00:00
|
|
|
|
|
|
|
# Read two characters at a time and convert to C hex
|
|
|
|
# e.g. 23 -> 0x23
|
2020-04-02 15:46:49 +00:00
|
|
|
for n in range(0, len(contents_hex), 2):
|
2020-04-16 11:44:40 +00:00
|
|
|
twoChars = ascii(contents_hex[n:n + 2])
|
2017-01-25 11:53:23 +00:00
|
|
|
print("0x%s," % (twoChars,), end="", file=g)
|
2016-06-14 13:04:48 +00:00
|
|
|
i += 1
|
|
|
|
if (i % 20) == 0:
|
|
|
|
print("", file=g)
|
|
|
|
|
|
|
|
print('};', file=g)
|
2020-04-15 21:19:44 +00:00
|
|
|
if totsize >= CHUNK:
|
|
|
|
g.close()
|
|
|
|
fcount += 1
|
|
|
|
opath = output_file_path + "_" + str(fcount).zfill(3) + ".c"
|
2020-04-16 11:44:40 +00:00
|
|
|
print('MEMFS: Generating output: ', opath)
|
2020-04-15 21:19:44 +00:00
|
|
|
g = open(opath, "w")
|
|
|
|
totsize = 0
|
|
|
|
|
|
|
|
g.close()
|
2020-04-16 11:26:32 +00:00
|
|
|
assert fcount == 3
|
2020-04-16 11:06:19 +00:00
|
|
|
opath = output_file_path + "_final.c"
|
2020-04-16 11:44:40 +00:00
|
|
|
print('MEMFS: Generating output: ', opath)
|
2020-04-16 11:06:19 +00:00
|
|
|
g = open(opath, "w")
|
2016-06-14 13:04:48 +00:00
|
|
|
|
|
|
|
print("""
|
2016-06-14 14:27:49 +00:00
|
|
|
#include "eccodes_config.h"
|
2018-05-11 12:07:03 +00:00
|
|
|
#ifdef ECCODES_HAVE_FMEMOPEN
|
2016-06-14 13:04:48 +00:00
|
|
|
#define _GNU_SOURCE
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
2019-01-07 16:13:48 +00:00
|
|
|
#include "eccodes_windef.h"
|
2020-04-02 15:46:49 +00:00
|
|
|
""", file=g)
|
2016-06-14 13:04:48 +00:00
|
|
|
|
2020-04-15 21:19:44 +00:00
|
|
|
# Write extern variables with sizes
|
|
|
|
for k, v in SIZES.items():
|
2020-04-16 11:44:40 +00:00
|
|
|
print('extern const unsigned char %s[%d];' % (k, v), file=g)
|
2020-04-02 15:46:49 +00:00
|
|
|
|
|
|
|
print("""
|
2016-06-14 13:04:48 +00:00
|
|
|
struct entry {
|
|
|
|
const char* path;
|
|
|
|
const unsigned char* content;
|
|
|
|
size_t length;
|
|
|
|
} entries[] = { """, file=g)
|
|
|
|
|
|
|
|
items = [(v, k) for k, v in FILES.items()]
|
|
|
|
|
|
|
|
for k, v in sorted(items):
|
2020-04-16 11:44:40 +00:00
|
|
|
print('{"/MEMFS%s", &%s[0], sizeof(%s) / sizeof(%s[0]) },' % (k, v, v, v), file=g)
|
2016-06-14 13:04:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
print("""};
|
|
|
|
|
2018-05-11 12:07:03 +00:00
|
|
|
#if defined(ECCODES_HAVE_FUNOPEN) && !defined(ECCODES_HAVE_FMEMOPEN)
|
2016-06-14 13:04:48 +00:00
|
|
|
|
|
|
|
typedef struct mem_file {
|
|
|
|
const char* buffer;
|
|
|
|
size_t size;
|
|
|
|
size_t pos;
|
|
|
|
} mem_file;
|
|
|
|
|
|
|
|
static int read_mem(void *data, char * buf, int len) {
|
|
|
|
mem_file* f = (mem_file*)data;
|
|
|
|
int n = len;
|
|
|
|
|
|
|
|
if(f->pos + n > f->size) {
|
|
|
|
n = f->size - f->pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(buf, f->buffer + f->pos, n);
|
|
|
|
|
|
|
|
f->pos += n;
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int write_mem(void* data, const char* buf, int len) {
|
|
|
|
mem_file* f = (mem_file*)data;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static fpos_t seek_mem(void *data, fpos_t pos, int whence) {
|
|
|
|
mem_file* f = (mem_file*)data;
|
|
|
|
long newpos = 0;
|
|
|
|
|
|
|
|
switch (whence) {
|
|
|
|
case SEEK_SET:
|
|
|
|
newpos = (long)pos;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SEEK_CUR:
|
|
|
|
newpos = (long)f->pos + (long)pos;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SEEK_END:
|
|
|
|
newpos = (long)f->size - (long)pos;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(newpos < 0) { newpos = 0; }
|
|
|
|
if(newpos > f->size) { newpos = f->size; }
|
|
|
|
|
|
|
|
f->pos = newpos;
|
|
|
|
return newpos;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int close_mem(void *data) {
|
|
|
|
mem_file* f = (mem_file*)data;
|
|
|
|
free(f);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static FILE* fmemopen(const char* buffer, size_t size, const char* mode){
|
|
|
|
mem_file* f = (mem_file*)calloc(sizeof(mem_file), 1);
|
|
|
|
if(!f) return NULL;
|
|
|
|
|
|
|
|
f->buffer = buffer;
|
|
|
|
f->size = size;
|
|
|
|
|
|
|
|
return funopen(f, &read_mem, &write_mem, &seek_mem, &close_mem);
|
|
|
|
}
|
|
|
|
|
2019-01-07 16:13:48 +00:00
|
|
|
#elif defined(ECCODES_ON_WINDOWS)
|
2018-12-27 17:13:51 +00:00
|
|
|
|
|
|
|
#include <io.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <windows.h>
|
|
|
|
|
|
|
|
static FILE *fmemopen(void* buffer, size_t size, const char* mode) {
|
|
|
|
char path[MAX_PATH - 13];
|
|
|
|
if (!GetTempPath(sizeof(path), path))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
char filename[MAX_PATH + 1];
|
|
|
|
if (!GetTempFileName(path, "eccodes", 0, filename))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
HANDLE h = CreateFile(filename,
|
|
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
OPEN_ALWAYS,
|
|
|
|
FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
if (h == INVALID_HANDLE_VALUE)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
int fd = _open_osfhandle((intptr_t)h, _O_RDWR);
|
|
|
|
if (fd < 0) {
|
|
|
|
CloseHandle(h);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
FILE* f = _fdopen(fd, "w+");
|
|
|
|
if (!f) {
|
|
|
|
_close(fd);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
fwrite(buffer, size, 1, f);
|
|
|
|
rewind(f);
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
2016-06-14 13:04:48 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
static size_t entries_count = sizeof(entries)/sizeof(entries[0]);
|
|
|
|
|
|
|
|
static const unsigned char* find(const char* path, size_t* length) {
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for(i = 0; i < entries_count; i++) {
|
2016-06-18 17:18:14 +00:00
|
|
|
if(strcmp(path, entries[i].path) == 0) {
|
2016-06-19 08:36:18 +00:00
|
|
|
/*printf("Found in MEMFS %s\\n", path);*/
|
2016-06-14 13:04:48 +00:00
|
|
|
*length = entries[i].length;
|
|
|
|
return entries[i].content;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int codes_memfs_exists(const char* path) {
|
|
|
|
size_t dummy;
|
|
|
|
return find(path, &dummy) != NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
FILE* codes_memfs_open(const char* path) {
|
|
|
|
size_t size;
|
|
|
|
const unsigned char* mem = find(path, &size);
|
|
|
|
if(!mem) {
|
2016-06-19 08:22:15 +00:00
|
|
|
return NULL;
|
2016-06-14 13:04:48 +00:00
|
|
|
}
|
|
|
|
return fmemopen((void*)mem, size, "r");
|
|
|
|
}
|
|
|
|
|
|
|
|
""", file=g)
|
2020-04-16 11:06:19 +00:00
|
|
|
|
2020-04-16 11:44:40 +00:00
|
|
|
print('Finished')
|