~ubuntu-branches/ubuntu/saucy/mpd/saucy

« back to all changes in this revision

Viewing changes to src/tag_ape.c

  • Committer: Bazaar Package Importer
  • Author(s): Angel Abad
  • Date: 2011-02-02 12:26:30 UTC
  • mfrom: (1.5.11 upstream)
  • Revision ID: james.westby@ubuntu.com-20110202122630-bdyx8w4k94doz4fs
Tags: 0.16.1-1ubuntu1
* Merge from debian unstable. Remaining changes:
  - debian/control:
    + Don't build-depend on libmikmod2-dev (Debian bug #510675).
    + Move avahi-daemon from Suggests field to Recommends field.
  - debian/mpd.init.d:
    + Read mpd user from mpd.conf.
  - debian/control, debian/rules:
    + Add libmp3lame-dev to the build dependencies and enable lame.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * Copyright (C) 2003-2009 The Music Player Daemon Project
 
2
 * Copyright (C) 2003-2010 The Music Player Daemon Project
3
3
 * http://www.musicpd.org
4
4
 *
5
5
 * This program is free software; you can redistribute it and/or modify
17
17
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
18
 */
19
19
 
 
20
#include "config.h"
20
21
#include "tag_ape.h"
21
22
#include "tag.h"
22
23
#include "tag_table.h"
23
 
 
24
 
#include <glib.h>
25
 
 
26
 
#include <assert.h>
27
 
#include <stdio.h>
 
24
#include "ape.h"
28
25
 
29
26
static const char *const ape_tag_names[TAG_NUM_OF_ITEM_TYPES] = {
30
 
        [TAG_ITEM_ALBUM_ARTIST] = "album artist",
31
 
        [TAG_ITEM_DATE] = "year"
 
27
        [TAG_ALBUM_ARTIST] = "album artist",
 
28
        [TAG_DATE] = "year",
32
29
};
33
30
 
34
31
static enum tag_type
55
52
 
56
53
        if (tag == NULL)
57
54
                tag = tag_new();
58
 
        tag_add_item_n(tag, type, value, value_length);
 
55
 
 
56
        const char *end = value + value_length;
 
57
        while (true) {
 
58
                /* multiple values are separated by null bytes */
 
59
                const char *n = memchr(value, 0, end - value);
 
60
                if (n != NULL) {
 
61
                        if (n > value)
 
62
                                tag_add_item_n(tag, type, value, n - value);
 
63
                        value = n + 1;
 
64
                } else {
 
65
                        if (end > value)
 
66
                                tag_add_item_n(tag, type, value, end - value);
 
67
                        break;
 
68
                }
 
69
        }
59
70
 
60
71
        return tag;
61
72
}
62
73
 
 
74
struct tag_ape_ctx {
 
75
        struct tag *tag;
 
76
};
 
77
 
 
78
static bool
 
79
tag_ape_callback(unsigned long flags, const char *key,
 
80
                 const char *value, size_t value_length, void *_ctx)
 
81
{
 
82
        struct tag_ape_ctx *ctx = _ctx;
 
83
 
 
84
        ctx->tag = tag_ape_import_item(ctx->tag, flags, key,
 
85
                                       value, value_length);
 
86
        return true;
 
87
}
 
88
 
63
89
struct tag *
64
90
tag_ape_load(const char *file)
65
91
{
66
 
        struct tag *ret = NULL;
67
 
        FILE *fp;
68
 
        int tagCount;
69
 
        char *buffer = NULL;
70
 
        char *p;
71
 
        size_t tagLen;
72
 
        size_t size;
73
 
        unsigned long flags;
74
 
        char *key;
75
 
 
76
 
        struct {
77
 
                unsigned char id[8];
78
 
                uint32_t version;
79
 
                uint32_t length;
80
 
                uint32_t tagCount;
81
 
                unsigned char flags[4];
82
 
                unsigned char reserved[8];
83
 
        } footer;
84
 
 
85
 
        fp = fopen(file, "r");
86
 
        if (!fp)
87
 
                return NULL;
88
 
 
89
 
        /* determine if file has an apeV2 tag */
90
 
        if (fseek(fp, 0, SEEK_END))
91
 
                goto fail;
92
 
        size = (size_t)ftell(fp);
93
 
        if (fseek(fp, size - sizeof(footer), SEEK_SET))
94
 
                goto fail;
95
 
        if (fread(&footer, 1, sizeof(footer), fp) != sizeof(footer))
96
 
                goto fail;
97
 
        if (memcmp(footer.id, "APETAGEX", sizeof(footer.id)) != 0)
98
 
                goto fail;
99
 
        if (GUINT32_FROM_LE(footer.version) != 2000)
100
 
                goto fail;
101
 
 
102
 
        /* find beginning of ape tag */
103
 
        tagLen = GUINT32_FROM_LE(footer.length);
104
 
        if (tagLen <= sizeof(footer) + 10)
105
 
                goto fail;
106
 
        if (tagLen > 1024 * 1024)
107
 
                /* refuse to load more than one megabyte of tag data */
108
 
                goto fail;
109
 
        if (fseek(fp, size - tagLen, SEEK_SET))
110
 
                goto fail;
111
 
 
112
 
        /* read tag into buffer */
113
 
        tagLen -= sizeof(footer);
114
 
        assert(tagLen > 10);
115
 
 
116
 
        buffer = g_malloc(tagLen);
117
 
        if (fread(buffer, 1, tagLen, fp) != tagLen)
118
 
                goto fail;
119
 
 
120
 
        /* read tags */
121
 
        tagCount = GUINT32_FROM_LE(footer.tagCount);
122
 
        p = buffer;
123
 
        while (tagCount-- && tagLen > 10) {
124
 
                size = GUINT32_FROM_LE(*(const uint32_t *)p);
125
 
                p += 4;
126
 
                tagLen -= 4;
127
 
                flags = GUINT32_FROM_LE(*(const uint32_t *)p);
128
 
                p += 4;
129
 
                tagLen -= 4;
130
 
 
131
 
                /* get the key */
132
 
                key = p;
133
 
                while (tagLen > size && *p != '\0') {
134
 
                        p++;
135
 
                        tagLen--;
136
 
                }
137
 
                p++;
138
 
                tagLen--;
139
 
 
140
 
                /* get the value */
141
 
                if (tagLen < size)
142
 
                        goto fail;
143
 
 
144
 
                ret = tag_ape_import_item(ret, flags, key, p, size);
145
 
 
146
 
                p += size;
147
 
                tagLen -= size;
148
 
        }
149
 
 
150
 
fail:
151
 
        if (fp)
152
 
                fclose(fp);
153
 
        g_free(buffer);
154
 
        return ret;
 
92
        struct tag_ape_ctx ctx = { .tag = NULL };
 
93
 
 
94
        tag_ape_scan(file, tag_ape_callback, &ctx);
 
95
        return ctx.tag;
155
96
}