libdc/examples/output_raw.c
Jef Driesen 1130b7eade Fix -Wsign-compare compiler warnings
Comparing signed and unsigned integer expressions can have unexpected
results because the signed integer will get promoted to an unsigned
integer. To avoid the warning, add an explicit cast to the unsigned
type, along with a check to catch negative values.
2021-01-05 09:32:45 +01:00

220 lines
5.2 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 || (size_t) 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 || (size_t) 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;
}