eccodes/memfs.py

324 lines
7.4 KiB
Python
Raw Normal View History

2016-06-14 13:04:48 +00:00
#!/usr/bin/env python
from __future__ import print_function
import os
import re
import sys
import binascii
2020-10-19 11:37:31 +00:00
import time
2016-06-14 13:04:48 +00:00
assert len(sys.argv) > 2
2020-10-19 11:37:31 +00:00
start = time.time()
print("MEMFS: starting")
# Exclude experimental features e.g. GRIB3 and TAF
# The BUFR codetables is not used in the engine
2020-10-19 08:16:24 +00:00
EXCLUDED = ["grib3", "codetables", "taf", "stations"]
EXPECTED_FCOUNT = 6
2018-03-16 16:47:07 +00:00
pos = 1
2020-10-19 08:16:24 +00:00
if sys.argv[1] == "-exclude":
2020-03-12 17:19:34 +00:00
product = sys.argv[2]
2020-10-19 08:16:24 +00:00
if product == "bufr":
2020-03-12 17:19:34 +00:00
EXCLUDED.append(product)
EXPECTED_FCOUNT = 4
2020-10-19 08:16:24 +00:00
elif product == "grib":
EXCLUDED.extend(["grib1", "grib2"])
EXPECTED_FCOUNT = 2
2020-03-12 17:19:34 +00:00
else:
2020-10-19 08:16:24 +00:00
assert False, "Invalid product %s" % product
pos = 3
dirs = [os.path.realpath(x) for x in sys.argv[pos:-1]]
2020-10-19 08:16:24 +00:00
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-10-19 08:16:24 +00:00
CHUNK = 16 * 1024 * 1024 # chunk size in bytes
2016-06-14 13:04:48 +00:00
# Binary to ASCII function. Different in Python 2 and 3
2017-07-23 07:08:54 +00:00
try:
2020-10-19 08:16:24 +00:00
str(b"\x23\x20", "ascii")
ascii = lambda x: str(x, "ascii") # Python 3
2017-07-23 07:08:54 +00:00
except:
2020-10-19 08:16:24 +00:00
ascii = lambda x: str(x) # Python 2
2017-07-23 07:08:54 +00:00
2020-04-16 12:00:49 +00:00
def get_outfile_name(base, count):
return base + "_" + str(count).zfill(3) + ".c"
# The last argument is the base name of the generated C file(s)
2020-04-16 12:00:49 +00:00
output_file_base = sys.argv[-1]
2020-10-19 08:16:24 +00:00
2020-10-19 11:37:31 +00:00
buffer = None
2020-10-19 08:16:24 +00:00
fcount = -1
2016-06-14 13:04:48 +00:00
for directory in dirs:
# print("MEMFS: directory=", directory)
2016-06-14 13:04:48 +00:00
dname = os.path.basename(directory)
NAMES.append(dname)
for dirpath, dirnames, files in os.walk(directory, followlinks=True):
2020-10-19 11:37:31 +00:00
2018-03-16 16:47:07 +00:00
# Prune the walk by modifying the dirnames in-place
dirnames[:] = [dirname for dirname in dirnames if dirname not in EXCLUDED]
2016-06-14 13:04:48 +00:00
for name in files:
2020-10-19 11:37:31 +00:00
if buffer is None:
fcount += 1
opath = get_outfile_name(output_file_base, fcount)
print("MEMFS: Generating output:", opath)
buffer = open(opath, "w")
2020-10-19 11:37:31 +00:00
2020-10-19 08:16:24 +00:00
full = "%s/%s" % (dirpath, name)
2016-06-14 13:04:48 +00:00
_, ext = os.path.splitext(full)
2020-10-19 08:16:24 +00:00
if ext not in [".def", ".table", ".tmpl", ".list", ".txt"]:
continue
2020-10-19 08:16:24 +00:00
if name == "CMakeLists.txt":
2016-06-14 13:04:48 +00:00
continue
full = full.replace("\\", "/")
2020-10-19 08:16:24 +00:00
fname = full[full.find("/%s/" % (dname,)) :]
# print("MEMFS: Add ", fname)
name = re.sub(r"\W", "_", fname)
2016-06-14 13:04:48 +00:00
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-10-19 08:16:24 +00:00
SIZES[name] = os.path.getsize(full)
2016-06-14 13:04:48 +00:00
txt = "const unsigned char %s[] = {" % (name,)
buffer.write(txt)
2016-06-14 13:04:48 +00:00
2020-10-19 08:16:24 +00:00
with open(full, "rb") as f:
2016-06-14 13:04:48 +00:00
i = 0
# Python 2
2020-10-19 08:16:24 +00:00
# contents_hex = f.read().encode("hex")
2017-02-06 18:03:36 +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-10-19 08:16:24 +00:00
twoChars = ascii(contents_hex[n : n + 2])
txt = "0x%s," % (twoChars,)
buffer.write(txt)
2016-06-14 13:04:48 +00:00
i += 1
if (i % 20) == 0:
buffer.write("\n")
2020-10-19 08:16:24 +00:00
buffer.write("};\n")
2020-10-19 08:16:24 +00:00
if buffer.tell() >= CHUNK:
2020-10-19 11:37:31 +00:00
buffer.close()
buffer = None
2020-10-19 08:16:24 +00:00
2020-10-19 11:37:31 +00:00
if buffer is not None:
buffer.close()
# The number of generated C files is hard coded.
# See memfs/CMakeLists.txt
assert fcount == EXPECTED_FCOUNT, fcount
2020-04-16 12:00:49 +00:00
opath = output_file_base + "_final.c"
2020-10-19 08:16:24 +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
2020-10-19 08:16:24 +00:00
print(
"""
#include "eccodes_config.h"
#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>
#include "eccodes_windef.h"
2020-10-19 08:16:24 +00:00
""",
file=g,
)
2016-06-14 13:04:48 +00:00
# Write extern variables with sizes
for k, v in SIZES.items():
2020-10-19 08:16:24 +00:00
print("extern const unsigned char %s[%d];" % (k, v), file=g)
2020-04-02 15:46:49 +00:00
2020-10-19 08:16:24 +00:00
print(
"""
2016-06-14 13:04:48 +00:00
struct entry {
const char* path;
const unsigned char* content;
size_t length;
2020-10-19 08:16:24 +00:00
} entries[] = { """,
file=g,
)
2016-06-14 13:04:48 +00:00
items = [(v, k) for k, v in FILES.items()]
for k, v in sorted(items):
print('{"/MEMFS%s", &%s[0], sizeof(%s) / sizeof(%s[0]) },' % (k, v, v, v), file=g)
2016-06-14 13:04:48 +00:00
2020-10-19 08:16:24 +00:00
print(
"""};
2016-06-14 13:04:48 +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);
}
#elif defined(ECCODES_ON_WINDOWS)
#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");
}
2020-10-19 08:16:24 +00:00
""",
file=g,
)
2020-04-16 11:06:19 +00:00
2020-10-19 08:16:24 +00:00
print("Finished")
2020-10-19 11:37:31 +00:00
print("MEMFS: done", time.time() - start)