~ubuntu-branches/ubuntu/utopic/mpd/utopic-proposed

« back to all changes in this revision

Viewing changes to src/input/RewindInputPlugin.cxx

  • Committer: Package Import Robot
  • Author(s): Steve Kowalik
  • Date: 2013-11-12 18:17:40 UTC
  • mfrom: (2.2.36 sid)
  • Revision ID: package-import@ubuntu.com-20131112181740-72aa4zihehoobedp
Tags: 0.18.3-1ubuntu1
* Merge from Debian unstable.  Remaining changes:
  - Add libmp3lame-dev to Build-Depends, and enable LAME.
  - Read the user for the daemon from the config file in the init script.
  - Move avahi-daemon from Suggests to Recommends.
  - Added apport hook to include user configuration file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2003-2013 The Music Player Daemon Project
 
3
 * http://www.musicpd.org
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation; either version 2 of the License, or
 
8
 * (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License along
 
16
 * with this program; if not, write to the Free Software Foundation, Inc.,
 
17
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
18
 */
 
19
 
 
20
#include "config.h"
 
21
#include "RewindInputPlugin.hxx"
 
22
#include "InputStream.hxx"
 
23
#include "InputPlugin.hxx"
 
24
#include "tag/Tag.hxx"
 
25
 
 
26
#include <assert.h>
 
27
#include <string.h>
 
28
#include <stdio.h>
 
29
 
 
30
extern const InputPlugin rewind_input_plugin;
 
31
 
 
32
struct RewindInputStream {
 
33
        InputStream base;
 
34
 
 
35
        InputStream *input;
 
36
 
 
37
        /**
 
38
         * The read position within the buffer.  Undefined as long as
 
39
         * ReadingFromBuffer() returns false.
 
40
         */
 
41
        size_t head;
 
42
 
 
43
        /**
 
44
         * The write/append position within the buffer.
 
45
         */
 
46
        size_t tail;
 
47
 
 
48
        /**
 
49
         * The size of this buffer is the maximum number of bytes
 
50
         * which can be rewinded cheaply without passing the "seek"
 
51
         * call to CURL.
 
52
         *
 
53
         * The origin of this buffer is always the beginning of the
 
54
         * stream (offset 0).
 
55
         */
 
56
        char buffer[64 * 1024];
 
57
 
 
58
        RewindInputStream(InputStream *_input)
 
59
                :base(rewind_input_plugin, _input->uri.c_str(),
 
60
                      _input->mutex, _input->cond),
 
61
                 input(_input), tail(0) {
 
62
        }
 
63
 
 
64
        ~RewindInputStream() {
 
65
                input->Close();
 
66
        }
 
67
 
 
68
        /**
 
69
         * Are we currently reading from the buffer, and does the
 
70
         * buffer contain more data for the next read operation?
 
71
         */
 
72
        bool ReadingFromBuffer() const {
 
73
                return tail > 0 && base.offset < input->offset;
 
74
        }
 
75
 
 
76
        /**
 
77
         * Copy public attributes from the underlying input stream to the
 
78
         * "rewind" input stream.  This function is called when a method of
 
79
         * the underlying stream has returned, which may have modified these
 
80
         * attributes.
 
81
         */
 
82
        void CopyAttributes() {
 
83
                InputStream *dest = &base;
 
84
                const InputStream *src = input;
 
85
 
 
86
                assert(dest != src);
 
87
 
 
88
                bool dest_ready = dest->ready;
 
89
 
 
90
                dest->ready = src->ready;
 
91
                dest->seekable = src->seekable;
 
92
                dest->size = src->size;
 
93
                dest->offset = src->offset;
 
94
 
 
95
                if (!dest_ready && src->ready)
 
96
                        dest->mime = src->mime;
 
97
        }
 
98
};
 
99
 
 
100
static void
 
101
input_rewind_close(InputStream *is)
 
102
{
 
103
        RewindInputStream *r = (RewindInputStream *)is;
 
104
 
 
105
        delete r;
 
106
}
 
107
 
 
108
static bool
 
109
input_rewind_check(InputStream *is, Error &error)
 
110
{
 
111
        RewindInputStream *r = (RewindInputStream *)is;
 
112
 
 
113
        return r->input->Check(error);
 
114
}
 
115
 
 
116
static void
 
117
input_rewind_update(InputStream *is)
 
118
{
 
119
        RewindInputStream *r = (RewindInputStream *)is;
 
120
 
 
121
        if (!r->ReadingFromBuffer())
 
122
                r->CopyAttributes();
 
123
}
 
124
 
 
125
static Tag *
 
126
input_rewind_tag(InputStream *is)
 
127
{
 
128
        RewindInputStream *r = (RewindInputStream *)is;
 
129
 
 
130
        return r->input->ReadTag();
 
131
}
 
132
 
 
133
static bool
 
134
input_rewind_available(InputStream *is)
 
135
{
 
136
        RewindInputStream *r = (RewindInputStream *)is;
 
137
 
 
138
        return r->input->IsAvailable();
 
139
}
 
140
 
 
141
static size_t
 
142
input_rewind_read(InputStream *is, void *ptr, size_t size,
 
143
                  Error &error)
 
144
{
 
145
        RewindInputStream *r = (RewindInputStream *)is;
 
146
 
 
147
        if (r->ReadingFromBuffer()) {
 
148
                /* buffered read */
 
149
 
 
150
                assert(r->head == (size_t)is->offset);
 
151
                assert(r->tail == (size_t)r->input->offset);
 
152
 
 
153
                if (size > r->tail - r->head)
 
154
                        size = r->tail - r->head;
 
155
 
 
156
                memcpy(ptr, r->buffer + r->head, size);
 
157
                r->head += size;
 
158
                is->offset += size;
 
159
 
 
160
                return size;
 
161
        } else {
 
162
                /* pass method call to underlying stream */
 
163
 
 
164
                size_t nbytes = r->input->Read(ptr, size, error);
 
165
 
 
166
                if (r->input->offset > (InputPlugin::offset_type)sizeof(r->buffer))
 
167
                        /* disable buffering */
 
168
                        r->tail = 0;
 
169
                else if (r->tail == (size_t)is->offset) {
 
170
                        /* append to buffer */
 
171
 
 
172
                        memcpy(r->buffer + r->tail, ptr, nbytes);
 
173
                        r->tail += nbytes;
 
174
 
 
175
                        assert(r->tail == (size_t)r->input->offset);
 
176
                }
 
177
 
 
178
                r->CopyAttributes();
 
179
 
 
180
                return nbytes;
 
181
        }
 
182
}
 
183
 
 
184
static bool
 
185
input_rewind_eof(InputStream *is)
 
186
{
 
187
        RewindInputStream *r = (RewindInputStream *)is;
 
188
 
 
189
        return !r->ReadingFromBuffer() && r->input->IsEOF();
 
190
}
 
191
 
 
192
static bool
 
193
input_rewind_seek(InputStream *is, InputPlugin::offset_type offset,
 
194
                  int whence,
 
195
                  Error &error)
 
196
{
 
197
        RewindInputStream *r = (RewindInputStream *)is;
 
198
 
 
199
        assert(is->ready);
 
200
 
 
201
        if (whence == SEEK_SET && r->tail > 0 &&
 
202
            offset <= (InputPlugin::offset_type)r->tail) {
 
203
                /* buffered seek */
 
204
 
 
205
                assert(!r->ReadingFromBuffer() ||
 
206
                       r->head == (size_t)is->offset);
 
207
                assert(r->tail == (size_t)r->input->offset);
 
208
 
 
209
                r->head = (size_t)offset;
 
210
                is->offset = offset;
 
211
 
 
212
                return true;
 
213
        } else {
 
214
                bool success = r->input->Seek(offset, whence, error);
 
215
                r->CopyAttributes();
 
216
 
 
217
                /* disable the buffer, because r->input has left the
 
218
                   buffered range now */
 
219
                r->tail = 0;
 
220
 
 
221
                return success;
 
222
        }
 
223
}
 
224
 
 
225
const InputPlugin rewind_input_plugin = {
 
226
        nullptr,
 
227
        nullptr,
 
228
        nullptr,
 
229
        nullptr,
 
230
        input_rewind_close,
 
231
        input_rewind_check,
 
232
        input_rewind_update,
 
233
        input_rewind_tag,
 
234
        input_rewind_available,
 
235
        input_rewind_read,
 
236
        input_rewind_eof,
 
237
        input_rewind_seek,
 
238
};
 
239
 
 
240
InputStream *
 
241
input_rewind_open(InputStream *is)
 
242
{
 
243
        assert(is != nullptr);
 
244
        assert(is->offset == 0);
 
245
 
 
246
        if (is->seekable)
 
247
                /* seekable resources don't need this plugin */
 
248
                return is;
 
249
 
 
250
        RewindInputStream *c = new RewindInputStream(is);
 
251
        return &c->base;
 
252
}