summaryrefslogtreecommitdiff
path: root/src/common/fifo.c
blob: 214e276b7e4e79678146ec5983c80f5bf4b3d774 (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
/*
Copyright (C) 2003-2008 Andrey Nazarov

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program 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 General Public License for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "shared/shared.h"
#include "common/fifo.h"
#include "common/msg.h"

size_t FIFO_Read(fifo_t *fifo, void *buffer, size_t len)
{
    size_t wrapped, head = fifo->ay - fifo->ax;

    if (head > len) {
        if (buffer) {
            memcpy(buffer, fifo->data + fifo->ax, len);
            fifo->ax += len;
        }
        return len;
    }

    wrapped = len - head;
    if (wrapped > fifo->bs) {
        wrapped = fifo->bs;
    }
    if (buffer) {
        memcpy(buffer, fifo->data + fifo->ax, head);
        memcpy((byte *)buffer + head, fifo->data, wrapped);
        fifo->ax = wrapped;
        fifo->ay = fifo->bs;
        fifo->bs = 0;
    }

    return head + wrapped;
}

size_t FIFO_Write(fifo_t *fifo, const void *buffer, size_t len)
{
    size_t tail, wrapped, remaining;

    if (fifo->bs) {
        remaining = fifo->ax - fifo->bs;
        if (len > remaining) {
            len = remaining;
        }
        if (buffer) {
            memcpy(fifo->data + fifo->bs, buffer, len);
            fifo->bs += len;
        }
        return len;
    }

    tail = fifo->size - fifo->ay;
    if (tail > len) {
        if (buffer) {
            memcpy(fifo->data + fifo->ay, buffer, len);
            fifo->ay += len;
        }
        return len;
    }

    wrapped = len - tail;
    if (wrapped > fifo->ax) {
        wrapped = fifo->ax;
    }
    if (buffer) {
        memcpy(fifo->data + fifo->ay, buffer, tail);
        memcpy(fifo->data, (byte *)buffer + tail, wrapped);
        fifo->ay = fifo->size;
        fifo->bs = wrapped;
    }

    return tail + wrapped;
}

qboolean FIFO_ReadMessage(fifo_t *fifo, size_t msglen)
{
    size_t len;
    byte *data;

    data = FIFO_Peek(fifo, &len);
    if (len < msglen) {
        // read in two chunks into message buffer
        if (!FIFO_TryRead(fifo, msg_read_buffer, msglen)) {
            return qfalse; // not yet available
        }
        SZ_Init(&msg_read, msg_read_buffer, sizeof(msg_read_buffer));
    } else {
        // read in a single block without copying any memory
        SZ_Init(&msg_read, data, msglen);
        FIFO_Decommit(fifo, msglen);
    }

    msg_read.cursize = msglen;
    return qtrue;
}