libdc/examples/output_raw.c
Jef Driesen 5d9ddafc41 Add support for the raw output format.
The RAW output format exports each dive to a raw (binary) file. To
output multiple files, the filename is interpreted as a template and
should contain one or more placeholders.
2016-02-26 08:23:55 +01:00

220 lines
5.1 KiB
C

/*
* libdivecomputer
*
* Copyright (C) 2016 Jef Driesen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "output-private.h"
#include "utils.h"
static dc_status_t dctool_raw_output_write (dctool_output_t *output, dc_parser_t *parser, const unsigned char data[], unsigned int size, const unsigned char fingerprint[], unsigned int fsize);
static dc_status_t dctool_raw_output_free (dctool_output_t *output);
typedef struct dctool_raw_output_t {
dctool_output_t base;
char *template;
} dctool_raw_output_t;
static const dctool_output_vtable_t raw_vtable = {
sizeof(dctool_raw_output_t), /* size */
dctool_raw_output_write, /* write */
dctool_raw_output_free, /* free */
};
static int
mktemplate_fingerprint (char *buffer, size_t size, const unsigned char fingerprint[], size_t fsize)
{
const unsigned char ascii[] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
if (size < 2 * fsize + 1)
return -1;
for (size_t i = 0; i < fsize; ++i) {
// Set the most-significant nibble.
unsigned char msn = (fingerprint[i] >> 4) & 0x0F;
buffer[i * 2 + 0] = ascii[msn];
// Set the least-significant nibble.
unsigned char lsn = fingerprint[i] & 0x0F;
buffer[i * 2 + 1] = ascii[lsn];
}
// Null-terminate the string.
buffer[fsize * 2] = 0;
return fsize * 2;
}
static int
mktemplate_datetime (char *buffer, size_t size, dc_parser_t *parser)
{
dc_status_t rc = DC_STATUS_SUCCESS;
dc_datetime_t datetime = {0};
int n = 0;
rc = dc_parser_get_datetime (parser, &datetime);
if (rc != DC_STATUS_SUCCESS)
return -1;
n = snprintf (buffer, size, "%04i%02i%02iT%02i%02i%02i",
datetime.year, datetime.month, datetime.day,
datetime.hour, datetime.minute, datetime.second);
if (n < 0 || n >= size)
return -1;
return n;
}
static int
mktemplate_number (char *buffer, size_t size, unsigned int number)
{
int n = 0;
n = snprintf (buffer, size, "%04u", number);
if (n < 0 || n >= size)
return -1;
return n;
}
static int
mktemplate (char *buffer, size_t size, const char *format, dc_parser_t *parser, const unsigned char fingerprint[], size_t fsize, unsigned int number)
{
const char *p = format;
size_t n = 0;
int len = 0;
char ch = 0;
while ((ch = *p++) != 0) {
if (ch != '%') {
if (n >= size)
return -1;
buffer[n] = ch;
n++;
continue;
}
ch = *p++;
switch (ch) {
case '%':
if (n >= size)
return -1;
buffer[n] = ch;
n++;
break;
case 't': // Timestamp
len = mktemplate_datetime (buffer + n, size - n, parser);
if (len < 0)
return -1;
n += len;
break;
case 'f': // Fingerprint
len = mktemplate_fingerprint (buffer + n, size - n, fingerprint, fsize);
if (len < 0)
return -1;
n += len;
break;
case 'n': // Number
len = mktemplate_number (buffer + n, size - n, number);
if (len < 0)
return -1;
n += len;
break;
default:
return -1;
}
}
// Null-terminate the string
if (n >= size)
return -1;
buffer[n] = 0;
return n;
}
dctool_output_t *
dctool_raw_output_new (const char *template)
{
dctool_raw_output_t *output = NULL;
if (template == NULL)
goto error_exit;
// Allocate memory.
output = (dctool_raw_output_t *) dctool_output_allocate (&raw_vtable);
if (output == NULL) {
goto error_exit;
}
output->template = strdup(template);
if (output->template == NULL) {
goto error_free;
}
return (dctool_output_t *) output;
error_free:
dctool_output_deallocate ((dctool_output_t *) output);
error_exit:
return NULL;
}
static dc_status_t
dctool_raw_output_write (dctool_output_t *abstract, dc_parser_t *parser, const unsigned char data[], unsigned int size, const unsigned char fingerprint[], unsigned int fsize)
{
dctool_raw_output_t *output = (dctool_raw_output_t *) abstract;
// Generate the filename.
char name[1024] = {0};
int ret = mktemplate (name, sizeof(name), output->template, parser, fingerprint, fsize, abstract->number);
if (ret < 0) {
ERROR("Failed to generate filename from template.");
return DC_STATUS_SUCCESS;
}
// Open the output file.
FILE *fp = fopen (name, "wb");
if (fp == NULL) {
ERROR("Failed to open the output file.");
return DC_STATUS_SUCCESS;
}
// Write the data.
fwrite (data, sizeof (unsigned char), size, fp);
fclose (fp);
return DC_STATUS_SUCCESS;
}
static dc_status_t
dctool_raw_output_free (dctool_output_t *abstract)
{
dctool_raw_output_t *output = (dctool_raw_output_t *) abstract;
free (output->template);
return DC_STATUS_SUCCESS;
}