1 /* Copyright (C) 2000-2015 Lavtech.com corp. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2 of the License, or
6 (at your option) any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17
18 #include "udm_config.h"
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/types.h>
24
25 #include "udm_common.h"
26 #include "udm_utils.h"
27 #include "udm_id3.h"
28 #include "udm_vars.h"
29 #include "udm_textlist.h"
30 #include "udm_http.h"
31
32
33 static udm_rc_t
add_var(UDM_DOCUMENT * Doc,const char * name,size_t namelen,const char * val,size_t vallen)34 add_var(UDM_DOCUMENT *Doc,
35 const char *name, size_t namelen,
36 const char *val, size_t vallen)
37 {
38 const UDM_VAR *Sec;
39 if ((Sec= UdmVarListFind(&Doc->Sections, name)))
40 {
41 UDM_CONST_TEXTITEM Item;
42 UDM_TEXT_PARAM TextParam;
43 while (vallen && val[vallen - 1] == ' ')
44 {
45 vallen--;
46 }
47 bzero((void*)&Item, sizeof(Item));
48 UdmConstStrSet(&Item.text, val, vallen);
49 UdmConstStrSet(&Item.section_name, name, namelen);
50 UdmTextParamInit(&TextParam, UDM_TEXTLIST_FLAG_NONE, UdmVarSecno(Sec));
51 UdmTextListAddConst(&Doc->TextList, &Item, &TextParam);
52 }
53 return UDM_OK;
54 }
55
56
57 static udm_rc_t
get_tag(UDM_DOCUMENT * Doc,const UDM_CONST_STR * content)58 get_tag(UDM_DOCUMENT *Doc, const UDM_CONST_STR *content)
59 {
60 const char *tag= content->str + content->length - 128;
61 UDM_ASSERT(content->length >= 128);
62 add_var(Doc, UDM_CSTR_WITH_LEN("MP3.Song"), tag + 3, 30);
63 add_var(Doc, UDM_CSTR_WITH_LEN("MP3.Album"), tag + 63, 30);
64 add_var(Doc, UDM_CSTR_WITH_LEN("MP3.Artist"), tag + 33, 30);
65 add_var(Doc, UDM_CSTR_WITH_LEN("MP3.Year"), tag + 93, 4);
66 return UDM_OK;
67 }
68
69 /*
70 id3 header v2.3.0 http://www.id3.org/
71 ID3 3
72 version 1+1
73 flag 1
74 size 4
75 */
76
77 static udm_rc_t
get_id3(UDM_DOCUMENT * Doc,const UDM_CONST_STR * cont)78 get_id3(UDM_DOCUMENT *Doc, const UDM_CONST_STR *cont)
79 {
80 const char *ch, *end;
81 UDM_CONST_STR art, song, alb;
82
83 UDM_ASSERT(cont->length >= 30);
84
85 UdmConstStrSet(&art, "", 0);
86 UdmConstStrSet(&song, "", 0);
87 UdmConstStrSet(&alb, "", 0);
88
89 ch= cont->str;
90 end= cont->str + cont->length;
91
92 if (*(ch + 6) == 'b')
93 {
94 /*
95 extened header:
96 size 4
97 flag 2
98 size of pagging 4
99 */
100 ch+= 20;
101 }
102 else
103 {
104 ch+= 10;
105 }
106
107 for ( ; ch + 10 < end; )
108 {
109 /*
110 frame header:
111 frame id 4
112 size 4
113 flags 2
114 */
115 size_t frame_size= (unsigned char) ch[7] + 256 * ((unsigned char) ch[6]);
116 /*
117 printf("frame_size=%d ch=%.*s fr='%.*s'\n", (int) frame_size,
118 4, ch, frame_size - 1, ch+11);
119 */
120 if (frame_size == 0 || ch + frame_size > end)
121 break;
122
123 if (!strncmp(ch , "TPE1", 4))
124 {
125 UdmConstStrSet(&art, ch + 11, frame_size - 1);
126 }
127 else if(!strncmp(ch , "TALB", 4))
128 {
129 UdmConstStrSet(&alb, ch + 11, frame_size - 1);
130 }
131 else if(!strncmp(ch, "TIT2", 4))
132 {
133 UdmConstStrSet(&song, ch + 11, frame_size - 1);
134 }
135 /* TODO34: more ID3 tags */
136 ch+= frame_size + 10;
137 }
138
139 add_var(Doc, UDM_CSTR_WITH_LEN("MP3.Song"), song.str, song.length);
140 add_var(Doc, UDM_CSTR_WITH_LEN("MP3.Album"), alb.str, alb.length);
141 add_var(Doc, UDM_CSTR_WITH_LEN("MP3.Artist"), art.str, art.length);
142
143 return UDM_OK;
144 }
145
146
147 udm_mp3type_t
UdmMP3Type(const UDM_DOCUMENT * Doc)148 UdmMP3Type(const UDM_DOCUMENT *Doc)
149 {
150 int hd;
151 UDM_CONST_STR content;
152 if (UdmHTTPBufContentToConstStr(&Doc->Buf, &content) || content.length < 4)
153 return UDM_MP3_UNKNOWN;
154
155 hd= ((unsigned char)(content.str[0])+
156 256 * (unsigned char)(content.str[1])) & 0xf0ff;
157
158 if (hd == 0xf0ff)
159 return UDM_MP3_TAG;
160
161 if (!memcmp(content.str, "RIFF",4))
162 return UDM_MP3_RIFF;
163
164 if (!memcmp(content.str, "ID3", 3))
165 return UDM_MP3_ID3;
166
167 return UDM_MP3_UNKNOWN;
168 }
169
170
171 udm_rc_t
UdmMP3Parse(UDM_AGENT * A,UDM_DOCUMENT * Doc)172 UdmMP3Parse(UDM_AGENT *A, UDM_DOCUMENT *Doc)
173 {
174 UDM_CONST_STR content;
175 if (UdmHTTPBufContentToConstStr(&Doc->Buf, &content) || content.length < 128)
176 return UDM_ERROR;
177
178 if (!memcmp(content.str, "ID3", 3))
179 get_id3(Doc, &content);
180
181 if (!memcmp(content.str + content.length - 128, "TAG", 3))
182 get_tag(Doc, &content);
183
184 return UDM_OK;
185 }
186