~ubuntu-branches/ubuntu/utopic/rhythmbox/utopic-proposed

« back to all changes in this revision

Viewing changes to daapsharing/rb-daap-structure.c

Tags: upstream-0.9.2
ImportĀ upstreamĀ versionĀ 0.9.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Header for DAAP (iTunes Music Sharing) structures
 
3
 *
 
4
 *  Copyright (C) 2004,2005 Charles Schmidt <cschmidt2@emich.edu>
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; either version 2 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  This program is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with this program; if not, write to the Free Software
 
18
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
19
 *
 
20
 */
 
21
 
 
22
#include <glib.h>
 
23
#include <glib-object.h>
 
24
#include <gobject/gvaluecollector.h>
 
25
#include "rb-daap-structure.h"
 
26
#include "rb-debug.h"
 
27
 
 
28
#include <gst/gstutils.h>
 
29
 
 
30
#include <string.h>
 
31
#include <stdarg.h>
 
32
 
 
33
#define MAKE_CONTENT_CODE(ch0, ch1, ch2, ch3) \
 
34
    (( (gint32)(gchar)(ch0) | ( (gint32)(gchar)(ch1) << 8 ) | \
 
35
    ( (gint32)(gchar)(ch2) << 16 ) | \
 
36
    ( (gint32)(gchar)(ch3) << 24 ) ))
 
