summaryrefslogtreecommitdiffstats
path: root/src/roof-read-file.c
blob: da8d51cd7306dda94c61db2cea8e2d270ce53cfb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <stdint.h>

#include "glib.h"

#include "ufo-roof.h"
#include "ufo-roof-read-file.h"

typedef struct {
    RoofReadInterface iface;

    RoofConfig *cfg;

    gchar *fname;
    FILE *fd;
    uint8_t *buf;
} RoofReadFile;

static void roof_read_file_free(RoofReadInterface *iface) {
    RoofReadFile *reader = (RoofReadFile*)iface;

    if (reader) {
        if (reader->fname)
            g_free(reader->fname);

        if (reader->fd) 
            fclose(reader->fd);

        if (reader->buf)
            free(reader->buf);
        free(reader);
    }
}

static guint roof_read_file(RoofReadInterface *iface, uint8_t **buffers, GError **error) {
    RoofReadFile *reader = (RoofReadFile*)iface;
    RoofConfig *cfg = reader->cfg;

    assert(iface);
    assert(buffers);

    size_t bytes = 0;
    size_t packet_size = cfg->header_size + cfg->payload_size;
    size_t expected = cfg->max_packets * packet_size;

    while ((!feof(reader->fd))&&(!ferror(reader->fd))&&(bytes < expected)) {
        size_t ret = fread(reader->buf + bytes, 1, expected - bytes, reader->fd);
        bytes += ret;
    }

    guint packets = bytes / packet_size;

    if (ferror(reader->fd)) {
        roof_network_error_with_retval(error, 0, "read failed, error %i", ferror(reader->fd));
    } else if ((feof(reader->fd))&&(bytes % packet_size)) {
        roof_network_error_with_retval(error, packets, "extra data in the end of input");
    }

    *buffers = reader->buf;
    return packets;
}


RoofReadInterface *roof_read_file_new(RoofConfig *cfg, const char *path, guint file_id, GError **error) {
    RoofReadFile *reader = (RoofReadFile*)calloc(1, sizeof(RoofReadFile));
    if (!reader) roof_new_error(error, "Can't allocate RoofReadFile");
    
        // FIXME: Shall we jump if max_packet_size > header+payload (or will be extra data included in the data files)? Report error for now.
    if ((cfg->header_size + cfg->payload_size) != cfg->max_packet_size)
        roof_new_error(error, "packet_size (%u) should be equal to max_packet_size (%u) if RoofReadFile is used", cfg->header_size + cfg->payload_size, cfg->max_packet_size);

    reader->cfg = cfg;
    reader->iface.close = roof_read_file_free;
    reader->iface.read =roof_read_file;
    
    reader->fname = g_strdup_printf(path, file_id);
    if (!reader->fname) {
        free(reader);
        roof_new_error(error, "Can't build file name");
    }

    reader->fd = fopen(reader->fname, "rb");
    if (!reader->fd) {
        g_free(reader->fname);
        g_free(reader);
        roof_new_error(error, "Can't open file %i at path %s", file_id, path);
    }

    reader->buf = (uint8_t*)malloc(cfg->max_packets * (cfg->header_size + cfg->payload_size));
    if (!reader->buf) {
        roof_read_file_free((RoofReadInterface*)reader);
        roof_new_error(error, "Can't allocate file buffer");
    }

    return (RoofReadInterface*)reader;
}