CVS: main asxparser.c,NONE,1.1 asxparser.h,NONE,1.1 playtree.c,NONE,1.1 playtree.h,NONE,1.1 playtreeparser.c,NONE,1.1 Makefile,1.135,1.136
Update of /cvsroot/mplayer/main In directory mplayer:/var/tmp.root/cvs-serv2664 Modified Files: Makefile Added Files: asxparser.c asxparser.h playtree.c playtree.h playtreeparser.c Log Message: tree-based playlist parser code by Alban Bedel <albeu@free.fr> --- NEW FILE --- #include <stdlib.h> #include <stdio.h> #include <stdarg.h> #include <string.h> #include "asxparser.h" #include "mp_msg.h" ////// List utils typedef void (*ASX_FreeFunc)(void* arg); void asx_list_add(void* list_ptr,void* entry){ void** list = *(void***)list_ptr; int c = 0; if(list != NULL) for( ; list[c] != NULL; c++) ; list = (void*)realloc(list,sizeof(void*)*(c+2)); list[c] = entry; list[c+1] = NULL; *(void***)list_ptr = list; } void asx_list_remove(void* list_ptr,void* entry,ASX_FreeFunc free_func) { void** list = *(void***)list_ptr; int c,e = -1; if(list == NULL) return; for(c = 0 ; list[c] != NULL; c++){ if(list[c] == entry) e = c; } if(e == -1) return; // Not found if(free_func != NULL) free_func(list[e]); if(c == 1) { // Only one entry, we drop all free(list); *(void**)list_ptr = NULL; return; } if(c > e) // If c==e the memmove is not needed memmove(list+e,list+e+1,(c-e)*sizeof(void*)); list = (void*)realloc(list,(c-1)*sizeof(void*)); list[c-1] = NULL; *(void***)list_ptr = list; } void asx_list_free(void* list_ptr,ASX_FreeFunc free_func) { void** ptr = *(void***)list_ptr; if(ptr == NULL) return; if(free_func != NULL) { for( ; *ptr != NULL ; ptr++) free_func(*ptr); } free(*(void**)list_ptr); *(void**)list_ptr = NULL; } /////// Attribs utils static char* asx_get_attrib(char* attrib,char** attribs) { char** ptr; if(attrib == NULL || attribs == NULL) return NULL; for(ptr = attribs; ptr[0] != NULL; ptr += 2){ if(strcasecmp(ptr[0],attrib) == 0) return strdup(ptr[1]); } return NULL; } static int asx_attrib_to_enum(char* val,char** valid_vals) { char** ptr; int r = 0; if(valid_vals == NULL || val == NULL) return -2; for(ptr = valid_vals ; ptr[0] != NULL ; ptr++) { if(strcasecmp(val,ptr[0]) == 0) return r; r++; } return -1; } static void asx_warning_attrib_invalid(ASX_Parser_t* parser, char* elem, char* attrib, char** valid_vals,char* val) { char *str,*vals,**ptr; int len; if(valid_vals == NULL || valid_vals[0] == NULL) return; len = strlen(valid_vals[0]) + 1; for(ptr = valid_vals+1 ; ptr[0] != NULL; ptr++) { len += strlen(ptr[0]); len += ((ptr[1] == NULL) ? 4 : 2); } str = vals = (char*)malloc(len); vals += sprintf(vals,"%s",valid_vals[0]); for(ptr = valid_vals + 1 ; ptr[0] != NULL ; ptr++) { if(ptr[1] == NULL) vals += sprintf(vals," or %s",ptr[0]); else vals += sprintf(vals,", %s",ptr[0]); } mp_msg(MSGT_PLAYTREE,MSGL_ERR,"at line %d : attribute %s of element %s is invalid (%s). Valid values are %s", parser->line,attrib,elem,val,str); free(str); } static int asx_get_yes_no_attrib(ASX_Parser_t* parser, char* element, char* attrib,char** attribs,int def) { char* val = asx_get_attrib(attrib,attribs); char* valids[] = { "NO", "YES", NULL }; int r; if(val == NULL) return def; r = asx_attrib_to_enum(val,valids); if(r < 0) { asx_warning_attrib_invalid(parser,element,attrib,valids,val); r = def; } free(val); return r; } #define asx_free_attribs(a) asx_list_free((void***)&a,free) #define asx_warning_attrib_required(p,e,a) mp_msg(MSGT_PLAYTREE,MSGL_WARN,"At line %d : element %s don't have the required attribute %s",p->line,e,a) #define asx_warning_body_parse_error(p,e) mp_msg(MSGT_PLAYTREE,MSGL_WARN,"At line %d : error while parsing %s body",p->line,e) ASX_Parser_t* asx_parser_new(void) { ASX_Parser_t* parser = calloc(1,sizeof(ASX_Parser_t)); return parser; } void asx_parser_free(ASX_Parser_t* parser) { if(!parser) return; if(parser->ret_stack) free(parser->ret_stack); free(parser); } #define LETTER "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" #define SPACE " \n\t\r" static int asx_parse_attribs(ASX_Parser_t* parser,char* buffer,char*** _attribs) { char *ptr1, *ptr2, *ptr3; int n_attrib = 0; char **attribs = NULL; char *attrib, *val; ptr1 = buffer; while(1) { for( ; strchr(SPACE,*ptr1) != NULL; ptr1++) { // Skip space if(*ptr1 == '\0') break; } ptr3 = strchr(ptr1,'='); if(ptr3 == NULL) break; for(ptr2 = ptr3-1; strchr(SPACE,*ptr2) != NULL; ptr2--) { if (ptr2 == ptr1) { mp_msg(MSGT_PLAYTREE,MSGL_ERR,"At line %d : this should never append, back to attribute begin while skipping end space",parser->line); break; } } attrib = (char*)malloc(ptr2-ptr1+2); strncpy(attrib,ptr1,ptr2-ptr1+1); attrib[ptr2-ptr1+1] = '\0'; ptr1 = strchr(ptr3,'"'); if(ptr1 == NULL || ptr1[1] == '\0') { mp_msg(MSGT_PLAYTREE,MSGL_WARN,"At line %d : can't find attribute %s value",parser->line,attrib); free(attrib); break; } ptr1++; ptr2 = strchr(ptr1,'"'); if (ptr2 == NULL) { mp_msg(MSGT_PLAYTREE,MSGL_WARN,"At line %d : value of attribute %s isn't finished",parser->line,attrib); free(attrib); break; } val = (char*)malloc(ptr2-ptr1+1); strncpy(val,ptr1,ptr2-ptr1); val[ptr2-ptr1] = '\0'; n_attrib++; attribs = (char**)realloc(attribs,2*n_attrib*sizeof(char*)+1); attribs[n_attrib*2-2] = attrib; attribs[n_attrib*2-1] = val; ptr1 = ptr2+2; } if(n_attrib > 0) attribs[n_attrib*2] = NULL; *_attribs = attribs; return n_attrib; } /* * Return -1 on error, 0 when nothing is found, 1 on sucess */ static int asx_get_element(ASX_Parser_t* parser,char** _buffer, char** _element,char** _body,char*** _attribs) { char *ptr1,*ptr2, *ptr3, *ptr4; char *attribs = NULL; char *element = NULL, *body = NULL, *ret = NULL, *buffer; int n_attrib = 0; int body_line = 0,attrib_line,ret_line; if(_buffer == NULL || _element == NULL || _body == NULL || _attribs == NULL) { mp_msg(MSGT_PLAYTREE,MSGL_ERR,"At line %d : asx_get_element called with invalid value",parser->line); return -1; } *_body = *_element = NULL; *_attribs = NULL; buffer = *_buffer; if(buffer == NULL) return 0; if(parser->ret_stack && /*parser->last_body && */buffer != parser->last_body) { ASX_LineSave_t* ls = parser->ret_stack; int i; for(i = 0 ; i < parser->ret_stack_size ; i++) { if(buffer == ls[i].buffer) { parser->line = ls[i].line; break; } } if( i < parser->ret_stack_size) { i++; if( i < parser->ret_stack_size) memmove(parser->ret_stack,parser->ret_stack+i, (parser->ret_stack_size - i)*sizeof(ASX_LineSave_t)); parser->ret_stack_size -= i; parser->ret_stack = (ASX_LineSave_t*)realloc(parser->ret_stack,parser->ret_stack_size*sizeof(ASX_LineSave_t)); } } ptr1 = buffer; while(1) { for( ; ptr1[0] != '<' ; ptr1++) { if(ptr1[0] == '\0') { ptr1 = NULL; break; } if(ptr1[0] == '\n') parser->line++; } //ptr1 = strchr(ptr1,'<'); if(!ptr1 || ptr1[1] == '\0') return 0; // Nothing found if(strncmp(ptr1,"<!--",4) == 0) { // Comments for( ; strncmp(ptr1,"-->",3) != 0 ; ptr1++) { if(ptr1[0] == '\0') { ptr1 = NULL; break; } if(ptr1[0] == '\n') parser->line++; } //ptr1 = strstr(ptr1,"-->"); if(!ptr1) { mp_msg(MSGT_PLAYTREE,MSGL_ERR,"At line %d : unfinished comment",parser->line); return -1; } } else { break; } } // Is this space skip very useful ?? for(ptr1++; strchr(SPACE,ptr1[0]) != NULL; ptr1++) { // Skip space if(ptr1[0] == '\0') { mp_msg(MSGT_PLAYTREE,MSGL_ERR,"At line %d : EOB reached while parsing element start",parser->line); return -1; } if(ptr1[0] == '\n') parser->line++; } for(ptr2 = ptr1; strchr(LETTER,*ptr2) != NULL;ptr2++) { // Go to end of name if(*ptr2 == '\0'){ mp_msg(MSGT_PLAYTREE,MSGL_ERR,"At line %d : EOB reached while parsing element start",parser->line); return -1; } if(ptr2[0] == '\n') parser->line++; } element = (char*)malloc(ptr2-ptr1+1); strncpy(element,ptr1,ptr2-ptr1); element[ptr2-ptr1] = '\0'; for( ; strchr(SPACE,*ptr2) != NULL; ptr2++) { // Skip space if(ptr2[0] == '\0') { mp_msg(MSGT_PLAYTREE,MSGL_ERR,"At line %d : EOB reached while parsing element start",parser->line); free(element); return -1; } if(ptr2[0] == '\n') parser->line++; } attrib_line = parser->line; for(ptr3 = ptr2; ptr3[0] != '\0'; ptr3++) { // Go to element end if(ptr3[0] == '>' || strncmp(ptr3,"/>",2) == 0) break; if(ptr3[0] == '\n') parser->line++; } if(ptr3[0] == '\0' || ptr3[1] == '\0') { // End of file mp_msg(MSGT_PLAYTREE,MSGL_ERR,"At line %d : EOB reached while parsing element start",parser->line); free(element); return -1; } // Save attribs string if(ptr3-ptr2 > 0) { attribs = (char*)malloc(ptr3-ptr2+1); strncpy(attribs,ptr2,ptr3-ptr2); attribs[ptr3-ptr2] = '\0'; } //bs_line = parser->line; if(ptr3[0] != '/') { // Not Self closed element ptr3++; for( ; strchr(SPACE,*ptr3) != NULL; ptr3++) { // Skip space on body begin if(*ptr3 == '\0') { mp_msg(MSGT_PLAYTREE,MSGL_ERR,"At line %d : EOB reached while parsing %s element body",parser->line,element); free(element); if(attribs) free(attribs); return -1; } if(ptr3[0] == '\n') parser->line++; } ptr4 = ptr3; body_line = parser->line; while(1) { // Find closing element for( ; strncmp(ptr4,"</",2) != 0; ptr4++) { if(ptr4[0] == '\0') { ptr4 = NULL; break; } if(ptr4[0] == '\n') parser->line++; } //ptr4 = strstr(ptr4,"</"); if(ptr4 == NULL || ptr4[2] == '\0') { mp_msg(MSGT_PLAYTREE,MSGL_ERR,"At line %d : EOB reached while parsing %s element body",parser->line,element); free(element); if(attribs) free(attribs); return -1; } if(strncasecmp(element,ptr4+2,strlen(element)) == 0) { // Extract body ret = ptr4+strlen(element)+3; if(ptr4 != ptr3) { ptr4--; for( ; ptr4 != ptr3 && strchr(SPACE,*ptr4) != NULL; ptr4--) ;// Skip space on body end // if(ptr4[0] == '\0') parser->line--; //} ptr4++; body = (char*)malloc(ptr4-ptr3+1); strncpy(body,ptr3,ptr4-ptr3); body[ptr4-ptr3] = '\0'; } break; } else { ptr4 += 2; } } } else { ret = ptr3 + 2; // 2 is for /> } for( ; ret[0] != '\0' && strchr(SPACE,ret[0]) != NULL; ret++) { // Skip space if(ret[0] == '\n') parser->line++; } ret_line = parser->line; if(attribs) { parser->line = attrib_line; n_attrib = asx_parse_attribs(parser,attribs,_attribs); free(attribs); if(n_attrib < 0) { mp_msg(MSGT_PLAYTREE,MSGL_WARN,"At line %d : error while parsing element %s attributes",parser->line,element); free(element); free(body); return -1; } } else *_attribs = NULL; *_element = element; *_body = body; parser->last_body = body; parser->ret_stack_size++; parser->ret_stack = (ASX_LineSave_t*)realloc(parser->ret_stack,parser->ret_stack_size*sizeof(ASX_LineSave_t)); if(parser->ret_stack_size > 1) memmove(parser->ret_stack+1,parser->ret_stack,(parser->ret_stack_size-1)*sizeof(ASX_LineSave_t)); parser->ret_stack[0].buffer = ret; parser->ret_stack[0].line = ret_line; parser->line = body ? body_line : ret_line; *_buffer = ret; return 1; } static void asx_parse_ref(ASX_Parser_t* parser, char** attribs, play_tree_t* pt) { char *href; href = asx_get_attrib("HREF",attribs); if(href == NULL) { asx_warning_attrib_required(parser,"ENTRYREF" ,"HREF" ); return; } play_tree_add_file(pt,href); mp_msg(MSGT_PLAYTREE,MSGL_V,"Adding file %s to element entry\n",href); free(href); } static play_tree_t* asx_parse_entryref(ASX_Parser_t* parser,char* buffer,char** _attribs) { mp_msg(MSGT_PLAYTREE,MSGL_INFO,"Need to implement entryref\n"); return NULL; } static play_tree_t* asx_parse_entry(ASX_Parser_t* parser,char* buffer,char** _attribs) { char *element,*body,**attribs; int r,nref=0; play_tree_t *ref; ref = play_tree_new(); while(buffer && buffer[0] != '\0') { r = asx_get_element(parser,&buffer,&element,&body,&attribs); if(r < 0) { asx_warning_body_parse_error(parser,"ENTRY"); return NULL; } else if (r == 0) { // No more element break; } if(strcasecmp(element,"REF") == 0) { asx_parse_ref(parser,attribs,ref); mp_msg(MSGT_PLAYTREE,MSGL_DBG2,"Adding element %s to entry\n",element); nref++; } else mp_msg(MSGT_PLAYTREE,MSGL_DBG2,"Ignoring element %s\n",element); if(body) free(body); asx_free_attribs(attribs); } if(nref <= 0) { play_tree_free(ref,1); return NULL; } return ref; } static play_tree_t* asx_parse_repeat(ASX_Parser_t* parser,char* buffer,char** _attribs) { char *element,*body,**attribs; play_tree_t *repeat, *list=NULL, *entry; char* count; int r; repeat = play_tree_new(); count = asx_get_attrib("COUNT",_attribs); if(count == NULL) { mp_msg(MSGT_PLAYTREE,MSGL_DBG2,"Setting element repeat loop to infinit\n"); repeat->loop = -1; // Infinit } else { repeat->loop = atoi(count); free(count); if(repeat->loop == 0) repeat->loop = 1; mp_msg(MSGT_PLAYTREE,MSGL_DBG2,"Setting element repeat loop to %d\n",repeat->loop); } while(buffer && buffer[0] != '\0') { r = asx_get_element(parser,&buffer,&element,&body,&attribs); if(r < 0) { asx_warning_body_parse_error(parser,"REPEAT"); return NULL; } else if (r == 0) { // No more element break; } if(strcasecmp(element,"ENTRY") == 0) { entry = asx_parse_entry(parser,body,attribs); if(entry) { if(!list) list = entry; else play_tree_append_entry(list,entry); mp_msg(MSGT_PLAYTREE,MSGL_DBG2,"Adding element %s to repeat\n",element); } } else if(strcasecmp(element,"ENTRYREF") == 0) { entry = asx_parse_entryref(parser,body,attribs); if(entry) { if(!list) list = entry; else play_tree_append_entry(list,entry); mp_msg(MSGT_PLAYTREE,MSGL_DBG2,"Adding element %s to repeat\n",element); } } else if(strcasecmp(element,"REPEAT") == 0) { entry = asx_parse_repeat(parser,body,attribs); if(entry) { if(!list) list = entry; else play_tree_append_entry(list,entry); mp_msg(MSGT_PLAYTREE,MSGL_DBG2,"Adding element %s to repeat\n",element); } } else mp_msg(MSGT_PLAYTREE,MSGL_DBG2,"Ignoring element %s\n",element); if(body) free(body); asx_free_attribs(attribs); } if(!list) { play_tree_free(repeat,1); return NULL; } play_tree_set_child(repeat,list); return repeat; } play_tree_t* asx_parser_build_tree(char* buffer) { char *element,*asx_body,**asx_attribs,*body, **attribs; int r; play_tree_t *asx,*entry,*list = NULL; ASX_Parser_t* parser = asx_parser_new(); parser->line = 1; r = asx_get_element(parser,&buffer,&element,&asx_body,&asx_attribs); if(r < 0) { mp_msg(MSGT_PLAYTREE,MSGL_ERR,"At line %d : Syntax error ???",parser->line); asx_parser_free(parser); return NULL; } else if(r == 0) { // No contents mp_msg(MSGT_PLAYTREE,MSGL_ERR,"empty asx element"); asx_parser_free(parser); return NULL; } if(strcasecmp(element,"ASX") != 0) { mp_msg(MSGT_PLAYTREE,MSGL_ERR,"first element isn't ASX, it's %s\n",element); asx_free_attribs(asx_attribs); if(body) free(body); asx_parser_free(parser); return NULL; } if(!asx_body) { mp_msg(MSGT_PLAYTREE,MSGL_ERR,"ASX element is empty"); asx_free_attribs(asx_attribs); asx_parser_free(parser); return NULL; } asx = play_tree_new(); buffer = asx_body; while(buffer && buffer[0] != '\0') { r = asx_get_element(parser,&buffer,&element,&body,&attribs); if(r < 0) { asx_warning_body_parse_error(parser,"ASX"); asx_parser_free(parser); return NULL; } else if (r == 0) { // No more element break; } if(strcasecmp(element,"ENTRY") == 0) { entry = asx_parse_entry(parser,body,attribs); if(entry) { if(!list) list = entry; else play_tree_append_entry(list,entry); mp_msg(MSGT_PLAYTREE,MSGL_DBG2,"Adding element %s to asx\n",element); } } else if(strcasecmp(element,"ENTRYREF") == 0) { entry = asx_parse_entryref(parser,body,attribs); if(entry) { if(!list) list = entry; else play_tree_append_entry(list,entry); mp_msg(MSGT_PLAYTREE,MSGL_DBG2,"Adding element %s to asx\n",element); } } else if(strcasecmp(element,"REPEAT") == 0) { entry = asx_parse_repeat(parser,body,attribs); if(entry) { if(!list) list = entry; else play_tree_append_entry(list,entry); mp_msg(MSGT_PLAYTREE,MSGL_DBG2,"Adding element %s to asx\n",element); } } else mp_msg(MSGT_PLAYTREE,MSGL_DBG2,"Ignoring element %s\n",element); if(body) free(body); asx_free_attribs(attribs); } free(asx_body); asx_free_attribs(asx_attribs); asx_parser_free(parser); if(!list) { play_tree_free(asx,1); return NULL; } play_tree_set_child(asx,list); return asx; } --- NEW FILE --- #include "playtree.h" typedef struct _ASX_Parser_t ASX_Parser_t; typedef struct { char* buffer; int line; } ASX_LineSave_t; struct _ASX_Parser_t { int line; // Curent line ASX_LineSave_t *ret_stack; int ret_stack_size; char* last_body; }; --- NEW FILE --- #include <stdlib.h> #include <string.h> #include <stdio.h> #include <assert.h> #include "playtree.h" #include "mp_msg.h" static int play_tree_is_valid(play_tree_t* pt); play_tree_t* play_tree_new(void) { play_tree_t* r = (play_tree_t*)calloc(1,sizeof(play_tree_t)); if(r == NULL) mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't allocate %d bytes of memory\n",sizeof(play_tree_t)); return r; } void play_tree_free(play_tree_t* pt, int childs) { play_tree_t* iter; #ifdef DEBUG assert(pt != NULL); #endif if(childs) { for(iter = pt->child; iter != NULL; iter = iter->next) play_tree_free(iter,1); pt->child = NULL; } play_tree_remove(pt,0,0); for(iter = pt->child ; iter != NULL ; iter = iter->next) iter->parent = NULL; //if(pt->params) free(pt->params); if(pt->files) { int i; for(i = 0 ; pt->files[i] != NULL ; i++) free(pt->files[i]); free(pt->files); } free(pt); } void play_tree_free_list(play_tree_t* pt, int childs) { play_tree_t* iter; #ifdef DEBUG assert(pt != NULL); #endif for(iter = pt ; iter->prev != NULL ; iter = iter->prev) /* NOTHING */; for( ; iter != NULL ; iter = iter->next) play_tree_free(iter,childs); } void play_tree_append_entry(play_tree_t* pt, play_tree_t* entry) { play_tree_t* iter; #ifdef DEBUG assert(pt != NULL); assert(entry != NULL); #endif if(pt == entry) return; for(iter = pt ; iter->next != NULL ; iter = iter->next) /* NOTHING */; entry->parent = iter->parent; entry->prev = iter; entry->next = NULL; iter->next = entry; } void play_tree_prepend_entry(play_tree_t* pt, play_tree_t* entry) { play_tree_t* iter; #ifdef DEBUG assert(pt != NULL); assert(entry != NULL); #endif for(iter = pt ; iter->prev != NULL; iter = iter->prev) /* NOTHING */; entry->prev = NULL; entry->next = iter; entry->parent = iter->parent; iter->prev = entry; if(entry->parent) { #ifdef DEBUG assert(entry->parent->child == iter); #endif entry->parent->child = entry; } } void play_tree_insert_entry(play_tree_t* pt, play_tree_t* entry) { #ifdef DEBUG assert(pt != NULL); assert(entry != NULL); #endif entry->parent = pt->parent; entry->prev = pt; if(pt->next) { #ifdef DEBUG assert(pt->next->prev == pt); #endif entry->next = pt->next; entry->next->prev = entry; } else entry->next = NULL; pt->next = entry; } void play_tree_remove(play_tree_t* pt, int free_it,int with_childs) { #ifdef DEBUG assert(pt != NULL); #endif // Middle of list if(pt->prev && pt->next) { #ifdef DEBUG assert(pt->prev->next == pt); assert(pt->next->prev == pt); #endif pt->prev->next = pt->next; pt->next->prev = pt->prev; } // End of list else if(pt->prev) { #ifdef DEBUG assert(pt->prev->next == pt); #endif pt->prev->next = NULL; } // Begining of list else if(pt->next) { #ifdef DEBUG assert(pt->next->prev == pt); #endif pt->next->prev = NULL; if(pt->parent) { #ifdef DEBUG assert(pt->parent->child == pt); #endif pt->parent->child = pt->next; } } // The only one else if(pt->parent) { #ifdef DEBUG assert(pt->parent->child == pt); #endif pt->parent->child = NULL; } pt->prev = pt->next = pt->parent = NULL; if(free_it) play_tree_free(pt,with_childs); } void play_tree_set_child(play_tree_t* pt, play_tree_t* child) { play_tree_t* iter; #ifdef DEBUG assert(pt != NULL); assert(pt->files == NULL); #endif for(iter = pt->child ; iter != NULL ; iter = iter->next) iter->parent = NULL; // Go back to first one for(iter = child ; iter->prev != NULL ; iter = iter->prev) /* NOTHING */; pt->child = iter; for( ; iter != NULL ; iter= iter->next) iter->parent = pt; } void play_tree_set_parent(play_tree_t* pt, play_tree_t* parent) { play_tree_t* iter; #ifdef DEBUG assert(pt != NULL); #endif if(pt->parent) pt->parent->child = NULL; for(iter = pt ; iter != NULL ; iter = iter->next) iter->parent = parent; if(pt->prev) { for(iter = pt->prev ; iter->prev != NULL ; iter = iter->prev) iter->parent = parent; iter->parent = parent; parent->child = iter; } else parent->child = pt; } void play_tree_add_file(play_tree_t* pt,char* file) { int n = 0; #ifdef DEBUG assert(pt != NULL); assert(pt->child == NULL); assert(file != NULL); #endif if(pt->files) { for(n = 0 ; pt->files[n] != NULL ; n++) /* NOTHING */; } pt->files = (char**)realloc(pt->files,(n+2)*sizeof(char*)); if(pt->files ==NULL) { mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't allocate %d bytes of memory\n",(n+2)*sizeof(char*)); return; } pt->files[n] = strdup(file); pt->files[n+1] = NULL; } int play_tree_remove_file(play_tree_t* pt,char* file) { int n,f = -1; #ifdef DEBUG assert(pt != NULL); assert(file != NULL); assert(pt->files != NULL); #endif for(n=0 ; pt->files[n] != NULL ; n++) { if(strcmp(file,pt->files[n]) == 0) f = n; } if(f < 0) // Not found return 0; #ifdef DEBUG assert(n > f); #endif free(pt->files[f]); if(n > 1) { memmove(&pt->files[f],&pt->files[f+1],(n-f)*sizeof(char*)); pt->files = (char**)realloc(pt->files,n*sizeof(char*)); if(pt->files == NULL) { mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't allocate %d bytes of memory\n",(n+2)*sizeof(char*)); return -1; } } else { free(pt->files); pt->files = NULL; } return 1; } #if 0 void play_tree_set_param(play_tree_t* pt, char* name, char* val) { int n = 0,ni = -1; #ifdef DEBUG assert(pt != NULL); assert(name != NULL); #endif if(pt->params) { for( ; pt->params[n].name != NULL ; n++) { if(strcasecmp(pt->params[n].name,name) == 0) ni = n; } } if(ni > 0) { if(pt->params[n].value != NULL) free(pt->params[n].value); pt->params[n].value = val; return; } pt->params = (play_tree_param_t*)realloc(pt->params,(n+2)*sizeof(play_tree_param_t)); pt->params[n].name = strdup(name); pt->params[n].value = val != NULL ? strdup(val) : NULL; memset(&pt->params[n+1],0,sizeof(play_tree_param_t)); return; } int play_tree_unset_param(play_tree_t* pt, char* name) { int n,ni = 0; #ifdef DEBUG assert(pt != NULL); assert(name != NULL); assert(pt->params != NULL); #endif for(n = 0 ; pt->params[n].name != NULL ; n++) { if(strcasecmp(pt->params[n].name,name) == 0) ni = n; } if(ni < 0) return 0; if(n > 1) { memmove(&pt->params[ni],&pt->params[ni+1],(n-ni)*sizeof(play_tree_param_t)); pt->params = (play_tree_param_t*)realloc(pt->params,n*sizeof(play_tree_param_t)); assert(pt->params != NULL); } else { free(pt->params); pt->params = NULL; } return 1; } #endif play_tree_iter_t* play_tree_iter_new(play_tree_t* pt) { play_tree_iter_t* iter; #ifdef DEBUG assert(pt != NULL); #endif if( ! play_tree_is_valid(pt)) return NULL; iter = (play_tree_iter_t*)calloc(1,sizeof(play_tree_iter_t)); if(! iter) return NULL; iter->root = pt; iter->tree = NULL; if(pt->parent) iter->loop = pt->parent->loop; return iter; } void play_tree_iter_free(play_tree_iter_t* iter) { #ifdef DEBUG assert(iter != NULL); #endif if(iter->status_stack) { #ifdef DEBUG assert(iter->stack_size > 0); #endif free(iter->status_stack); } free(iter); } int play_tree_iter_step(play_tree_iter_t* iter, int d,int with_nodes) { play_tree_t* pt; #ifdef DEBUG assert(iter != NULL); assert(iter->root != NULL); #endif if(iter->tree == NULL) { iter->tree = iter->root; return play_tree_iter_step(iter,0,with_nodes); } iter->file = 0; if( d > 0 ) pt = iter->tree->next; else if(d < 0) pt = iter->tree->prev; else pt = iter->tree; if(pt == NULL) { // No next // Must we loop? if(iter->tree->parent && iter->tree->parent->loop != 0 && ((d > 0 && iter->loop != 0) || ( d < 0 && (iter->loop < 0 || iter->loop < iter->tree->parent->loop) ) ) ) { if(d > 0) { // Go back to the first one for(pt = iter->tree ; pt->prev != NULL; pt = pt->prev) /* NOTHNG */; if(iter->loop > 0) iter->loop--; } else if( d < 0 ) { // Or the last one for(pt = iter->tree ; pt->next != NULL; pt = pt->next) /* NOTHNG */; if(iter->loop >= 0 && iter->loop < iter->tree->parent->loop) iter->loop++; } iter->tree = pt; return play_tree_iter_step(iter,0,with_nodes); } // Go up one level return play_tree_iter_up_step(iter,d,with_nodes); } // Is there any valid childs ? if(pt->child && play_tree_is_valid(pt->child)) { iter->tree = pt; if(with_nodes) { // Stop on the node return PLAY_TREE_ITER_NODE; } else // Or follow it return play_tree_iter_down_step(iter,d,with_nodes); } // Is it a valid enty ? if(! play_tree_is_valid(pt)) { if(d == 0) { // Can this happen ? mp_msg(MSGT_PLAYTREE,MSGL_ERR,"What to do now ???? Infinite loop if we continue\n"); return PLAY_TREE_ITER_ERROR; } // Not a valid entry : go to next one return play_tree_iter_step(iter,d,with_nodes); } #ifdef DEBUG assert(iter->tree->files != NULL); #endif iter->tree = pt; for(d = 0 ; iter->tree->files[d] != NULL ; d++) /* NOTHING */; iter->num_files = d; return PLAY_TREE_ITER_ENTRY; } static int play_tree_is_valid(play_tree_t* pt) { play_tree_t* iter; #ifdef DEBUG assert(pt != NULL); #endif if(pt->files != NULL) return 1; else if (pt->child != NULL) { for(iter = pt->child ; iter != NULL ; iter = iter->next) { if(play_tree_is_valid(iter)) return 1; } } return 0; } int play_tree_iter_up_step(play_tree_iter_t* iter, int d,int with_nodes) { #ifdef DEBUG assert(iter != NULL); assert(iter->tree != NULL); #endif iter->file = 0; if(iter->tree->parent == iter->root->parent) return PLAY_TREE_ITER_END; #ifdef DEBUG assert(iter->tree->parent != NULL); assert(iter->stack_size > 0); assert(iter->status_stack != NULL); #endif // Pop status iter->stack_size--; iter->loop = iter->status_stack[iter->stack_size]; iter->status_stack = (int*)realloc(iter->status_stack,iter->stack_size*sizeof(int)); if(iter->stack_size > 0 && iter->status_stack == NULL) { mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't allocate %d bytes of memory\n",iter->stack_size*sizeof(char*)); return PLAY_TREE_ITER_ERROR; } iter->tree = iter->tree->parent; return play_tree_iter_step(iter,d,with_nodes); } int play_tree_iter_down_step(play_tree_iter_t* iter, int d,int with_nodes) { #ifdef DEBUG assert(iter->tree->files == NULL); assert(iter->tree->child != NULL); assert(iter->tree->child->parent == iter->tree); #endif iter->file = 0; // Push status iter->stack_size++; iter->status_stack = (int*)realloc(iter->status_stack,iter->stack_size*sizeof(int)); if(iter->status_stack == NULL) { mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't allocate %d bytes of memory\n",iter->stack_size*sizeof(int)); return PLAY_TREE_ITER_ERROR; } iter->status_stack[iter->stack_size-1] = iter->loop; // Set new status iter->loop = iter->tree->loop-1; if(d >= 0) iter->tree = iter->tree->child; else { play_tree_t* pt; for(pt = iter->tree->child ; pt->next != NULL ; pt = pt->next) /*NOTING*/; iter->tree = pt; } return play_tree_iter_step(iter,0,with_nodes); } char* play_tree_iter_get_file(play_tree_iter_t* iter, int d) { #ifdef DEBUG assert(iter != NULL); assert(iter->tree->child == NULL); #endif if(iter->tree->files == NULL) return NULL; if(d > 0) { if(iter->tree->files[iter->file] == NULL) return NULL; iter->file++; } else if(d < 0) { if(iter->file == 0) return NULL; iter->file--; } return iter->tree->files[iter->file-1]; } play_tree_t* play_tree_cleanup(play_tree_t* pt) { play_tree_t* iter, *tmp, *first; #ifdef DEBUG assert(pt != NULL); #endif if( ! play_tree_is_valid(pt)) { play_tree_remove(pt,1,1); return NULL; } first = pt->child; for(iter = pt->child ; iter != NULL ; ) { tmp = iter; iter = iter->next; if(! play_tree_is_valid(tmp)) { play_tree_remove(tmp,1,1); if(tmp == first) first = iter; } } for(iter = first ; iter != NULL ; ) { tmp = iter; iter = iter->next; play_tree_cleanup(tmp); } return pt; } play_tree_iter_t* play_tree_iter_new_copy(play_tree_iter_t* old) { play_tree_iter_t* iter; #ifdef DEBUG assert(old != NULL); #endif iter = (play_tree_iter_t*)malloc(sizeof(play_tree_iter_t)); if(iter == NULL) { mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't allocate %d bytes of memory\n",sizeof(play_tree_iter_t)); return NULL; } ; memcpy(iter,old,sizeof(play_tree_iter_t)); if(old->status_stack) { iter->status_stack = (int*)malloc(old->stack_size * sizeof(int)); if(iter->status_stack == NULL) { mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't allocate %d bytes of memory\n",old->stack_size * sizeof(int)); free(iter); return NULL; } memcpy(iter->status_stack,old->status_stack,iter->stack_size*sizeof(int)); } return iter; } --- NEW FILE --- #include "libmpdemux/stream.h" #define PLAY_TREE_ITER_ERROR 0 #define PLAY_TREE_ITER_ENTRY 1 #define PLAY_TREE_ITER_NODE 2 #define PLAY_TREE_ITER_END 3 typedef struct play_tree play_tree_t; typedef struct play_tree_iter play_tree_iter_t; #if 0 typedef struct play_tree_info play_tree_info_t; typedef struct play_tree_param play_tree_param_t; // TODO : a attrib,val pair system and not something hardcoded struct play_tree_info { char* title; char* author; char* copyright; char* abstract; // Some more ?? } struct play_tree_param { char* name; char* value; } #endif struct play_tree { play_tree_t* parent; play_tree_t* child; play_tree_t* next; play_tree_t* prev; //play_tree_info_t info; //int n_param; //play_tree_param_t* params; int loop; char** files; }; struct play_tree_iter { play_tree_t* root; // Iter root tree play_tree_t* tree; // Current tree // struct m_config* config; int loop; // Looping status int file; int num_files; int* status_stack; // loop/valid stack to save/revert status when we go up/down int stack_size; // status stack size }; play_tree_t* play_tree_new(void); // If childs is true free also the childs void play_tree_free(play_tree_t* pt, int childs); void play_tree_free_list(play_tree_t* pt, int childs); // Childs void play_tree_set_child(play_tree_t* pt, play_tree_t* child); // Or parent void play_tree_set_parent(play_tree_t* pt, play_tree_t* parent); // Add at end void play_tree_append_entry(play_tree_t* pt, play_tree_t* entry); // And on begining void play_tree_prepend_entry(play_tree_t* pt, play_tree_t* entry); // Insert after void play_tree_insert_entry(play_tree_t* pt, play_tree_t* entry); // Detach from the tree void play_tree_remove(play_tree_t* pt, int free_it,int with_childs); void play_tree_add_file(play_tree_t* pt,char* file); int play_tree_remove_file(play_tree_t* pt,char* file); #if 0 // Val can be NULL void play_tree_set_param(play_tree_t* pt, char* name, char* val); int play_tree_unset_param(play_tree_t* pt, char* name); #endif /// Iterator play_tree_iter_t* play_tree_iter_new(play_tree_t* pt); play_tree_iter_t* play_tree_iter_new_copy(play_tree_iter_t* old); void play_tree_iter_free(play_tree_iter_t* iter); // d is the direction : d > 0 == next , d < 0 == prev // with_node : TRUE == stop on nodes with childs, FALSE == go directly to the next child int play_tree_iter_step(play_tree_iter_t* iter, int d,int with_nodes); int // Break a loop, etc play_tree_iter_up_step(play_tree_iter_t* iter, int d,int with_nodes); int // Enter a node child list play_tree_iter_down_step(play_tree_iter_t* iter, int d,int with_nodes); char* play_tree_iter_get_file(play_tree_iter_t* iter, int d); play_tree_t* parse_playtree(stream_t *stream); play_tree_t* play_tree_cleanup(play_tree_t* pt); play_tree_t* parse_playlist_file(char* file); --- NEW FILE --- #include <stdlib.h> #include <stdio.h> #include <string.h> #include <assert.h> #include <errno.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include "playtree.h" #include "libmpdemux/stream.h" #include "mp_msg.h" extern play_tree_t* asx_parser_build_tree(char* buffer); static char* buffer = NULL; static int buffer_size = 0, buffer_end = 0; play_tree_t* parse_asx(stream_t* stream) { int r; int comments = 0,read = 1,eof = 0; mp_msg(MSGT_PLAYTREE,MSGL_V,"Trying asx...\n"); while(1) { if(read && eof) // Eof reached before anything useful return NULL; if(read) { if(buffer_size - buffer_end < 50) buffer_size += 255; buffer = (char*)realloc(buffer,buffer_size*sizeof(char)); if(buffer == NULL) { mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't allocate %d bytes of memory\n",buffer_size*sizeof(char)); buffer_size = buffer_end = 0; return NULL; } r = stream_read(stream,buffer+buffer_end,buffer_size-buffer_end-1); if(r < 0) { mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't read from stream r=%d\n",r); return NULL; } else if(r == 0) eof = 1; buffer_end += r; buffer[buffer_end] = '\0'; } if(comments) { // Jump comments int e; char* end = strstr(buffer,"-->"); if(!end) { if(buffer[buffer_end-1] != '-') buffer_end = 0; // Drop buffer content if last char isn't '-' continue; } comments = 0; e = end - buffer + 3; if(e >= buffer_end) { // > seems impossible buffer_end = 0; // Drop buffer content read = 1; continue; } buffer_end -= e; memmove(buffer,end+3,buffer_end); // Drop comments continue; } for(r= 0 ; r < buffer_end ; r++) { if(strchr(" \n\r\t",buffer[r]) != NULL) // Jump space continue; if(buffer[r] != '<') { mp_msg(MSGT_PLAYTREE,MSGL_DBG2,"First char isn't '<' but '%c'\n",buffer[r]); mp_msg(MSGT_PLAYTREE,MSGL_DBG3,"Buffer = [%s]\n",buffer); return NULL; } break; // Stop on first '<' } if(r > buffer_end-4) { // We need more if(r > 0) { // Drop unuseful beggining buffer_end -= r; memmove(buffer,&buffer[r],buffer_end); } read = 1; continue; } if(strncmp(&buffer[r],"<!--",4) == 0) { // Comments read = 0; comments = 1; continue; } if(strncasecmp(&buffer[r],"<ASX",4) != 0) // First element is not a comment nor an asx : end return NULL; mp_msg(MSGT_PLAYTREE,MSGL_V,"Detected asx format\n"); break; } // We have an asx : load it in memory and parse while(!eof) { if(buffer_size - buffer_end < 50) buffer_size += 255; buffer = (char*)realloc(buffer,buffer_size*sizeof(char)); if(buffer == NULL) { mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't allocate %d bytes of memory\n",buffer_size*sizeof(char)); buffer_size = buffer_end = 0; return NULL; } r = stream_read(stream,buffer+buffer_end,buffer_size-buffer_end-1); if(r > 0) buffer_end += r; if(r <= 0) break; buffer[buffer_end] = '\0'; } mp_msg(MSGT_PLAYTREE,MSGL_DBG3,"Parsing asx file : [%s]\n",buffer); return asx_parser_build_tree(buffer); } play_tree_t* parse_textplain(stream_t *stream) { char* end; char* file; int eof = 0,r,p_end=-1,resize = 0; play_tree_t *list = NULL, *entry = NULL; mp_msg(MSGT_PLAYTREE,MSGL_V,"Trying plaintext...\n"); if(buffer_size < 255 && ! stream->eof) { buffer_size = 255; buffer = (char*)realloc(buffer,buffer_size*sizeof(char)); if(buffer == NULL) { mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't allocate %d bytes of memory\n",buffer_size*sizeof(char)); buffer_size = buffer_end = 0; return NULL; } } while(!eof) { if(resize) { buffer_size += 255; buffer = (char*)realloc(buffer,buffer_size*sizeof(char)); resize = 0; if(buffer == NULL) { mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't allocate %d bytes of memory\n",buffer_size*sizeof(char)); buffer_size = buffer_end = 0; if(list) play_tree_free_list(list,1); return NULL; } } if(!stream->eof) { r = stream_read(stream,buffer+buffer_end,buffer_size-buffer_end-1); if(r < 0) { mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't read from stream r=%d\n",r); return NULL; } else if(r == 0) eof = 1; buffer_end += r; buffer[buffer_end] = '\0'; } else eof = 1; r = 0; while(1) { p_end = r; for( ; buffer[r] != '\0' ; r++) { if(strchr(" \n\r\t",buffer[r]) != NULL) continue; break; } if(buffer[r] == '\0') { p_end = r; if(!eof) resize = 1; break; } end = strchr(&buffer[r],'\n'); if(!end) { if(!eof) { p_end = r; if(p_end == 0) { resize = 1; } break; } entry = play_tree_new(); play_tree_add_file(entry,&buffer[r]); r = buffer_end; } else { if(r > 0 && buffer[r-1] == '\r') r--; file = (char*)malloc((end-(&buffer[r])+1)*sizeof(char)); if(file == NULL) { mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't allocate %d bytes of memory\n",buffer_size*sizeof(char)); buffer_size = buffer_end = 0; if(list) play_tree_free_list(list,1); return NULL; } // TODO : Check if the given file exist and is readable (or it'a an url) strncpy(file,&buffer[r],end-(&buffer[r])); file[end-(&buffer[r])] = '\0'; entry = play_tree_new(); play_tree_add_file(entry,file); free(file); r += end-(&buffer[r]); p_end = r; } if(entry) { mp_msg(MSGT_PLAYTREE,MSGL_DBG2,"Adding file %s to playlist\n",entry->files[0]); if(list) play_tree_append_entry(list,entry); else list = entry; entry = NULL; } } if(!eof && p_end > 0 && p_end < buffer_end) { memmove(buffer,&buffer[p_end],buffer_end-p_end); buffer_end -= p_end; } else if(!eof && !resize && p_end == buffer_end) { buffer_end = 0; buffer[0] = '\0'; } } if(!list) return NULL; entry = play_tree_new(); play_tree_set_child(entry,list); return entry; } play_tree_t* parse_playtree(stream_t *stream) { play_tree_t* tree = NULL; #ifdef DEBUG assert(stream != NULL); assert(stream->type == STREAMTYPE_PLAYLIST); #endif while(1) { tree = parse_asx(stream); if(tree) break; // Here come the others formats ( textplain must stay the last one ) tree = parse_textplain(stream); if(tree) break; break; } if(tree) mp_msg(MSGT_PLAYTREE,MSGL_V,"Playlist succefully parsed\n"); else mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Error while parsing playlist\n"); if(tree) tree = play_tree_cleanup(tree); if(!tree) mp_msg(MSGT_PLAYTREE,MSGL_WARN,"Warning empty playlist\n"); if(buffer) free(buffer); buffer = NULL; buffer_end = buffer_size = 0; return tree; } play_tree_t* parse_playlist_file(char* file) { stream_t *stream; play_tree_t* ret; int fd; if(!strcmp(file,"-")) fd = 0; else fd = open(file,O_RDONLY); if(fd < 0) { mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Error while opening playlist file %s : %s\n",file,strerror(errno)); return NULL; } mp_msg(MSGT_PLAYTREE,MSGL_V,"Parsing playlist file %s...\n",file); stream = new_stream(fd,STREAMTYPE_PLAYLIST); ret = parse_playtree(stream); if(close(fd) < 0) mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Warning error while closing playlist file %s : %s\n",file,strerror(errno)); free_stream(stream); return ret; } Index: Makefile =================================================================== RCS file: /cvsroot/mplayer/main/Makefile,v retrieving revision 1.135 retrieving revision 1.136 diff -u -r1.135 -r1.136 --- Makefile 7 Jan 2002 09:28:20 -0000 1.135 +++ Makefile 8 Jan 2002 01:24:25 -0000 1.136 @@ -27,7 +27,7 @@ SRCS_COMMON = cyuv.c adpcm.c xacodec.c cpudetect.c mp_msg.c ac3-iec958.c dec_audio.c dec_video.c msvidc.c cinepak.c fli.c qtrle.c codec-cfg.c cfgparser.c my_profile.c RTjpegN.c minilzo.c nuppelvideo.c SRCS_MENCODER = mencoder.c $(SRCS_COMMON) libao2/afmt.c divx4_vbr.c libvo/aclib.c libvo/img_format.c -SRCS_MPLAYER = mplayer.c $(SRCS_COMMON) find_sub.c subreader.c lirc_mp.c mixer.c spudec.c +SRCS_MPLAYER = mplayer.c $(SRCS_COMMON) find_sub.c subreader.c lirc_mp.c mixer.c spudec.c playtree.c playtreeparser.c asxparser.c OBJS_MENCODER = $(SRCS_MENCODER:.c=.o) OBJS_MPLAYER = $(SRCS_MPLAYER:.c=.o)
participants (1)
-
Arpi of Ize