37
 
 
38
static const RBDAAPContentCodeDefinition cc_defs[] = {
 
39
        {RB_DAAP_CC_MDCL, MAKE_CONTENT_CODE('m','d','c','l'), "dmap.dictionary", "mdcl", RB_DAAP_TYPE_CONTAINER},
 
40
        {RB_DAAP_CC_MSTT, MAKE_CONTENT_CODE('m','s','t','t'), "dmap.status", "mstt", RB_DAAP_TYPE_INT},
 
41
        {RB_DAAP_CC_MIID, MAKE_CONTENT_CODE('m','i','i','d'), "dmap.itemid", "miid", RB_DAAP_TYPE_INT},
 
42
        {RB_DAAP_CC_MINM, MAKE_CONTENT_CODE('m','i','n','m'), "dmap.itemname", "minm", RB_DAAP_TYPE_STRING},
 
43
        {RB_DAAP_CC_MIKD, MAKE_CONTENT_CODE('m','i','k','d'), "dmap.itemkind", "mikd", RB_DAAP_TYPE_BYTE},
 
44
        {RB_DAAP_CC_MPER, MAKE_CONTENT_CODE('m','p','e','r'), "dmap.persistentid", "mper", RB_DAAP_TYPE_INT64},
 
45
        {RB_DAAP_CC_MCON, MAKE_CONTENT_CODE('m','c','o','n'), "dmap.container", "mcon", RB_DAAP_TYPE_CONTAINER},
 
46
        {RB_DAAP_CC_MCTI, MAKE_CONTENT_CODE('m','c','t','i'), "dmap.containeritemid", "mcti", RB_DAAP_TYPE_INT},
 
47
        {RB_DAAP_CC_MPCO, MAKE_CONTENT_CODE('m','p','c','o'), "dmap.parentcontainerid", "mpco", RB_DAAP_TYPE_INT},
 
48
        {RB_DAAP_CC_MSTS, MAKE_CONTENT_CODE('m','s','t','s'), "dmap.statusstring", "msts", RB_DAAP_TYPE_STRING},
 
49
        {RB_DAAP_CC_MIMC, MAKE_CONTENT_CODE('m','i','m','c'), "dmap.itemcount", "mimc", RB_DAAP_TYPE_INT},
 
50
        {RB_DAAP_CC_MCTC, MAKE_CONTENT_CODE('m','c','t','c'), "dmap.containercount", "mctc", RB_DAAP_TYPE_INT},
 
51
        {RB_DAAP_CC_MRCO, MAKE_CONTENT_CODE('m','r','c','o'), "dmap.returnedcount", "mrco", RB_DAAP_TYPE_INT},
 
52
        {RB_DAAP_CC_MTCO, MAKE_CONTENT_CODE('m','t','c','o'), "dmap.specifiedtotalcount", "mtco", RB_DAAP_TYPE_INT},
 
53
        {RB_DAAP_CC_MLCL, MAKE_CONTENT_CODE('m','l','c','l'), "dmap.listing", "mlcl", RB_DAAP_TYPE_CONTAINER},
 
54
        {RB_DAAP_CC_MLIT, MAKE_CONTENT_CODE('m','l','i','t'), "dmap.listingitem", "mlit", RB_DAAP_TYPE_CONTAINER},
 
55
        {RB_DAAP_CC_MBCL, MAKE_CONTENT_CODE('m','b','c','l'), "dmap.bag", "mbcl", RB_DAAP_TYPE_CONTAINER},
 
56
        {RB_DAAP_CC_MSRV, MAKE_CONTENT_CODE('m','s','r','v'), "dmap.serverinforesponse", "msrv", RB_DAAP_TYPE_CONTAINER},
 
57
        {RB_DAAP_CC_MSAU, MAKE_CONTENT_CODE('m','s','a','u'), "dmap.authenticationmethod", "msau", RB_DAAP_TYPE_BYTE},
 
58
        {RB_DAAP_CC_MSLR, MAKE_CONTENT_CODE('m','s','l','r'), "dmap.loginrequired", "mslr", RB_DAAP_TYPE_BYTE},
 
59
        {RB_DAAP_CC_MPRO, MAKE_CONTENT_CODE('m','p','r','o'), "dmap.protocolversion", "mpro", RB_DAAP_TYPE_VERSION},
 
60
        {RB_DAAP_CC_APRO, MAKE_CONTENT_CODE('a','p','r','o'), "daap.protocolversion", "apro", RB_DAAP_TYPE_VERSION},
 
61
        {RB_DAAP_CC_MSAL, MAKE_CONTENT_CODE('m','s','a','l'), "dmap.supportsautologout", "msal", RB_DAAP_TYPE_BYTE},
 
62
        {RB_DAAP_CC_MSUP, MAKE_CONTENT_CODE('m','s','u','p'), "dmap.supportsupdate", "msup", RB_DAAP_TYPE_BYTE},
 
63
        {RB_DAAP_CC_MSPI, MAKE_CONTENT_CODE('m','s','p','i'), "dmap.supportspersistenids", "mspi", RB_DAAP_TYPE_BYTE},
 
64
        {RB_DAAP_CC_MSEX, MAKE_CONTENT_CODE('m','s','e','x'), "dmap.supportsextensions", "msex", RB_DAAP_TYPE_BYTE},
 
65
        {RB_DAAP_CC_MSBR, MAKE_CONTENT_CODE('m','s','b','r'), "dmap.supportsbrowse", "msbr", RB_DAAP_TYPE_BYTE},
 
66
        {RB_DAAP_CC_MSQY, MAKE_CONTENT_CODE('m','s','q','y'), "dmap.supportsquery", "msqy", RB_DAAP_TYPE_BYTE},
 
67
        {RB_DAAP_CC_MSIX, MAKE_CONTENT_CODE('m','s','i','x'), "dmap.supportsindex", "msix", RB_DAAP_TYPE_BYTE},
 
68
        {RB_DAAP_CC_MSRS, MAKE_CONTENT_CODE('m','s','r','s'), "dmap.supportsresolve", "msrs", RB_DAAP_TYPE_BYTE},
 
69
        {RB_DAAP_CC_MSTM, MAKE_CONTENT_CODE('m','s','t','m'), "dmap.timeoutinterval", "mstm", RB_DAAP_TYPE_INT},
 
70
        {RB_DAAP_CC_MSDC, MAKE_CONTENT_CODE('m','s','d','c'), "dmap.databasescount", "msdc", RB_DAAP_TYPE_INT},
 
71
        {RB_DAAP_CC_MCCR, MAKE_CONTENT_CODE('m','c','c','r'), "dmap.contentcodesresponse", "mccr", RB_DAAP_TYPE_CONTAINER},
 
72
        {RB_DAAP_CC_MCNM, MAKE_CONTENT_CODE('m','c','n','m'), "dmap.contentcodesnumber", "mcnm", RB_DAAP_TYPE_INT},
 
73
        {RB_DAAP_CC_MCNA, MAKE_CONTENT_CODE('m','c','n','a'), "dmap.contentcodesname", "mcna", RB_DAAP_TYPE_STRING},
 
74
        {RB_DAAP_CC_MCTY, MAKE_CONTENT_CODE('m','c','t','y'), "dmap.contentcodestype", "mcty", RB_DAAP_TYPE_SHORT},
 
75
        {RB_DAAP_CC_MLOG, MAKE_CONTENT_CODE('m','l','o','g'), "dmap.loginresponse", "mlog", RB_DAAP_TYPE_CONTAINER},
 
76
        {RB_DAAP_CC_MLID, MAKE_CONTENT_CODE('m','l','i','d'), "dmap.sessionid", "mlid", RB_DAAP_TYPE_INT},
 
77
        {RB_DAAP_CC_MUPD, MAKE_CONTENT_CODE('m','u','p','d'), "dmap.updateresponse", "mupd", RB_DAAP_TYPE_CONTAINER},
 
78
        {RB_DAAP_CC_MUSR, MAKE_CONTENT_CODE('m','u','s','r'), "dmap.serverrevision", "musr", RB_DAAP_TYPE_INT},
 
79
        {RB_DAAP_CC_MUTY, MAKE_CONTENT_CODE('m','u','t','y'), "dmap.updatetype", "muty", RB_DAAP_TYPE_BYTE},
 
80
        {RB_DAAP_CC_MUDL, MAKE_CONTENT_CODE('m','u','d','l'), "dmap.deletedidlisting", "mudl", RB_DAAP_TYPE_CONTAINER},
 
81
        {RB_DAAP_CC_AVDB, MAKE_CONTENT_CODE('a','v','d','b'), "daap.serverdatabases", "avdb", RB_DAAP_TYPE_CONTAINER},
 
82
        {RB_DAAP_CC_ABRO, MAKE_CONTENT_CODE('a','b','r','o'), "daap.databasebrowse", "abro", RB_DAAP_TYPE_CONTAINER},
 
83
        {RB_DAAP_CC_ABAL, MAKE_CONTENT_CODE('a','b','a','l'), "daap.browsealbumlisting", "abal", RB_DAAP_TYPE_CONTAINER},
 
84
        {RB_DAAP_CC_ABAR, MAKE_CONTENT_CODE('a','b','a','r'), "daap.browseartistlisting", "abar", RB_DAAP_TYPE_CONTAINER},
 
85
        {RB_DAAP_CC_ABCP, MAKE_CONTENT_CODE('a','b','c','p'), "daap.browsecomposerlisting", "abcp", RB_DAAP_TYPE_CONTAINER},
 
86
        {RB_DAAP_CC_ABGN, MAKE_CONTENT_CODE('a','b','g','n'), "daap.browsegenrelisting", "abgn", RB_DAAP_TYPE_CONTAINER},
 
87
        {RB_DAAP_CC_ADBS, MAKE_CONTENT_CODE('a','d','b','s'), "daap.returndatabasesongs", "adbs", RB_DAAP_TYPE_CONTAINER},
 
88
        {RB_DAAP_CC_ASAL, MAKE_CONTENT_CODE('a','s','a','l'), "daap.songalbum", "asal", RB_DAAP_TYPE_STRING},
 
89
        {RB_DAAP_CC_ASAR, MAKE_CONTENT_CODE('a','s','a','r'), "daap.songartist", "asar", RB_DAAP_TYPE_STRING},
 
90
        {RB_DAAP_CC_ASBT, MAKE_CONTENT_CODE('a','s','b','t'), "daap.songsbeatsperminute", "asbt", RB_DAAP_TYPE_SHORT},
 
91
        {RB_DAAP_CC_ASBR, MAKE_CONTENT_CODE('a','s','b','r'), "daap.songbitrate", "asbr", RB_DAAP_TYPE_SHORT},
 
92
        {RB_DAAP_CC_ASCM, MAKE_CONTENT_CODE('a','s','c','m'), "daap.songcomment", "ascm", RB_DAAP_TYPE_STRING},
 
93
        {RB_DAAP_CC_ASCO, MAKE_CONTENT_CODE('a','s','c','o'), "daap.songcompliation", "asco", RB_DAAP_TYPE_BYTE},
 
94
        {RB_DAAP_CC_ASDA, MAKE_CONTENT_CODE('a','s','d','a'), "daap.songdateadded", "asda", RB_DAAP_TYPE_DATE},
 
95
        {RB_DAAP_CC_ASDM, MAKE_CONTENT_CODE('a','s','d','m'), "daap.songdatemodified", "asdm", RB_DAAP_TYPE_DATE},
 
96
        {RB_DAAP_CC_ASDC, MAKE_CONTENT_CODE('a','s','d','c'), "daap.songdisccount", "asdc", RB_DAAP_TYPE_SHORT},
 
97
        {RB_DAAP_CC_ASDN, MAKE_CONTENT_CODE('a','s','d','n'), "daap.songdiscnumber", "asdn", RB_DAAP_TYPE_SHORT},
 
98
        {RB_DAAP_CC_ASDB, MAKE_CONTENT_CODE('a','s','d','b'), "daap.songdisabled", "asdb", RB_DAAP_TYPE_BYTE},
 
99
        {RB_DAAP_CC_ASEQ, MAKE_CONTENT_CODE('a','s','e','q'), "daap.songeqpreset", "aseq", RB_DAAP_TYPE_STRING},
 
100
        {RB_DAAP_CC_ASFM, MAKE_CONTENT_CODE('a','s','f','m'), "daap.songformat", "asfm", RB_DAAP_TYPE_STRING},
 
101
        {RB_DAAP_CC_ASGN, MAKE_CONTENT_CODE('a','s','g','n'), "daap.songgenre", "asgn", RB_DAAP_TYPE_STRING},
 
102
        {RB_DAAP_CC_ASDT, MAKE_CONTENT_CODE('a','s','d','t'), "daap.songdescription", "asdt", RB_DAAP_TYPE_STRING},
 
103
        {RB_DAAP_CC_ASRV, MAKE_CONTENT_CODE('a','s','r','v'), "daap.songrelativevolume", "asrv", RB_DAAP_TYPE_SIGNED_INT},
 
104
        {RB_DAAP_CC_ASSR, MAKE_CONTENT_CODE('a','s','s','r'), "daap.songsamplerate", "assr", RB_DAAP_TYPE_INT},
 
105
        {RB_DAAP_CC_ASSZ, MAKE_CONTENT_CODE('a','s','s','z'), "daap.songsize", "assz", RB_DAAP_TYPE_INT},
 
106
        {RB_DAAP_CC_ASST, MAKE_CONTENT_CODE('a','s','s','t'), "daap.songstarttime", "asst", RB_DAAP_TYPE_INT},
 
107
        {RB_DAAP_CC_ASSP, MAKE_CONTENT_CODE('a','s','s','p'), "daap.songstoptime", "assp", RB_DAAP_TYPE_INT},
 
108
        {RB_DAAP_CC_ASTM, MAKE_CONTENT_CODE('a','s','t','m'), "daap.songtime", "astm", RB_DAAP_TYPE_INT},
 
109
        {RB_DAAP_CC_ASTC, MAKE_CONTENT_CODE('a','s','t','c'), "daap.songtrackcount", "astc", RB_DAAP_TYPE_SHORT},
 
110
        {RB_DAAP_CC_ASTN, MAKE_CONTENT_CODE('a','s','t','n'), "daap.songtracknumber", "astn", RB_DAAP_TYPE_SHORT},
 
111
        {RB_DAAP_CC_ASUR, MAKE_CONTENT_CODE('a','s','u','r'), "daap.songuserrating", "asur", RB_DAAP_TYPE_BYTE},
 
112
        {RB_DAAP_CC_ASYR, MAKE_CONTENT_CODE('a','s','y','r'), "daap.songyear", "asyr", RB_DAAP_TYPE_SHORT},
 
113
        {RB_DAAP_CC_ASDK, MAKE_CONTENT_CODE('a','s','d','k'), "daap.songdatakind", "asdk", RB_DAAP_TYPE_BYTE},
 
114
        {RB_DAAP_CC_ASUL, MAKE_CONTENT_CODE('a','s','u','l'), "daap.songdataurl", "asul", RB_DAAP_TYPE_STRING},
 
115
        {RB_DAAP_CC_APLY, MAKE_CONTENT_CODE('a','p','l','y'), "daap.databaseplaylists", "aply", RB_DAAP_TYPE_CONTAINER},
 
116
        {RB_DAAP_CC_ABPL, MAKE_CONTENT_CODE('a','b','p','l'), "daap.baseplaylist", "abpl", RB_DAAP_TYPE_BYTE},
 
117
        {RB_DAAP_CC_APSO, MAKE_CONTENT_CODE('a','p','s','o'), "daap.playlistsongs", "apso", RB_DAAP_TYPE_CONTAINER},
 
118
        {RB_DAAP_CC_PRSV, MAKE_CONTENT_CODE('p','r','s','v'), "daap.resolve", "prsv", RB_DAAP_TYPE_CONTAINER},
 
119
        {RB_DAAP_CC_ARIF, MAKE_CONTENT_CODE('a','r','i','f'), "daap.resolveinfo", "arif", RB_DAAP_TYPE_CONTAINER},
 
120
        {RB_DAAP_CC_AESV, MAKE_CONTENT_CODE('a','e','S','V'), "com.applie.itunes.music-sharing-version", "aesv", RB_DAAP_TYPE_INT},
 
121
        {RB_DAAP_CC_MSAS, MAKE_CONTENT_CODE('m','s','a','s'), "daap.authentication.schemes", "msas", RB_DAAP_TYPE_BYTE},
 
122
        {RB_DAAP_CC_AGRP, MAKE_CONTENT_CODE('a','g','r','p'), "daap.songgrouping", "agrp", RB_DAAP_TYPE_STRING},
 
123
        {RB_DAAP_CC_ASCP, MAKE_CONTENT_CODE('a','s','c','p'), "daap.songcomposer", "ascp", RB_DAAP_TYPE_STRING}
 
124
        };
 
