Skip to content

Commit ebe9072

Browse files
committed
fmem: added base implementations
1 parent 157785d commit ebe9072

12 files changed

Lines changed: 855 additions & 0 deletions

.cmake/FindCriterion.cmake

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# This file is licensed under the WTFPL version 2 -- you can see the full
2+
# license over at http://www.wtfpl.net/txt/copying/
3+
#
4+
# - Try to find Criterion
5+
#
6+
# Once done this will define
7+
# CRITERION_FOUND - System has Criterion
8+
# CRITERION_INCLUDE_DIRS - The Criterion include directories
9+
# CRITERION_LIBRARIES - The libraries needed to use Criterion
10+
11+
find_package(PkgConfig)
12+
13+
find_path(CRITERION_INCLUDE_DIR criterion/criterion.h
14+
PATH_SUFFIXES criterion)
15+
16+
find_library(CRITERION_LIBRARY NAMES criterion libcriterion)
17+
18+
set(CRITERION_LIBRARIES ${CRITERION_LIBRARY})
19+
set(CRITERION_INCLUDE_DIRS ${CRITERION_INCLUDE_DIR})
20+
21+
include(FindPackageHandleStandardArgs)
22+
# handle the QUIET and REQUIRED arguments and set CRITERION_FOUND to TRUE
23+
# if all listed variables are TRUE
24+
find_package_handle_standard_args(Criterion DEFAULT_MSG
25+
CRITERION_LIBRARY CRITERION_INCLUDE_DIR)
26+
27+
mark_as_advanced(CRITERION_INCLUDE_DIR CRITERION_LIBRARY)

