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.
220 lines
5.2 KiB
C
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;
|
|
}
|