125
 
 
126
 
 
127
const gchar * 
 
128
rb_daap_content_code_name (RBDAAPContentCode code)
 
129
{
 
130
        return cc_defs[code-1].name;
 
131
}
 
132
 
 
133
RBDAAPType 
 
134
rb_daap_content_code_rb_daap_type (RBDAAPContentCode code)
 
135
{
 
136
        return cc_defs[code-1].type;
 
137
}
 
138
 
 
139
const gchar * 
 
140
rb_daap_content_code_string (RBDAAPContentCode code)
 
141
{
 
142
        return cc_defs[code-1].string;
 
143
}
 
144
                        
 
145
static GType
 
146
rb_daap_content_code_gtype (RBDAAPContentCode code)
 
147
{
 
148
        switch (rb_daap_content_code_rb_daap_type (code)) {
 
149
                case RB_DAAP_TYPE_BYTE:
 
150
                case RB_DAAP_TYPE_SIGNED_INT:
 
151
                        return G_TYPE_CHAR;
 
152
                case RB_DAAP_TYPE_SHORT:
 
153
                case RB_DAAP_TYPE_INT:
 
154
                case RB_DAAP_TYPE_DATE:
 
155
                        return G_TYPE_INT;
 
156
                case RB_DAAP_TYPE_INT64:
 
157
                        return G_TYPE_INT64;
 
158
                case RB_DAAP_TYPE_VERSION:
 
159
                        return G_TYPE_DOUBLE;
 
160
                case RB_DAAP_TYPE_STRING:
 
161
                        return G_TYPE_STRING;
 
162
                case RB_DAAP_TYPE_CONTAINER:
 
163
                default:
 
164
                        return G_TYPE_NONE;
 
165
        }
 
166
}
 
