Skip to content

Commit

Permalink
feat: first version
Browse files Browse the repository at this point in the history
  • Loading branch information
thefab committed Oct 31, 2018
1 parent 78b888b commit 7cc73c2
Show file tree
Hide file tree
Showing 27 changed files with 1,317 additions and 1 deletion.
10 changes: 10 additions & 0 deletions .drone.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
pipeline:
build:
image: metwork/mfcom-${OS_VERSION}-buildimage:integration
commands:
- /opt/metwork-mfext/bin/mfext_wrapper layer_wrapper --layers=mapserver@mfext -- make MAPSERVER_LIB_DIR=/opt/metwork-mfext/opt/mapserver/lib PREFIX=/opt/metwork-mfext/opt/mapserver clean all test install

matrix:
OS_VERSION:
- centos6
- centos7
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

# Linker output
*.ilk
*.map
*.exp

# Precompiled Headers
Expand Down Expand Up @@ -50,3 +49,7 @@ modules.order
Module.symvers
Mkfile.old
dkms.conf

src/test_mapserverapi
src/testresult.png
src/mapserverapi.pc
96 changes: 96 additions & 0 deletions .metwork-framework/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
## What is it ?

This is a tiny C library to invoke [mapserver](http://mapserver.org) engine
as a library (with no daemon or CGI).

## Build

### Prerequisites

- mapserver installed
- standard compilation tools (gcc, make...)
- glib2 library and corresponding headers

### Building

To build the library you must specify:

- `MAPSERVER_LIB_DIR`: the full path of the directory containing `libmapserver.so`
- `PREFIX`: the full path of the directory where you want to install the library

For example:

```
make MAPSERVER_LIB_DIR=/opt/mapserver/lib PREFIX=/usr/local clean all install
```

### Testing

You must have `valgrind` tool installed.

```
make MAPSERVER_LIB_DIR=/opt/mapserver/lib PREFIX=/usr/local test
```

## Usage

### Compilation flags

The library use `pkg-config` tool. So you can use the following command to
get the compilation flags:

```
pkg-config --cflags --libs mapserverapi
```

If not found, you may have to add `PREFIX` at the end of `${PKG_CONFIG_PATH}`
environnement variable.

### In your code

```C
#include <mapserverapi.h>

// [...]

# Init the library (mandatory)
mapserverapi_init();

gchar *mapfile_content;
# [...]
# Put a mapfile content into mapfile_content string

# Set a WMS query_string (for this example)
gchar *query_string = "LAYERS=ocean&TRANSPARENT=true&FORMAT=image%2Fpng&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&STYLES=&EXCEPTIONS=application%2Fvnd.ogc.se_xml&SRS=EPSG%3A4326&BBOX=-180.0,-90.0,180.0,90.0&WIDTH=500&HEIGHT=250"

# Invoke mapserver
void *body;
gchar *content_type = NULL;
gsize body_length;
gboolean b = mapserverapi_invoke(mapfile_content, query_string, &body, &content_type, &body_length);
if (b == TRUE) {
# you have the full body (PNG image in this example) in body variable (this buffer is managed by the library, don't free it by yourself !)
# you have the body length in body_length variable.
# you have the content_type of the body in content_type variable (you have to free it after use).

# [...]

# free content_type when you have finished with them
# (but don't free body variable)
g_free(content_type);
}

# Another way to use the library, invoke mapserver and get the body in a file
gchar *content_type2 = NULL;
gboolean

# Destroy the library
mapserverapi_destroy();
```
### Uninstalling
```
make MAPSERVER_LIB_DIR=/opt/mapserver/lib PREFIX=/usr/local uninstall
```
11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
all:
cd src && $(MAKE) all

clean:
cd src && $(MAKE) clean

test:
cd src && $(MAKE) test

install:
cd src && $(MAKE) install
48 changes: 48 additions & 0 deletions src/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
ifndef MAPSERVER_LIB_DIR
$(error MAPSERVER_LIB_DIR is not set, see README.md file)
endif
ifndef PREFIX
$(error PREFIX is not set, see README.md file)
endif

_LDFLAGS=$(LDFLAGS) -L. $(shell pkg-config --libs glib-2.0) -L$(MAPSERVER_LIB_DIR) -L$(PREFIX)/lib -lmapserver
_CFLAGS=$(CFLAGS) -I. $(shell pkg-config --cflags glib-2.0) -I$(PREFIX)/include -fPIC -Wall
CC=gcc

OBJECTS=random.o mapserverapi.o
BINARIES=libmapserverapi.so test_mapserverapi

all: $(OBJECTS) $(BINARIES) mapserverapi.pc

clean:
rm -f $(OBJECTS) $(BINARIES) core.* vgcore.* testresult.png mapserverapi.pc

mapserverapi.pc: mapserverapi.pc.pc
cat $< |sed 's~@@@PREFIX@@@~$(PREFIX)~g' |sed 's~@@@MAPSERVER_LIB_DIR@@@~$(MAPSERVER_LIB_DIR)~g' >$@

random.o: random.c random.h
$(CC) -c $(_CFLAGS) -o $@ $<

mapserverapi.o: mapserverapi.c mapserverapi.h
$(CC) -c $(_CFLAGS) -o $@ $<

test_mapserverapi: test_mapserverapi.c $(OBJECTS)
$(CC) $(_CFLAGS) $(_LDFLAGS) -o $@ $^

libmapserverapi.so: $(OBJECTS)
$(CC) -shared $(_CFLAGS) $(_LDFLAGS) -o $@ $^

install: all
if ! test -d $(PREFIX)/lib/pkgconfig; then mkdir -p $(PREFIX)/lib/pkgconfig; fi
if ! test -d $(PREFIX)/include; then mkdir -p $(PREFIX)/include; fi
cp -f libmapserverapi.so $(PREFIX)/lib/
cp -f mapserverapi.h $(PREFIX)/include/
cp -f mapserverapi.pc $(PREFIX)/lib/pkgconfig/

uninstall:
rm -f $(PREFIX)/lib/libmapserverapi.so
rm -f $(PREFIX)/include/mapserverapi.h
rm -f $(PREFIX)/lib/pkgconfig/mapserverapi.pc

test: all
valgrind --show-possibly-lost=no --leak-check=full ./test_mapserverapi
7 changes: 7 additions & 0 deletions src/mapserver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#ifndef MAPSERVERAPI_MAPSERVER_H_
#define MAPSERVERAPI_MAPSERVER_H_

int msCGIHandler(const char *query_string, void **out_buffer, size_t *buffer_length);
void msIO_resetHandlers(void);

#endif /* MAPSERVERAPI_MAPSERVER_H_ */
166 changes: 166 additions & 0 deletions src/mapserverapi.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
#include "mapserverapi.h"
#include <glib.h>
#include <string.h>
#include <unistd.h>

#include "random.h"
#include "mapserver.h"

static gboolean __MAPSERVERAPI_INITIALIZED = FALSE;
static gchar *__MAPSERVERAPI_TMPDIR = NULL;

void mapserverapi_init() {
if (__MAPSERVERAPI_INITIALIZED) {
g_critical("mapserverapi already initialized: call mapserverapi_destroy() before");
g_assert(__MAPSERVERAPI_INITIALIZED == FALSE);
}
__MAPSERVERAPI_INITIALIZED = TRUE;
const gchar *tmp;
tmp = g_getenv("MAPSERVERAPI_TMPDIR");
if (tmp != NULL) {
__MAPSERVERAPI_TMPDIR = g_strdup(tmp);
return;
}
tmp = g_getenv("TMPDIR");
if (tmp != NULL) {
__MAPSERVERAPI_TMPDIR = g_strdup(tmp);
return;
}
tmp = g_getenv("TMP");
if (tmp != NULL) {
__MAPSERVERAPI_TMPDIR = g_strdup(tmp);
return;
}
__MAPSERVERAPI_TMPDIR = g_strdup("/tmp");
}

void mapserverapi_destroy() {
if (__MAPSERVERAPI_INITIALIZED == FALSE) {
g_critical("mapserverapi not initialized: call mapserverapi_init() before");
g_assert(__MAPSERVERAPI_INITIALIZED == TRUE);
}
msIO_resetHandlers();
__MAPSERVERAPI_INITIALIZED = FALSE;
g_free(__MAPSERVERAPI_TMPDIR);
}

gchar *get_tmpfilename() {
gchar *unique = get_unique_hexa_identifier();
gchar *tmp = g_strdup_printf("%s/mapserverapi_%s.map", __MAPSERVERAPI_TMPDIR,
unique);
g_free(unique);
return tmp;
}

void assert_mapserverapi_initialized() {
if (__MAPSERVERAPI_INITIALIZED == FALSE) {
g_critical("mapserverapi not initialized: call mapserverapi_init() before use");
g_assert(__MAPSERVERAPI_INITIALIZED);
}
}

gboolean mapserverapi_invoke(const gchar *mapfile_content, const gchar *query_string, void **body,
gchar **content_type, gsize *body_length) {
assert_mapserverapi_initialized();
g_assert(mapfile_content != NULL);
g_assert(body != NULL);
g_assert(query_string != NULL);
g_assert(strlen(query_string) > 0);
gboolean res;
gchar *mapfile_path = get_tmpfilename();
res = g_file_set_contents(mapfile_path, mapfile_content, -1, NULL);
if (!res) {
g_critical("can't write mapfile in %s", mapfile_path);
g_free(mapfile_path);
return FALSE;
}
GString *gs = g_string_new(NULL);
g_string_append_printf(gs, "MAP=%s", mapfile_path);
gs = g_string_append_c(gs, '&');
if (query_string[0] == '?') {
gs = g_string_append(gs, query_string + sizeof(gchar));
} else {
gs = g_string_append(gs, query_string);
}
gchar *mapserver_qs = g_string_free(gs, FALSE);
int mapserver_status;
void *mapserver_buffer;
size_t mapserver_buffer_length;
res = TRUE;
g_debug("Calling mapserver with query_string[%s]...", mapserver_qs);
mapserver_status = msCGIHandler(mapserver_qs, &mapserver_buffer, &mapserver_buffer_length);
unlink(mapfile_path);
g_free(mapfile_path);
if (mapserver_status != 0) {
g_warning("bad reply from mapserver for query_string = %s", mapserver_qs);
res = FALSE;
}
if (mapserver_buffer_length < 14) {
g_warning("bad reply from mapserver for query_string = %s (no Content-Type)", mapserver_qs);
g_free(mapserver_qs);
return FALSE;
}
if (strncasecmp((const char*) mapserver_buffer, "Content-type: ", 14) != 0) {
g_warning("bad reply from mapserver for query_string = %s (no Content-Type)", mapserver_qs);
g_free(mapserver_qs);
return FALSE;
}
int end_of_ct = 13;
while ((end_of_ct + 1 < mapserver_buffer_length) && (((char*)mapserver_buffer)[end_of_ct + 1] != 10)) {
end_of_ct++;
}
if (end_of_ct + 1 == mapserver_buffer_length) {
g_warning("bad reply from mapserver for query_string = %s (bad Content-Type)", query_string);
g_free(mapserver_qs);
return FALSE;
}
int start_of_data = end_of_ct + 2;
while ((start_of_data < mapserver_buffer_length) && (((char*)mapserver_buffer)[start_of_data] != 10)) {
start_of_data++;
}
if (start_of_data == mapserver_buffer_length) {
g_warning("bad reply from mapserver for query_string = %s (corrupt Content-Type)", mapserver_qs);
g_free(mapserver_qs);
return FALSE;
}
start_of_data++;
gchar *ct = g_malloc((end_of_ct - 14 + 2) * sizeof(gchar));
memcpy(ct, mapserver_buffer + 14 * sizeof(gchar), sizeof(gchar) * (end_of_ct - 14 + 2));
ct[end_of_ct - 14 + 1] = '\0';
if (content_type != NULL) {
*content_type = g_strstrip(ct);
} else {
g_free(ct);
}
if (body != NULL) {
*body = mapserver_buffer + start_of_data * sizeof(gchar);
}
if (body_length != NULL) {
*body_length = mapserver_buffer_length - start_of_data;
}
g_free(mapserver_qs);
return res;
}

gchar *mapserverapi_invoke_to_file(const gchar *mapfile_content, const gchar *query_string,
const gchar *target_file) {
void *body = NULL;
gsize body_length;
gchar *tmp_content_type = NULL;
gboolean res = mapserverapi_invoke(mapfile_content, query_string, &body,
&tmp_content_type, &body_length);
if (res == FALSE) {
return NULL;
}
GError *error = NULL;
gboolean res2 = g_file_set_contents(target_file, body, body_length, &error);
if (res2 == FALSE) {
g_warning("can't write mapserver output to target_file: %s", target_file);
if (error != NULL) {
g_warning("error message: %s", error->message);
}
g_free(tmp_content_type);
return NULL;
}
return tmp_content_type;
}
11 changes: 11 additions & 0 deletions src/mapserverapi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifndef MAPSERVERAPI_H_
#define MAPSERVERAPI_H_

#include <glib.h>

void mapserverapi_init();
void mapserverapi_destroy();
gboolean mapserverapi_invoke(const gchar *mapfile_content, const gchar *query_string, void **body, gchar **content_type, gsize *body_length);
gchar *mapserverapi_invoke_to_file(const gchar *mapfile_content, const gchar *query_string, const gchar *target_file);

#endif /* MAPSERVERAPI_H_ */
11 changes: 11 additions & 0 deletions src/mapserverapi.pc.pc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
prefix=@@@PREFIX@@@@
exec_prefix=@@@PREFIX@@@
libdir=@@@PREFIX@@@/lib
includedir=@@@PREFIX@@@/include

Name: mapserverapi
Description: tiny library to invoke mapserver as a library
Version: 0.1.0
Requires: glib-2.0 gobject-2.0 gthread-2.0
Libs: -L$(libdir) -lmapserverapi -L@@@MAPSERVER_LIB_DIR@@@ -lmapserver
Cflags: -I$(includedir)
Loading

0 comments on commit 7cc73c2

Please sign in to comment.