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