167
 
 
168
GNode * 
 
169
rb_daap_structure_add (GNode *parent, 
 
170
                       RBDAAPContentCode cc, 
 
171
                       ...)
 
172
{
 
173
        RBDAAPType rb_daap_type;
 
174
        GType gtype;
 
175
        RBDAAPItem *item;
 
176
        va_list list;
 
177
        GNode *node;
 
178
        gchar *error = NULL;
 
179
        
 
180
        va_start (list, cc);
 
181
 
 
182
        rb_daap_type = rb_daap_content_code_rb_daap_type (cc);
 
183
        gtype = rb_daap_content_code_gtype (cc);
 
184
 
 
185
        item = g_new0(RBDAAPItem, 1);
 
186
        item->content_code = cc;
 
187
        
 
188
        if (gtype != G_TYPE_NONE) {
 
189
                g_value_init (&(item->content), gtype);
 
190
        }
 
191
 
 
192
        if (rb_daap_type != RB_DAAP_TYPE_STRING && rb_daap_type != RB_DAAP_TYPE_CONTAINER) {
 
193
                G_VALUE_COLLECT (&(item->content), list, G_VALUE_NOCOPY_CONTENTS, &error);
 
194
                if (error) {
 
195
                        g_warning (error);
 
196
                        g_free (error);
 
197
                }
 
198
        }
 
199
 
 
200
        switch (rb_daap_type) {
 
201
                case RB_DAAP_TYPE_BYTE: 
 
202
                case RB_DAAP_TYPE_SIGNED_INT:
 
203
                        item->size = 1;
 
204
                        break;
 
205
                case RB_DAAP_TYPE_SHORT: 
 
206
                        item->size = 2;
 
207
                        break;
 
208
                case RB_DAAP_TYPE_DATE:
 
209
                case RB_DAAP_TYPE_INT:
 
210
                case RB_DAAP_TYPE_VERSION:
 
211
                        item->size = 4;
 
212
                        break;
 
213
                case RB_DAAP_TYPE_INT64: 
 
214
                        item->size = 8;
 
215
                        break;
 
216
                case RB_DAAP_TYPE_STRING: {
 
217
                        gchar *s = va_arg (list, gchar *);
 
218
 
 
219
                        g_value_set_string (&(item->content), s);
 
220
 
 
221
                        /* we dont use G_VALUE_COLLECT for this because we also
 
222
                         * need the length */
 
223
                        item->size = strlen (s);
 
224
                        break;
 
225
                }
 
226
                case RB_DAAP_TYPE_CONTAINER:
 
227
                default:
 
228
                        break;
 
229
        }
 
230
        
 
231
        node = g_node_new (item);
 
232
        
 
233
        if (parent) {
 
234
                g_node_append (parent, node);
 
235
 
 
236
                while (parent) {
 
237
                        RBDAAPItem *parent_item = parent->data;
 
238
 
 
239
                        parent_item->size += (4 + 4 + item->size);
 
240
 
 
241
                        parent = parent->parent;
 
242
                }
 
243
        }
 
244
 
 
245
        return node;
 
246
}
 
