Exemplo n.º 1
0
static int gio_ftruncate (VFSFile * file, int64_t length)
{
    FileData * data = vfs_get_handle (file);
    GError * error = 0;

    g_seekable_truncate (data->seekable, length, NULL, & error);
    CHECK_ERROR ("truncate", vfs_get_filename (file));

    return 0;

FAILED:
    return -1;
}
Exemplo n.º 2
0
int neon_vfs_fclose_impl (VFSFile * file)
{
    struct neon_handle * h = vfs_get_handle (file);

    if (h->reader_status.reading)
        kill_reader (h);

    if (h->request)
        ne_request_destroy (h->request);
    if (h->session)
        ne_session_destroy (h->session);

    handle_free (h);

    return 0;
}
Exemplo n.º 3
0
static int probe_buffer_fseek (VFSFile * file, int64_t offset, int whence)
{
    ProbeBuffer * p = vfs_get_handle (file);

    if (whence == SEEK_END)
        return -1;

    if (whence == SEEK_CUR)
        offset += p->at;

    g_return_val_if_fail (offset >= 0, -1);
    increase_buffer (p, offset);

    if (offset > p->filled)
        return -1;

    p->at = offset;
    return 0;
}
Exemplo n.º 4
0
static int64_t gio_fwrite (const void * buf, int64_t size, int64_t nitems, VFSFile * file)
{
    FileData * data = vfs_get_handle (file);
    GError * error = 0;

    if (! data->ostream)
    {
        gio_error ("Cannot write to %s: not open for writing.", vfs_get_filename (file));
        return 0;
    }

    int64_t written = g_output_stream_write (data->ostream, buf, size * nitems, 0, & error);
    CHECK_ERROR ("write to", vfs_get_filename (file));

    return (size > 0) ? written / size : 0;

FAILED:
    return 0;
}
Exemplo n.º 5
0
static int64_t gio_fread (void * buf, int64_t size, int64_t nitems, VFSFile * file)
{
    FileData * data = vfs_get_handle (file);
    GError * error = 0;

    if (! data->istream)
    {
        gio_error ("Cannot read from %s: not open for reading.", vfs_get_filename (file));
        return 0;
    }

    int64_t readed = g_input_stream_read (data->istream, buf, size * nitems, 0, & error);
    CHECK_ERROR ("read from", vfs_get_filename (file));

    return (size > 0) ? readed / size : 0;

FAILED:
    return 0;
}
Exemplo n.º 6
0
static int64_t gio_fsize (VFSFile * file)
{
    FileData * data = vfs_get_handle (file);
    GError * error = 0;

    /* Audacious core expects one of two cases:
     *  1) File size is known and file is seekable.
     *  2) File size is unknown and file is not seekable.
     * Therefore, we return -1 for size if file is not seekable. */
    if (! g_seekable_can_seek (data->seekable))
        return -1;

    GFileInfo * info = g_file_query_info (data->file,
     G_FILE_ATTRIBUTE_STANDARD_SIZE, 0, 0, & error);
    CHECK_ERROR ("get size of", vfs_get_filename (file));

    int64_t size = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_STANDARD_SIZE);

    g_object_unref (info);
    return size;

