/* Copyright (C) 2000-2015 Lavtech.com corp. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "udm_config.h" #include #include #include #include #include "udm_common.h" #include "udm_utils.h" #include "udm_id3.h" #include "udm_vars.h" #include "udm_textlist.h" #include "udm_http.h" static udm_rc_t add_var(UDM_DOCUMENT *Doc, const char *name, size_t namelen, const char *val, size_t vallen) { const UDM_VAR *Sec; if ((Sec= UdmVarListFind(&Doc->Sections, name))) { UDM_CONST_TEXTITEM Item; UDM_TEXT_PARAM TextParam; while (vallen && val[vallen - 1] == ' ') { vallen--; } bzero((void*)&Item, sizeof(Item)); UdmConstStrSet(&Item.text, val, vallen); UdmConstStrSet(&Item.section_name, name, namelen); UdmTextParamInit(&TextParam, UDM_TEXTLIST_FLAG_NONE, UdmVarSecno(Sec)); UdmTextListAddConst(&Doc->TextList, &Item, &TextParam); } return UDM_OK; } static udm_rc_t get_tag(UDM_DOCUMENT *Doc, const UDM_CONST_STR *content) { const char *tag= content->str + content->length - 128; UDM_ASSERT(content->length >= 128); add_var(Doc, UDM_CSTR_WITH_LEN("MP3.Song"), tag + 3, 30); add_var(Doc, UDM_CSTR_WITH_LEN("MP3.Album"), tag + 63, 30); add_var(Doc, UDM_CSTR_WITH_LEN("MP3.Artist"), tag + 33, 30); add_var(Doc, UDM_CSTR_WITH_LEN("MP3.Year"), tag + 93, 4); return UDM_OK; } /* id3 header v2.3.0 http://www.id3.org/ ID3 3 version 1+1 flag 1 size 4 */ static udm_rc_t get_id3(UDM_DOCUMENT *Doc, const UDM_CONST_STR *cont) { const char *ch, *end; UDM_CONST_STR art, song, alb; UDM_ASSERT(cont->length >= 30); UdmConstStrSet(&art, "", 0); UdmConstStrSet(&song, "", 0); UdmConstStrSet(&alb, "", 0); ch= cont->str; end= cont->str + cont->length; if (*(ch + 6) == 'b') { /* extened header: size 4 flag 2 size of pagging 4 */ ch+= 20; } else { ch+= 10; } for ( ; ch + 10 < end; ) { /* frame header: frame id 4 size 4 flags 2 */ size_t frame_size= (unsigned char) ch[7] + 256 * ((unsigned char) ch[6]); /* printf("frame_size=%d ch=%.*s fr='%.*s'\n", (int) frame_size, 4, ch, frame_size - 1, ch+11); */ if (frame_size == 0 || ch + frame_size > end) break; if (!strncmp(ch , "TPE1", 4)) { UdmConstStrSet(&art, ch + 11, frame_size - 1); } else if(!strncmp(ch , "TALB", 4)) { UdmConstStrSet(&alb, ch + 11, frame_size - 1); } else if(!strncmp(ch, "TIT2", 4)) { UdmConstStrSet(&song, ch + 11, frame_size - 1); } /* TODO34: more ID3 tags */ ch+= frame_size + 10; } add_var(Doc, UDM_CSTR_WITH_LEN("MP3.Song"), song.str, song.length); add_var(Doc, UDM_CSTR_WITH_LEN("MP3.Album"), alb.str, alb.length); add_var(Doc, UDM_CSTR_WITH_LEN("MP3.Artist"), art.str, art.length); return UDM_OK; } udm_mp3type_t UdmMP3Type(const UDM_DOCUMENT *Doc) { int hd; UDM_CONST_STR content; if (UdmHTTPBufContentToConstStr(&Doc->Buf, &content) || content.length < 4) return UDM_MP3_UNKNOWN; hd= ((unsigned char)(content.str[0])+ 256 * (unsigned char)(content.str[1])) & 0xf0ff; if (hd == 0xf0ff) return UDM_MP3_TAG; if (!memcmp(content.str, "RIFF",4)) return UDM_MP3_RIFF; if (!memcmp(content.str, "ID3", 3)) return UDM_MP3_ID3; return UDM_MP3_UNKNOWN; } udm_rc_t UdmMP3Parse(UDM_AGENT *A, UDM_DOCUMENT *Doc) { UDM_CONST_STR content; if (UdmHTTPBufContentToConstStr(&Doc->Buf, &content) || content.length < 128) return UDM_ERROR; if (!memcmp(content.str, "ID3", 3)) get_id3(Doc, &content); if (!memcmp(content.str + content.length - 128, "TAG", 3)) get_tag(Doc, &content); return UDM_OK; }