247
 
 
248
static gboolean 
 
249
rb_daap_structure_node_serialize (GNode *node, 
 
250
                                  GByteArray *array)
 
251
{
 
252
        RBDAAPItem *item = node->data;
 
253
        RBDAAPType rb_daap_type;
 
254
        guint32 size = GINT32_TO_BE (item->size);
 
255
 
 
256
        g_byte_array_append (array, (const guint8 *)rb_daap_content_code_string (item->content_code), 4);
 
257
        g_byte_array_append (array, (const guint8 *)&size, 4);
 
258
        
 
259
        rb_daap_type = rb_daap_content_code_rb_daap_type (item->content_code);
 
260
 
 
261
        switch (rb_daap_type) {
 
262
                case RB_DAAP_TYPE_BYTE: 
 
263
                case RB_DAAP_TYPE_SIGNED_INT: {
 
264
                        gchar c = g_value_get_char (&(item->content));
 
265
                        
 
266
                        g_byte_array_append (array, (const guint8 *)&c, 1);
 
267
                        
 
268
                        break;
 
269
                }
 
270
                case RB_DAAP_TYPE_SHORT: {
 
271
                        gint32 i = g_value_get_int (&(item->content));
 
272
                        gint16 s = GINT16_TO_BE ((gint16) i);
 
273
                        
 
274
                        g_byte_array_append (array, (const guint8 *)&s, 2);
 
275
 
 
276
                        break;
 
277
                }
 
278
                case RB_DAAP_TYPE_DATE: 
 
279
                case RB_DAAP_TYPE_INT: {
 
280
                        gint32 i = g_value_get_int (&(item->content));
 
281
                        gint32 s = GINT32_TO_BE (i);
 
282
 
 
283
                        g_byte_array_append (array, (const guint8 *)&s, 4);
 
284
                        
 
285
                        break;
 
286
                }
 
287
                case RB_DAAP_TYPE_VERSION: {
 
288
                        gdouble v = g_value_get_double (&(item->content));
 
289
                        gint16 major;
 
290
                        gint8 minor;
 
291
                        gint8 patch = 0;
 
292
 
 
293
                        major = (gint16)v;
 
294
                        minor = (gint8)(v - ((gdouble)major));
 
295
 
 
296
                        major = GINT16_TO_BE (major);
 
297
 
 
298
                        g_byte_array_append (array, (const guint8 *)&major, 2);
 
299
                        g_byte_array_append (array, (const guint8 *)&minor, 1);
 
300
                        g_byte_array_append (array, (const guint8 *)&patch, 1);
 
301
                        
 
302
                        break;
 
303
                }               
 
304
                case RB_DAAP_TYPE_INT64: {
 
305
                        gint64 i = g_value_get_int64 (&(item->content));
 
306
                        gint64 s = GINT64_TO_BE (i);
 
307
 
 
308
                        g_byte_array_append (array, (const guint8 *)&s, 8);
 
309
                        
 
310
                        break;
 
311
                }
 
312
                case RB_DAAP_TYPE_STRING: {
 
313
                        const gchar *s = g_value_get_string (&(item->content));
 
314
 
 
315
                        g_byte_array_append (array, (const guint8 *)s, strlen (s));
 
316
                        
 
317
                        break;
 
318
                }
 
319
                case RB_DAAP_TYPE_CONTAINER:
 
320
                default:
 
321
                        break;
 
322
        }
 
323
 
 
324
        return FALSE;
 
325
}
 
326
        
 
327
gchar * 
 
328
rb_daap_structure_serialize (GNode *structure, 
 
329
                             guint *length)
 