FAILED:
    return -1;
}
Exemplo n.º 7
0
static char * probe_buffer_get_metadata (VFSFile * file, const char * field)
{
    return vfs_get_metadata (((ProbeBuffer *) vfs_get_handle (file))->file, field);
}
Exemplo n.º 8
0
static int64_t probe_buffer_fsize (VFSFile * file)
{
    return vfs_fsize (((ProbeBuffer *) vfs_get_handle (file))->file);
}
Exemplo n.º 9
0
static bool_t probe_buffer_feof (VFSFile * file)
{
    ProbeBuffer * p = vfs_get_handle (file);
    return (p->at < p->filled) ? FALSE : vfs_feof (p->file);
}
Exemplo n.º 10
0
static int64_t probe_buffer_ftell (VFSFile * file)
{
    return ((ProbeBuffer *) vfs_get_handle (file))->at;
}
Exemplo n.º 11
0
static int64_t gio_ftell (VFSFile * file)
{
    FileData * data = vfs_get_handle (file);
    return g_seekable_tell (data->seekable);
}
Exemplo n.º 12
0
static int64_t neon_fread_real (void * ptr, int64_t size, int64_t nmemb, VFSFile * file)
{
    struct neon_handle * h = vfs_get_handle (file);

    if (! h->request)
    {
        _ERROR ("<%p> No request to read from, seek gone wrong?", (void *) h);
        return 0;
    }

    if (! size || ! nmemb || h->eof)
        return 0;

    /* If the buffer is empty, wait for the reader thread to fill it. */
    pthread_mutex_lock (& h->reader_status.mutex);

    for (int retries = 0; retries < NEON_RETRY_COUNT; retries ++)
    {
        if (used_rb_locked (& h->rb) / size > 0 || ! h->reader_status.reading ||
         h->reader_status.status != NEON_READER_RUN)
            break;

        pthread_cond_broadcast (& h->reader_status.cond);
        pthread_cond_wait (& h->reader_status.cond, & h->reader_status.mutex);
    }

    pthread_mutex_unlock (& h->reader_status.mutex);

    if (! h->reader_status.reading)
    {
        if (h->reader_status.status != NEON_READER_EOF || h->content_length != -1)
        {
            /* There is no reader thread yet. Read the first bytes from
             * the network ourselves, and then fire up the reader thread
             * to keep the buffer filled up. */
            _DEBUG ("<%p> Doing initial buffer fill", h);
            FillBufferResult ret = fill_buffer (h);

            if (ret == FILL_BUFFER_ERROR)
            {
                _ERROR ("<%p> Error while reading from the network", (void *) h);
                return 0;
            }

            /* We have some data in the buffer now.
             * Start the reader thread if we did not reach EOF during
             * the initial fill */
            pthread_mutex_lock (& h->reader_status.mutex);

            if (ret == FILL_BUFFER_SUCCESS)
            {
                h->reader_status.reading = TRUE;
                _DEBUG ("<%p> Starting reader thread", h);
                pthread_create (& h->reader, NULL, reader_thread, h);
                h->reader_status.status = NEON_READER_RUN;
            }
            else if (ret == FILL_BUFFER_EOF)
            {
                _DEBUG ("<%p> No reader thread needed (stream has reached EOF during fill)", h);
                h->reader_status.reading = FALSE;
                h->reader_status.status = NEON_READER_EOF;
            }

            pthread_mutex_unlock (& h->reader_status.mutex);
        }
    }
    else
    {
        /* There already is a reader thread. Look if it is in good shape. */
        pthread_mutex_lock (& h->reader_status.mutex);

        switch (h->reader_status.status)
        {
        case NEON_READER_INIT:
        case NEON_READER_RUN:
            /* All is well, nothing to be done. */
            break;

        case NEON_READER_ERROR:
            /* A reader error happened. Log it, and treat it like an EOF
             * condition, by falling through to the NEON_READER_EOF codepath. */
            _DEBUG ("<%p> NEON_READER_ERROR happened. Terminating reader thread and marking EOF.", h);
            h->reader_status.status = NEON_READER_EOF;
            pthread_mutex_unlock (& h->reader_status.mutex);

            if (h->reader_status.reading)
                kill_reader (h);

            pthread_mutex_lock (& h->reader_status.mutex);

        case NEON_READER_EOF:
            /* If there still is data in the buffer, carry on.
             * If not, terminate the reader thread and return 0. */
            if (! used_rb_locked (& h->rb))
            {
                _DEBUG ("<%p> Reached end of stream", h);
                pthread_mutex_unlock (& h->reader_status.mutex);

                if (h->reader_status.reading)
                    kill_reader (h);

                h->eof = TRUE;
                return 0;
            }

            break;

        case NEON_READER_TERM:
            /* The reader thread terminated gracefully, most likely on our own request.
             * We should not get here. */
            g_warn_if_reached ();
            pthread_mutex_unlock (& h->reader_status.mutex);
            return 0;
        }

        pthread_mutex_unlock (& h->reader_status.mutex);
    }

    /* Deliver data from the buffer */
    if (! used_rb (& h->rb))
    {
        /* The buffer is still empty, we can deliver no data! */
        _ERROR ("<%p> Buffer still underrun, fatal.", (void *) h);
        return 0;
    }

    int belem = used_rb (& h->rb) / size;

    if (h->icy_metaint)
    {
        if (! h->icy_metaleft)
        {
            /* The next data in the buffer is a ICY metadata announcement.
             * Get the length byte */
            unsigned char icy_metalen;
            read_rb (& h->rb, & icy_metalen, 1);

            /*  We need enough data in the buffer to
             * a) Read the complete ICY metadata block
             * b) deliver at least one byte to the reader */
            _DEBUG ("<%p> Expecting %d bytes of ICY metadata", h, (icy_metalen*16));

            if (free_rb (& h->rb) - icy_metalen * 16 < size)
            {
                /* There is not enough data. We do not have much choice at this point,
                 * so we'll deliver the metadata as normal data to the reader and
                 * hope for the best. */
                _ERROR ("<%p> Buffer underrun when reading metadata. Expect "
                 "audio degradation", (void *) h);
                h->icy_metaleft = h->icy_metaint + icy_metalen * 16;
            }
            else
            {
                /* Grab the metadata from the buffer and send it to the parser */
                char icy_metadata[NEON_ICY_BUFSIZE];
                read_rb (& h->rb, icy_metadata, icy_metalen * 16);
                parse_icy (& h->icy_metadata, icy_metadata, icy_metalen * 16);
                h->icy_metaleft = h->icy_metaint;
            }
        }

        /* The maximum number of bytes we can deliver is determined
         * by the number of bytes left until the next metadata announcement */
        belem = MIN (used_rb (& h->rb), h->icy_metaleft) / size;
    }

    nmemb = MIN (belem, nmemb);
    read_rb (& h->rb, ptr, nmemb * size);

    /* Signal the network thread to continue reading */
    pthread_mutex_lock (& h->reader_status.mutex);

    if (h->reader_status.status == NEON_READER_EOF)
    {
        if (! free_rb_locked (& h->rb))
        {
            _DEBUG ("<%p> stream EOF reached and buffer empty", h);
            h->eof = TRUE;
        }
    }
    else
        pthread_cond_broadcast (& h->reader_status.cond);

    pthread_mutex_unlock (& h->reader_status.mutex);

    h->pos += nmemb * size;
    h->icy_metaleft -= nmemb * size;

    return nmemb;
}