summaryrefslogtreecommitdiff
path: root/apps/plugins/xracer/map.c
blob: 6900dab23e6093d067b20947e463d6efa61b3f18 (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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include <stdbool.h>
#include <stdint.h>

#include "generator.h"
#include "map.h"
#include "util.h"

static bool add_section(struct road_segment *road, unsigned int max_road_length, unsigned int *back, struct road_section *map)
{
    bool ret = true;
    switch(map->type)
    {
    case 0:
        /* constant segment */
        add_road(road, max_road_length, *back, map->len, map->curve, map->slope);
        *back += map->len;
        break;
    case 1:
        /* up-hill */
        add_uphill(road, max_road_length, *back, map->slope, map->len, map->curve);
        *back += map->len + 2*map->slope;
        break;
    case 2:
        add_downhill(road, max_road_length, *back, map->slope, map->len, map->curve);
        *back += map->len + 2*map->slope;
        break;
    default:
        warning("invalid type id");
        ret = false;
        break;
    }
    return ret;
}

unsigned load_map(struct road_segment *road, unsigned int max_road_length, struct road_section *map, unsigned int map_length)
{
    gen_reset();
    unsigned int back = 0;
    for(unsigned int i=0;i<map_length;++i)
    {
        add_section(road, max_road_length, &back, &map[i]);
    }
    return back;
}

unsigned load_external_map(struct road_segment *road, unsigned int max_road_length, const char *filename)
{
    int fd = rb->open(filename, O_RDONLY, 0666);
    if(fd < 0)
    {
        warning("Map file could not be opened");
        return -1;
    }

    /* check the header */
    static const unsigned char cmp_header[8] = {'X', 'M', 'a', 'P',
                                                ((MAP_VERSION & 0xFF00) >> 8),
                                                ((MAP_VERSION & 0x00FF) >> 0),
                                                0xFF, 0xFF };
    unsigned char header[8];
    int ret = rb->read(fd, header, sizeof(header));
    if(ret != sizeof(header) || rb->memcmp(header, cmp_header, sizeof(header)) != 0)
    {
        warning("Malformed map header (version mismatch?)");
        return -1;
    }

    /* read data */
    unsigned char data_buf[16];
    unsigned int back = 0;
    bool fail = false;

    gen_reset();

    do {

        ret = rb->read(fd, data_buf, sizeof(data_buf));
        if(ret != sizeof(data_buf))
        {
            break;
        }

        uint16_t calc_crc16 = crc16_ccitt(data_buf, 12, 0, 0xFFFF);
        uint8_t calc_xor_value = ((calc_crc16 & 0xFF00) >> 8 ) ^ (calc_crc16 & 0xFF);

        uint16_t crc16 = (data_buf[0x0D] << 8) | (data_buf[0x0E]);
        uint8_t xor_value = data_buf[0x0F];
        if((calc_crc16 != crc16))
        {
            warning("Bad checksum");
            fail = true;
        }
        if(calc_xor_value != xor_value)
        {
            warning("Bad XOR value");
            fail = true;
        }

        struct road_section section =
            {
                data_buf[0],
                READ_BE_UINT32(&data_buf[1]),
                READ_BE_UINT32(&data_buf[5]),
                READ_BE_UINT32(&data_buf[9])
            };

        bool status = add_section(road, max_road_length, &back, &section);

        if(!status)
        {
            warning("Unknown map section type");
            fail = true;
        }

    } while(ret == sizeof(data_buf));

    /* last number of bytes read was not zero, this indicates failure */
    if(ret)
    {
        warning("Data too long");
        fail = true;
    }

    rb->close(fd);

    if(fail)
        return -1;
    else
        return back;
}