330
{
 
331
        GByteArray *array;
 
332
        gchar *data;
 
333
 
 
334
        array = g_byte_array_new ();
 
335
        
 
336
        if (structure) {
 
337
                g_node_traverse (structure, G_PRE_ORDER, G_TRAVERSE_ALL, -1, (GNodeTraverseFunc)rb_daap_structure_node_serialize, array);
 
338
        }
 
339
        
 
340
        data = (gchar *) array->data;
 
341
        *length = array->len;
 
342
        g_byte_array_free (array, FALSE);
 
343
        
 
344
        return data;
 
345
}
 
346
 
 
347
static RBDAAPContentCode 
 
348
rb_daap_buffer_read_content_code (const gchar *buf)
 
349
{
 
350
        gint32 c = MAKE_CONTENT_CODE (buf[0], buf[1], buf[2], buf[3]);
 
351
        guint i;
 
352
 
 
353
        for (i = 0; i < G_N_ELEMENTS (cc_defs); i++) {
 
354
                if (cc_defs[i].int_code == c) {
 
355
                        return cc_defs[i].code;
 
356
                }
 
357
        }
 
358
 
 
359
        return RB_DAAP_CC_INVALID;
 
360
}
 
361
 
 
362
#define rb_daap_buffer_read_int8(b)     GST_READ_UINT8 (b)
 
363
#define rb_daap_buffer_read_int16(b)    (gint16) GST_READ_UINT16_BE (b)
 
364
#define rb_daap_buffer_read_int32(b)    (gint32) GST_READ_UINT32_BE (b)
 
365
#define rb_daap_buffer_read_int64(b)    (gint64) GST_READ_UINT64_BE (b)
 
366
 
 
367
static gchar *
 
368
rb_daap_buffer_read_string (const gchar *buf, gssize size)
 
369
{
 
370
        if (g_utf8_validate (buf, size, NULL) == TRUE) {
 
371
                return g_strndup (buf, size);
 
372
        } else {
 
373
                return g_strdup ("");
 
374
        }
 
375
}
 
376
 
 
377
//#define PARSE_DEBUG
 
378
#define PARSE_DEBUG_FILE "daapbuffer"
 
379
 
 
380
#ifdef PARSE_DEBUG
 
381
#include <unistd.h>
 
382
#include <sys/stat.h>
 
383
#include <fcntl.h>
 
384
#endif
 
385
 
 
386
static void 
 
387
rb_daap_structure_parse_container_buffer (GNode *parent, 
 
388
                                          const guchar *buf, 
 
389
                                          gint buf_length)
 