CMakeLists.txt

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# Copyright (C) 2017 Franklin "Snaipe" Mathieu.
2+
# Redistribution and use of this file is allowed according to the terms of the MIT license.
3+
# For details see the LICENSE file distributed with Mimick.
4+
5+
cmake_minimum_required (VERSION 2.8)
6+
7+
project (fmem C)
8+
9+
list (APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/.cmake")
10+
11+
include (CheckSymbolExists)
12+
include (CheckCSourceCompiles)
13+
include (GNUInstallDirs)
14+
15+
list (APPEND CMAKE_REQUIRED_DEFINITIONS
16+
-D_GNU_SOURCE
17+
-D_CRT_RAND_S
18+
-DVC_EXTRALEAN
19+
-DWIN32_LEAN_AND_MEAN)
20+
21+
check_symbol_exists (open_memstream stdio.h HAVE_OPEN_MEMSTREAM)
22+
check_symbol_exists (fopencookie stdio.h HAVE_FOPENCOOKIE)
23+
check_symbol_exists (funopen stdio.h HAVE_FUNOPEN)
24+
check_symbol_exists (tmpfile stdio.h HAVE_TMPFILE)
25+
check_symbol_exists (rand_s stdlib.h HAVE_WINAPI_RAND_S)
26+
check_symbol_exists (CreateFile windows.h HAVE_WINAPI_CREATEFILE)
27+
check_symbol_exists (CloseHandle windows.h HAVE_WINAPI_CLOSEHANDLE)
28+
check_symbol_exists (GetFileSize windows.h HAVE_WINAPI_GETFILESIZE)
29+
check_symbol_exists (CreateFileMapping windows.h HAVE_WINAPI_CREATEFILEMAPPING)
30+
check_symbol_exists (MapViewOfFile windows.h HAVE_WINAPI_MAPVIEWOFFILE)
31+
check_symbol_exists (UnmapViewOfFile windows.h HAVE_WINAPI_UNMAPVIEWOFFILE)
32+
check_symbol_exists (GetTempPath windows.h HAVE_WINAPI_GETTEMPPATH)
33+
check_symbol_exists (_open_osfhandle io.h HAVE_WINAPI_OPEN_OSFHANDLE)
34+
check_symbol_exists (_get_osfhandle io.h HAVE_WINAPI_GET_OSFHANDLE)
35+
check_symbol_exists (_fdopen stdio.h HAVE_WINAPI_FDOPEN)
36+
check_symbol_exists (_fileno stdio.h HAVE_WINAPI_FILENO)
37+
check_symbol_exists (_close io.h HAVE_WINAPI_CLOSE)
38+
39+
set (SOURCES)
40+
41+
if (HAVE_OPEN_MEMSTREAM)
42+
list (APPEND SOURCES src/fmem-open_memstream.c)
43+
elseif (HAVE_FOPENCOOKIE)
44+
list (APPEND SOURCES
45+
src/alloc.c
46+
src/alloc.h
47+
src/fmem-fopencookie.c)
48+
elseif (HAVE_FUNOPEN)
49+
list (APPEND SOURCES
50+
src/alloc.c
51+
src/alloc.h
52+
src/fmem-funopen.c)
53+
elseif (HAVE_WINAPI_CREATEFILE
54+
AND HAVE_WINAPI_CLOSEHANDLE
55+
AND HAVE_WINAPI_GETFILESIZE
56+
AND HAVE_WINAPI_CREATEFILEMAPPING
57+
AND HAVE_WINAPI_MAPVIEWOFFILE
58+
AND HAVE_WINAPI_UNMAPVIEWOFFILE
59+
AND HAVE_WINAPI_GETTEMPPATH
60+
AND HAVE_WINAPI_FDOPEN
61+
AND HAVE_WINAPI_FILENO
62+
AND HAVE_WINAPI_CLOSE
63+
AND HAVE_WINAPI_OPEN_OSFHANDLE
64+
AND HAVE_WINAPI_GET_OSFHANDLE
65+
AND HAVE_WINAPI_RAND_S)
66+
list (APPEND SOURCES src/fmem-winapi-tmpfile.c)
67+
elseif (HAVE_TMPFILE)
68+
list (APPEND SOURCES src/fmem-tmpfile.c)
69+
else ()
70+
message (FATAL_ERROR "No memory stream implementation found")
71+
endif ()
72+
73+
include_directories (include src ${PROJECT_BINARY_DIR}/gen)
74+
add_library (fmem ${SOURCES})
75+
76+
get_property (FMEM_LIBTYPE
77+
TARGET fmem
78+
PROPERTY TYPE)
79+
80+
set (CMAKE_REQUIRED_DEFINITIONS -fvisibility=hidden)
81+
check_c_source_compiles (
82+
"__attribute__((visibility(\"default\"))) int main(void) { return 0; }"
83+
CC_HAVE_VISIBILITY)
84+
set (CMAKE_REQUIRED_DEFINITIONS)
85+
86+
if ("${FMEM_LIBTYPE}" MATCHES "SHARED_LIBRARY")
87+
if (WIN32)
88+
set (EXPORT_MACROS
89+
"#ifdef FMEM_BUILD_LIBRARY
90+
# define FMEM_API __declspec(dllexport)
91+
#else /* !FMEM_BUILD_LIBRARY */
92+
# define FMEM_API __declspec(dllimport)
93+
#endif /* !FMEM_BUILD_LIBRARY */")
94+
add_definitions (-DFMEM_BUILD_LIBRARY)
95+
elseif (CC_HAVE_VISIBILITY)
96+
set (EXPORT_MACROS "#define FMEM_API __attribute__((visibility(\"default\")))")
97+
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden")
98+
endif ()
99+
else ()
100+
set (EXPORT_MACROS "#define FMEM_API")
101+
endif ()
102+
103+
configure_file (
104+
${PROJECT_SOURCE_DIR}/include/fmem.h.in
105+
${PROJECT_BINARY_DIR}/gen/fmem.h
106+
@ONLY)
107+
108+
install(TARGETS fmem
109+
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
110+
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
111+
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
112+
113+
install(FILES
114+
fmem.h
115+
${PROJECT_BINARY_DIR}/gen/fmem-export.h
116+
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
117+
118+
include (CTest)
119+
120+
if (BUILD_TESTING)
121+
find_package (Criterion REQUIRED)
122+
add_subdirectory (test)
123+
endif ()

include/fmem.h.in

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#ifndef FMEM_H_
2+
#define FMEM_H_
3+
4+
#include <stdio.h>
5+
6+
@EXPORT_MACROS@
7+
8+
struct fmem_reserved {
9+
char reserved[32];
10+
};
11+
12+
typedef struct fmem_reserved fmem;
13+
14+
FMEM_API void fmem_init(fmem *file);
15+
FMEM_API void fmem_term(fmem *file);
16+
FMEM_API FILE *fmem_open(fmem *file, const char *mode);
17+
FMEM_API void fmem_mem(fmem *file, void **mem, size_t *size);
18+
19+
#endif /* !FMEM_H_ */

src/alloc.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#include <errno.h>
2+
#include <stdint.h>
3+
#include <stdlib.h>
4+
#include <string.h>
5+
#include "alloc.h"
6+
7+
static inline size_t golden_growth_ceil(size_t n)
8+
{
9+
/* This effectively is a return ceil(n * φ).
10+
φ is approximatively 207 / (2^7), so we shift our result by
11+
6, then perform our ceil by adding the remainder of the last division
12+
by 2 of the result to itself. */
13+
14+
n = (n * 207) >> 6;
15+
n = (n >> 1) + (n & 1);
16+
return n;
17+
}
18+
19+
int fmemi_grow(struct fmem_stream *stream, size_t required)
20+
{
21+
if (stream->cursor > SIZE_MAX - required) {
22+
errno = EOVERFLOW;
23+
return -1;
24+
}
25+
required += stream->cursor;
26+
27+
size_t newsize = stream->region_size;
28+
if (required <= newsize) {
29+
return 0;
30+
}
31+
32+
while (required > newsize) {
33+
newsize = golden_growth_ceil(newsize);
34+
}
35+
36+
char *newmem = realloc(stream->buf->mem, newsize);
37+
if (!newmem) {
38+
return -1;
39+
}
40+
stream->buf->mem = newmem;
41+
stream->region_size = newsize;
42+
return 0;
43+
}
44+
45+
int fmemi_cursor(struct fmemi_buf *buf, struct fmem_stream *from)
46+
{
47+
if (from->buf->size < from->cursor) {
48+
return -1;
49+
}
50+
51+
buf->mem = from->buf->mem + from->cursor;
52+
buf->size = from->buf->size - from->cursor;
53+
return 0;
54+
}
55+
56+
size_t fmemi_copy(struct fmemi_buf *to, struct fmemi_buf *from)
57+
{
58+
size_t copied = from->size < to->size ? from->size : to->size;
59+
memcpy(to->mem, from->mem, copied);
60+
return copied;
61+
}

src/alloc.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#ifndef ALLOC_H_
2+
#define ALLOC_H_
3+
4+
#include <stddef.h>
5+
6+
struct fmemi_buf {
7+
char *mem;
8+
size_t size;
9+
};
10+
11+
struct fmem_stream {
12+
struct fmemi_buf *buf;
13+
size_t cursor;
14+
size_t region_size;
15+
};
16+
17+
int fmemi_grow(struct fmem_stream *stream, size_t required);
18+
int fmemi_cursor(struct fmemi_buf *buf, struct fmem_stream *from);
19+
size_t fmemi_copy(struct fmemi_buf *to, struct fmemi_buf *from);
20+
21+
#endif /* !ALLOC_H_ */

src/fmem-fopencookie.c

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
#define _GNU_SOURCE
2+
#include <errno.h>
3+
#include <stdlib.h>
4+
#include <string.h>
5+
6+
#include "alloc.h"
7+
#include "fmem.h"
8+
9+
union fmem_conv {
10+
fmem *fm;
11+
struct fmemi_buf *buf;
12+
};
13+
14+
void fmem_init(fmem *file)
15+
{
16+
union fmem_conv cv = { .fm = file };
17+
memset(cv.buf, 0, sizeof (*cv.buf));
18+
}
19+
20+
void fmem_term(fmem *file)
21+
{
22+
union fmem_conv cv = { .fm = file };
23+
free(cv.buf->mem);
24+
}
25+
26+
static ssize_t mem_write(void *cookie, const char *buf, size_t size)
27+
{
28+
struct fmem_stream *stream = cookie;
29+
30+
struct fmemi_buf from = { (char *) buf, size };
31+
struct fmemi_buf to;
32+
33+
if (fmemi_grow(stream, size) < 0) {
34+
return -1;
35+
}
36+
if (fmemi_cursor(&to, stream) < 0) {
37+
return 0;
38+
}
39+
40+
size_t copied = fmemi_copy(&to, &from);
41+
stream->cursor += copied;
42+
return copied;
43+
}
44+
45+
static ssize_t mem_read(void *cookie, char *buf, size_t size)
46+
{
47+
struct fmem_stream *stream = cookie;
48+
49+
struct fmemi_buf to = { buf, size };
50+
struct fmemi_buf from;
51+
52+
if (fmemi_cursor(&from, stream) < 0) {
53+
return 0;
54+
}
55+
56+
size_t copied = fmemi_copy(&to, &from);
57+
stream->cursor += copied;
58+
return copied;
59+
}
60+
61+
static int mem_seek(void *cookie, off64_t *off, int whence)
62+
{
63+
struct fmem_stream *stream = cookie;
64+
65+
size_t newoff;
66+
switch (whence) {
67+
case SEEK_SET: newoff = *off; break;
68+
case SEEK_CUR: newoff = stream->cursor + *off; break;
69+
case SEEK_END: newoff = stream->buf->size + *off; break;
70+
default: errno = EINVAL; return -1;
71+
}
72+
if (newoff > stream->buf->size || (off64_t)newoff < 0) {
73+
return -1;
74+
}
75+
*off = newoff;
76+
return 0;
77+
}
78+
79+
static int mem_close(void *cookie)
80+
{
81+
free(cookie);
82+
return 0;
83+
}
84+
85+
FILE *fmem_open(fmem *file, const char *mode)
86+
{
87+
static cookie_io_functions_t funcs = {
88+
.read = mem_read,
89+
.write = mem_write,
90+
.seek = mem_seek,
91+
.close = mem_close,
92+
};
93+
94+
union fmem_conv cv = { .fm = file };
95+
96+
free(cv.buf->mem);
97+
cv.buf->mem = malloc(128);
98+
if (!cv.buf->mem)
99+
return NULL;
100+
101+
struct fmem_stream *stream = malloc(sizeof (*stream));
102+
if (!stream) {
103+
free(cv.buf->mem);
104+
cv.buf->mem = NULL;
105+
return NULL;
106+
}
107+
108+
*stream = (struct fmem_stream) {
109+
.buf = &cv.buf,
110+
.region_size = 128,
111+
};
112+
113+
FILE *f = fopencookie(stream, mode, funcs);
114+
if (!f)
115+
free(stream);
116+
return f;
117+
}
118+
119+
void fmem_mem(fmem *file, void **mem, size_t *size)
120+
{
121+
union fmem_conv cv = { .fm = file };
122+
*mem = cv.buf->mem;
123+
*size = cv.buf->size;
124+
}

0 commit comments

Comments
 (0)