390
{
 
391
        gint l = 0;
 
392
 
 
393
        while (l < buf_length) {
 
394
                RBDAAPContentCode cc;
 
395
                gint codesize = 0;
 
396
                RBDAAPItem *item = NULL;
 
397
                GNode *node = NULL;
 
398
                GType gtype;
 
399
                
 
400
#ifdef PARSE_DEBUG
 
401
                g_print ("l is %d and buf_length is %d\n", l, buf_length);
 
402
#endif          
 
403
 
 
404
                /* we need at least 8 bytes, 4 of content_code and 4 of size */
 
405
                if (buf_length - l < 8) {
 
406
#ifdef PARSE_DEBUG
 
407
                        g_print ("Malformed response recieved\n");
 
408
#endif
 
409
                        return;
 
410
                }
 
411
                
 
412
                cc = rb_daap_buffer_read_content_code ((const gchar*)&(buf[l]));
 
413
                if (cc == RB_DAAP_CC_INVALID) {
 
414
#ifdef PARSE_DEBUG
 
415
                        g_print ("Invalid content_code recieved\n");
 
416
#endif
 
417
                        return;
 
418
                }
 
419
                l += 4;
 
420
 
 
421
                codesize = rb_daap_buffer_read_int32(&(buf[l]));
 
422
                /* CCCCSIZECONTENT
 
423
                 * if the buffer length (minus 8 for the content code & size)
 
424
                 * is smaller than the read codesize (ie, someone sent us
 
425
                 * a codesize that is larger than the remaining data)
 
426
                 * then get out before we start processing it
 
427
                 */
 
428
                if (codesize > buf_length - l - 4 || codesize < 0) {
 
429
#ifdef PARSE_DEBUG
 
430
                        g_print ("Invalid codesize %d recieved in buf_length %d\n", codesize, buf_length);
 
431
#endif
 
432
                        return;
 
433
                }
 
434
                l += 4;
 
435
 
 
436
#ifdef PARSE_DEBUG
 
437
                g_print ("content_code = %d, codesize is %d, l is %d\n", cc, codesize, l);
 
438
#endif
 
439
                
 
440
                item = g_new0 (RBDAAPItem, 1);
 
441
                item->content_code = cc;
 
442
                node = g_node_new (item);
 
443
                g_node_append (parent, node);
 
444
                
 
445
                gtype = rb_daap_content_code_gtype (item->content_code);
 
446
 
 
447
                if (gtype != G_TYPE_NONE) {
 
448
                        g_value_init (&(item->content), gtype);
 
449
                }
 
450
                
 
451
#ifdef PARSE_DEBUG 
 
452
                {
 
453
                        guint i;
 
454
 
 
455
                        for (i = 2; i < g_node_depth (node); i++) {
 
456
                                g_print ("\t");
 
457
                        }
 
458
                }
 
459
#endif
 
460
                
 
461
// FIXME USE THE G_TYPE CONVERTOR FUNCTION rb_daap_type_to_gtype
 
462
                switch (rb_daap_content_code_rb_daap_type (item->content_code)) {
 
463
                        case RB_DAAP_TYPE_SIGNED_INT:
 
464
                        case RB_DAAP_TYPE_BYTE: {
 
465
                                gchar c = 0;
 
466
                                
 
467
                                if (codesize == 1) {
 
468
                                        c = (gchar) rb_daap_buffer_read_int8(&(buf[l]));
 
469
                                }
 
470
                                
 
471
                                g_value_set_char (&(item->content), c);
 
472
#ifdef PARSE_DEBUG
 
473
                                g_print ("Code: %s, content (%d): \"%c\"\n", rb_daap_content_code_string (item->content_code), codesize, (gchar)c);
 
474
#endif
 
475
 
 
476
                                break;
 
477
                        }
 
478
                        case RB_DAAP_TYPE_SHORT: {
 
479
                                gint16 s = 0;
 
480
 
 
481
                                if (codesize == 2) {
 
482
                                        s = rb_daap_buffer_read_int16(&(buf[l]));
 
483
                                }
 
484
 
 
485
                                g_value_set_int (&(item->content),(gint32)s);
 
486
#ifdef PARSE_DEBUG
 
487
                                g_print ("Code: %s, content (%d): %hi\n", rb_daap_content_code_string (item->content_code), codesize, s);
 
488
#endif
 
489
 
 
490
                                break;
 
491
                        }
 
492
                        case RB_DAAP_TYPE_DATE:
 
493
                        case RB_DAAP_TYPE_INT: {
 
494
                                gint32 i = 0;
 
495
 
 
496
                                if (codesize == 4) {
 
497
                                        i = rb_daap_buffer_read_int32(&(buf[l]));
 
498
                                }
 
499
                                
 
500
                                g_value_set_int (&(item->content), i);
 
501
#ifdef PARSE_DEBUG
 
502
                                g_print ("Code: %s, content (%d): %d\n", rb_daap_content_code_string (item->content_code), codesize, i);
 
503
#endif
 
504
                                break;
 
505
                        }
 
506
                        case RB_DAAP_TYPE_INT64: {
 
507
                                gint64 i = 0;
 
508
                
 
509
                                if (codesize == 8) {
 
510
                                        i = rb_daap_buffer_read_int16(&(buf[l]));
 
511
                                }
 
512
                                
 
513
                                g_value_set_int64 (&(item->content), i);
 
514
#ifdef PARSE_DEBUG
 
515
                                g_print ("Code: %s, content (%d): %"G_GINT64_FORMAT"\n", rb_daap_content_code_string (item->content_code), codesize, i);
 
516
#endif
 
517
 
 
518
                                break;
 
519
                        }
 
520
                        case RB_DAAP_TYPE_STRING: {
 
521
                                gchar *s = rb_daap_buffer_read_string ((const gchar*)&(buf[l]), codesize);
 
522
 
 
523
                                g_value_take_string (&(item->content), s);
 
524
#ifdef PARSE_DEBUG
 
525
                                g_print ("Code: %s, content (%d): \"%s\"\n", rb_daap_content_code_string (item->content_code), codesize, s);
 
526
#endif
 
527
 
 
528
                                break;
 
529
                        }
 
530
                        case RB_DAAP_TYPE_VERSION: {
 
531
                                gint16 major = 0;
 
532
                                gint16 minor = 0;
 
533
                                gint16 patch = 0;
 
534
                                gdouble v = 0;
 
535
 
 
536
                                if (codesize == 4) {
 
537
                                        major = rb_daap_buffer_read_int16(&(buf[l]));
 
538
                                        minor = rb_daap_buffer_read_int8(&(buf[l]) + 2);
 
539
                                        patch = rb_daap_buffer_read_int8(&(buf[l]) + 3);
 
540
                                }
 
541
 
 
542
                                v = (gdouble)major;
 
543
                                v += (gdouble)(minor * 0.1);
 
544
                                v += (gdouble)(patch * 0.01);
 
545
                                
 
546
                                g_value_set_double (&(item->content), v);
 
547
#ifdef PARSE_DEBUG
 
548
                                g_print ("Code: %s, content: %f\n", rb_daap_content_code_string (item->content_code), v);
 
549
#endif
 
550
 
 
551
                                break;
 
552
                        }
 
553
                        case RB_DAAP_TYPE_CONTAINER: {
 
554
#ifdef PARSE_DEBUG
 
555
                                g_print ("Code: %s, container\n", rb_daap_content_code_string (item->content_code));
 
556
#endif
 
557
                                rb_daap_structure_parse_container_buffer (node,&(buf[l]), codesize);
 
558
                                break;
 
559
                        }
 
560
                }
 
561
 
 
562
                l += codesize;
 
563
        }
 
564
 
 
565
        return;
 
566
}
 
567
 
 
568
GNode * 
 
569
rb_daap_structure_parse (const gchar *buf, 
 
570
                         gint buf_length)
 
571
{
 
572
        GNode *root = NULL;
 
573
        GNode *child = NULL;
 
574
 
 
575
#ifdef PARSE_DEBUG
 
576
        {
 
577
                int fd;
 
578
 
 
579
                fd = open (PARSE_DEBUG_FILE, O_WRONLY | O_CREAT);
 
580
                write (fd, (const void *)buf, (size_t)buf_length);
 
581
                close (fd);
 
582
        }
 
583
#endif
 
584
        
 
585
        root = g_node_new (NULL);
 
586
 
 
587
        rb_daap_structure_parse_container_buffer (root, (guchar *)buf, buf_length);
 
588
 
 
589
        child = root->children;
 
590
        if (child) {
 
591
                g_node_unlink (child);
 
592
        }
 
593
        g_node_destroy (root);
 
594
        
 
595
        return child;
 
596
}
 
597
 
 
598
struct NodeFinder {
 
599
        RBDAAPContentCode code;
 
600
        GNode *node;
 
601
};
 
602
 
 
603
static gboolean 
 
604
gnode_find_node (GNode *node, 
 
605
                 gpointer data)
 
606
{
 
607
        struct NodeFinder *finder = (struct NodeFinder *)data;
 
608
        RBDAAPItem *item = node->data;
 
609
 
 
610
        if (item->content_code == finder->code) {
 
611
                finder->node = node;
 
612
                return TRUE;
 
613
        }
 
614
 
 
615
        return FALSE;
 
616
}
 
617
 
 
618
RBDAAPItem * 
 
619
rb_daap_structure_find_item (GNode *structure, 
 
620
                             RBDAAPContentCode code)
 
621
{
 
622
        GNode *node = NULL;
 
623
        
 
624
        node = rb_daap_structure_find_node (structure, code);
 
625
 
 
626
        if (node) {
 
627
                return node->data;
 
628
        }
 
629
 
 
630
        return NULL;
 
631
}
 
632
 
 
633
GNode * 
 
634
rb_daap_structure_find_node (GNode *structure, 
 
635
                             RBDAAPContentCode code)
 
636
{
 
637
        struct NodeFinder *finder;
 
638
        GNode *node = NULL;
 
639
 
 
640
        finder = g_new0(struct NodeFinder,1);
 
641
        finder->code = code;
 
642
 
 
643
        g_node_traverse (structure, G_IN_ORDER, G_TRAVERSE_ALL, -1, gnode_find_node, finder);
 
644
 
 
645
        node = finder->node;
 
646
        g_free (finder);
 
647
        finder = NULL;
 
648
 
 
649
        return node;
 
650
}
 
651
 
 
652
 
 
653
 
 
654
static void
 
655
rb_daap_item_free (RBDAAPItem *item)
 
656
{
 
657
        if (rb_daap_content_code_rb_daap_type (item->content_code) != RB_DAAP_TYPE_CONTAINER) {
 
658
                g_value_unset (&(item->content));
 
659
        }
 
660
 
 
661
        g_free (item);
 
662
}
 
663
 
 
664
static gboolean
 
665
gnode_free_rb_daap_item (GNode *node,
 
666
                         gpointer data)
 
667
{
 
668
        rb_daap_item_free ((RBDAAPItem *)node->data);
 
669
 
 
670
        return FALSE;
 
671
}
 
672
 
 
673
void 
 
674
rb_daap_structure_destroy (GNode *structure)
 
675
{
 
676
        if (structure) {
 
677
                g_node_traverse (structure, G_IN_ORDER, G_TRAVERSE_ALL, -1, gnode_free_rb_daap_item, NULL);
 
678
 
 
679
                g_node_destroy (structure);
 
680
 
 
681
                structure = NULL;
 
682
        }
 
683
}
 
684
 
 
685
const RBDAAPContentCodeDefinition *
 
686
rb_daap_content_codes (guint *number)
 
687
{
 
688
        *number = G_N_ELEMENTS (cc_defs);
 
689
 
 
690
        return cc_defs;
 
691
}
 
692
 
 
693
gint32 
 
694
rb_daap_content_code_string_as_int32 (const gchar *str)
 
695
{
 
696
        union {
 
697
                gint32 i;
 
698
                gchar str[4];
 
699
        } u;
 
700
 
 
701
        strncpy (u.str, str, 4);
 
702
 
 
703
        return u.i;
 
704
}
 
705
 
 
706
static gboolean 
 
707
print_rb_daap_item (GNode *node, 
 
708
                    gpointer data)
 
709
{
 
710
        RBDAAPItem *item;
 
711
        const gchar *name;
 
712
        gchar *value;
 
713
        gint i;
 
714
 
 
715
        for (i = 1; i < g_node_depth (node); i++) {
 
716
                g_print ("\t");
 
717
        }
 
718
 
 
719
        item = node->data;
 
720
 
 
721
        name = rb_daap_content_code_name (item->content_code);
 
722
 
 
723
        if (G_IS_VALUE (&(item->content))) {
 
724
                value = g_strdup_value_contents (&(item->content));
 
725
        } else {
 
726
                value = g_strdup ("");
 
727
        }
 
728
 
 
729
        g_print ("%d, %s = %s (%d)\n", g_node_depth (node), name, value, item->size);
 
730
        g_free (value);
 
731
 
 
732
        return FALSE;
 
733
}
 
734
 
 
735
void
 
736
rb_daap_structure_print (GNode *structure)
 
737
{
 
738
        if (structure) {
 
739
                g_node_traverse (structure, G_PRE_ORDER, G_TRAVERSE_ALL, -1, (GNodeTraverseFunc)print_rb_daap_item, NULL);
 
740
        }
 
741
}