util.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:29k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * util.c : Utility functions for HTTP interface
  3.  *****************************************************************************
  4.  * Copyright (C) 2001-2005 the VideoLAN team
  5.  * $Id: aee0199cfec637c129fb21e699d8f71cc59533a4 $
  6.  *
  7.  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  8.  *          Laurent Aimar <fenrir@via.ecp.fr>
  9.  *          Christophe Massiot <massiot@via.ecp.fr>
  10.  *
  11.  * This program is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  *
  16.  * This program is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  24.  *****************************************************************************/
  25. #ifdef HAVE_CONFIG_H
  26. # include "config.h"
  27. #endif
  28. #include <vlc_common.h>
  29. #include "http.h"
  30. #include "vlc_strings.h"
  31. /****************************************************************************
  32.  * File and directory functions
  33.  ****************************************************************************/
  34. /* ToUrl: create a good name for an url from filename */
  35. char *FileToUrl( char *name, bool *pb_index )
  36. {
  37.     char *url, *p;
  38.     url = p = malloc( strlen( name ) + 1 );
  39.     *pb_index = false;
  40.     if( !url || !p )
  41.     {
  42.         return NULL;
  43.     }
  44. #ifdef WIN32
  45.     while( *name == '\' || *name == '/' )
  46. #else
  47.     while( *name == '/' )
  48. #endif
  49.     {
  50.         name++;
  51.     }
  52.     *p++ = '/';
  53.     strcpy( p, name );
  54. #ifdef WIN32
  55.     /* convert '\' into '/' */
  56.     name = p;
  57.     while( *name )
  58.     {
  59.         if( *name == '\' )
  60.             *name = '/';
  61.         name++;
  62.     }
  63. #endif
  64.     /* index.* -> / */
  65.     if( ( p = strrchr( url, '/' ) ) != NULL )
  66.     {
  67.         if( !strncmp( p, "/index.", 7 ) )
  68.         {
  69.             p[1] = '';
  70.             *pb_index = true;
  71.         }
  72.     }
  73.     return url;
  74. }
  75. /* Load a file */
  76. int FileLoad( FILE *f, char **pp_data, int *pi_data )
  77. {
  78.     int i_read;
  79.     /* just load the file */
  80.     *pi_data = 0;
  81.     *pp_data = malloc( 1025 );  /* +1 for  */
  82.     while( ( i_read = fread( &(*pp_data)[*pi_data], 1, 1024, f ) ) == 1024 )
  83.     {
  84.         *pi_data += 1024;
  85.         *pp_data = realloc( *pp_data, *pi_data  + 1025 );
  86.     }
  87.     if( i_read > 0 )
  88.     {
  89.         *pi_data += i_read;
  90.     }
  91.     (*pp_data)[*pi_data] = '';
  92.     return VLC_SUCCESS;
  93. }
  94. /* Parse a directory and recursively add files */
  95. int ParseDirectory( intf_thread_t *p_intf, char *psz_root,
  96.                         char *psz_dir )
  97. {
  98.     intf_sys_t     *p_sys = p_intf->p_sys;
  99.     char           dir[MAX_DIR_SIZE];
  100.     DIR           *p_dir;
  101.     vlc_acl_t     *p_acl;
  102.     FILE          *file;
  103.     char          *user = NULL;
  104.     char          *password = NULL;
  105.     int           i_dirlen;
  106.     if( ( p_dir = utf8_opendir( psz_dir ) ) == NULL )
  107.     {
  108.         if( errno != ENOENT && errno != ENOTDIR )
  109.             msg_Err( p_intf, "cannot open directory (%s)", psz_dir );
  110.         return VLC_EGENERIC;
  111.     }
  112.     i_dirlen = strlen( psz_dir );
  113.     if( i_dirlen + 10 > MAX_DIR_SIZE )
  114.     {
  115.         msg_Warn( p_intf, "skipping too deep directory (%s)", psz_dir );
  116.         closedir( p_dir );
  117.         return 0;
  118.     }
  119.     msg_Dbg( p_intf, "dir=%s", psz_dir );
  120.     snprintf( dir, sizeof( dir ), "%s"DIR_SEP".access", psz_dir );
  121.     if( ( file = utf8_fopen( dir, "r" ) ) != NULL )
  122.     {
  123.         char line[1024];
  124.         int  i_size;
  125.         msg_Dbg( p_intf, "find .access in dir=%s", psz_dir );
  126.         i_size = fread( line, 1, 1023, file );
  127.         if( i_size > 0 )
  128.         {
  129.             char *p;
  130.             while( i_size > 0 && ( line[i_size-1] == 'n' ||
  131.                    line[i_size-1] == 'r' ) )
  132.             {
  133.                 i_size--;
  134.             }
  135.             line[i_size] = '';
  136.             p = strchr( line, ':' );
  137.             if( p )
  138.             {
  139.                 *p++ = '';
  140.                 user = strdup( line );
  141.                 password = strdup( p );
  142.             }
  143.         }
  144.         msg_Dbg( p_intf, "using user=%s (read=%d)", user, i_size );
  145.         fclose( file );
  146.     }
  147.     snprintf( dir, sizeof( dir ), "%s"DIR_SEP".hosts", psz_dir );
  148.     p_acl = ACL_Create( p_intf, false );
  149.     if( ACL_LoadFile( p_acl, dir ) )
  150.     {
  151.         ACL_Destroy( p_acl );
  152.         struct stat st;
  153.         if( stat( dir, &st ) == 0 )
  154.         {
  155.             free( user );
  156.             free( password );
  157.             closedir( p_dir );
  158.             return VLC_EGENERIC;
  159.         }
  160.         p_acl = NULL;
  161.     }
  162.     for( ;; )
  163.     {
  164.         char *psz_filename;
  165.         /* parse psz_src dir */
  166.         if( ( psz_filename = utf8_readdir( p_dir ) ) == NULL )
  167.         {
  168.             break;
  169.         }
  170.         if( ( psz_filename[0] == '.' )
  171.          || ( i_dirlen + strlen( psz_filename ) > MAX_DIR_SIZE ) )
  172.         {
  173.             free( psz_filename );
  174.             continue;
  175.         }
  176.         snprintf( dir, sizeof( dir ), "%s"DIR_SEP"%s", psz_dir, psz_filename );
  177.         free( psz_filename );
  178.         if( ParseDirectory( p_intf, psz_root, dir ) )
  179.         {
  180.             httpd_file_sys_t *f = NULL;
  181.             httpd_handler_sys_t *h = NULL;
  182.             bool b_index;
  183.             char *psz_name, *psz_ext;
  184.             psz_name = FileToUrl( &dir[strlen( psz_root )], &b_index );
  185.             psz_ext = strrchr( dir, '.' );
  186.             if( psz_ext != NULL )
  187.             {
  188.                 int i;
  189.                 psz_ext++;
  190.                 for( i = 0; i < p_sys->i_handlers; i++ )
  191.                     if( !strcmp( p_sys->pp_handlers[i]->psz_ext, psz_ext ) )
  192.                         break;
  193.                 if( i < p_sys->i_handlers )
  194.                 {
  195.                     f = malloc( sizeof( httpd_handler_sys_t ) );
  196.                     h = (httpd_handler_sys_t *)f;
  197.                     f->b_handler = true;
  198.                     h->p_association = p_sys->pp_handlers[i];
  199.                 }
  200.             }
  201.             if( f == NULL )
  202.             {
  203.                 f = malloc( sizeof( httpd_file_sys_t ) );
  204.                 f->b_handler = false;
  205.             }
  206.             f->p_intf  = p_intf;
  207.             f->p_file = NULL;
  208.             f->p_redir = NULL;
  209.             f->p_redir2 = NULL;
  210.             f->file = strdup (dir);
  211.             f->name = psz_name;
  212.             f->b_html = strstr( &dir[strlen( psz_root )], ".htm" ) || strstr( &dir[strlen( psz_root )], ".xml" ) ? true : false;
  213.             if( !f->name )
  214.             {
  215.                 msg_Err( p_intf , "unable to parse directory" );
  216.                 closedir( p_dir );
  217.                 free( f );
  218.                 return( VLC_ENOMEM );
  219.             }
  220.             msg_Dbg( p_intf, "file=%s (url=%s)",
  221.                      f->file, f->name );
  222.             if( !f->b_handler )
  223.             {
  224.                 char *psz_type = strdup( "text/html; charset=UTF-8" );
  225.                 if( strstr( &dir[strlen( psz_root )], ".xml" ) )
  226.                 {
  227.                     char *psz = strstr( psz_type, "html;" );
  228.                     if( psz )
  229.                     {
  230.                         psz[0] = 'x';
  231.                         psz[1] = 'm';
  232.                         psz[2] = 'l';
  233.                         psz[3] = ';';
  234.                         psz[4] = ' ';
  235.                     }
  236.                 }
  237.                 f->p_file = httpd_FileNew( p_sys->p_httpd_host,
  238.                                            f->name,
  239.                                            f->b_html ? psz_type : NULL,
  240.                                            user, password, p_acl,
  241.                                            HttpCallback, f );
  242.                 free( psz_type );
  243.                 if( f->p_file != NULL )
  244.                 {
  245.                     TAB_APPEND( p_sys->i_files, p_sys->pp_files, f );
  246.                 }
  247.             }
  248.             else
  249.             {
  250.                 h->p_handler = httpd_HandlerNew( p_sys->p_httpd_host,
  251.                                                  f->name,
  252.                                                  user, password, p_acl,
  253.                                                  HandlerCallback, h );
  254.                 if( h->p_handler != NULL )
  255.                 {
  256.                     TAB_APPEND( p_sys->i_files, p_sys->pp_files,
  257.                                 (httpd_file_sys_t *)h );
  258.                 }
  259.             }
  260.             /* for url that ends by / add
  261.              *  - a redirect from rep to rep/
  262.              *  - in case of index.* rep/index.html to rep/ */
  263.             if( f && f->name[strlen(f->name) - 1] == '/' )
  264.             {
  265.                 char *psz_redir = strdup( f->name );
  266.                 char *p;
  267.                 psz_redir[strlen( psz_redir ) - 1] = '';
  268.                 msg_Dbg( p_intf, "redir=%s -> %s", psz_redir, f->name );
  269.                 f->p_redir = httpd_RedirectNew( p_sys->p_httpd_host, f->name, psz_redir );
  270.                 free( psz_redir );
  271.                 if( b_index && ( p = strstr( f->file, "index." ) ) )
  272.                 {
  273.                     if( asprintf( &psz_redir, "%s%s", f->name, p ) != -1 )
  274.                     {
  275.                         msg_Dbg( p_intf, "redir=%s -> %s", psz_redir, f->name );
  276.                         f->p_redir2 = httpd_RedirectNew( p_sys->p_httpd_host,
  277.                                                          f->name, psz_redir );
  278.                         free( psz_redir );
  279.                     }
  280.                 }
  281.             }
  282.         }
  283.     }
  284.     free( user );
  285.     free( password );
  286.     ACL_Destroy( p_acl );
  287.     closedir( p_dir );
  288.     return VLC_SUCCESS;
  289. }
  290. /*************************************************************************
  291.  * Playlist stuff
  292.  *************************************************************************/
  293. void PlaylistListNode( intf_thread_t *p_intf, playlist_t *p_pl,
  294.                            playlist_item_t *p_node, char *name, mvar_t *s,
  295.                            int i_depth )
  296. {
  297.     if( !p_node || !p_node->p_input )
  298.         return;
  299.     if( p_node->i_children == -1 )
  300.     {
  301.         char value[512];
  302.         char *psz;
  303.         playlist_item_t * p_item = playlist_CurrentPlayingItem( p_pl );
  304.         if( !p_item || !p_item->p_input )
  305.             return;
  306.         mvar_t *itm = mvar_New( name, "set" );
  307.         if( p_item->p_input->i_id == p_node->p_input->i_id )
  308.             mvar_AppendNewVar( itm, "current", "1" );
  309.         else
  310.             mvar_AppendNewVar( itm, "current", "0" );
  311.         sprintf( value, "%d", p_node->i_id );
  312.         mvar_AppendNewVar( itm, "index", value );
  313.         psz = input_item_GetName( p_node->p_input );
  314.         mvar_AppendNewVar( itm, "name", psz );
  315.         free( psz );
  316.         psz = input_item_GetURI( p_node->p_input );
  317.         mvar_AppendNewVar( itm, "uri", psz );
  318.         free( psz );
  319.         sprintf( value, "Item");
  320.         mvar_AppendNewVar( itm, "type", value );
  321.         sprintf( value, "%d", i_depth );
  322.         mvar_AppendNewVar( itm, "depth", value );
  323.         if( p_node->i_flags & PLAYLIST_RO_FLAG )
  324.             mvar_AppendNewVar( itm, "ro", "ro" );
  325.         else
  326.             mvar_AppendNewVar( itm, "ro", "rw" );
  327.         sprintf( value, "%"PRId64, input_item_GetDuration( p_node->p_input ) );
  328.         mvar_AppendNewVar( itm, "duration", value );
  329.         //Adding extra meta-information to each playlist item
  330.         psz = input_item_GetTitle( p_node->p_input );
  331.         mvar_AppendNewVar( itm, "title", psz );
  332.         free( psz );
  333.         psz = input_item_GetArtist( p_node->p_input );
  334.         mvar_AppendNewVar( itm, "artist", psz );
  335.         free( psz );
  336.         psz = input_item_GetGenre( p_node->p_input );
  337.         mvar_AppendNewVar( itm, "genre", psz );
  338.         free( psz );
  339.         psz = input_item_GetCopyright( p_node->p_input );
  340.         mvar_AppendNewVar( itm, "copyright", psz );
  341.         free( psz );
  342.         psz = input_item_GetAlbum( p_node->p_input );
  343.         mvar_AppendNewVar( itm, "album", psz );
  344.         free( psz );
  345.         psz = input_item_GetTrackNum( p_node->p_input );
  346.         mvar_AppendNewVar( itm, "track", psz );
  347.         free( psz );
  348.         psz = input_item_GetDescription( p_node->p_input );
  349.         mvar_AppendNewVar( itm, "description", psz );
  350.         free( psz );
  351.         psz = input_item_GetRating( p_node->p_input );
  352.         mvar_AppendNewVar( itm, "rating", psz );
  353.         free( psz );
  354.         psz = input_item_GetDate( p_node->p_input );
  355.         mvar_AppendNewVar( itm, "date", psz );
  356.         free( psz );
  357.         psz = input_item_GetURL( p_node->p_input );
  358.         mvar_AppendNewVar( itm, "url", psz );
  359.         free( psz );
  360.         psz = input_item_GetLanguage( p_node->p_input );
  361.         mvar_AppendNewVar( itm, "language", psz );
  362.         free( psz );
  363.         psz = input_item_GetNowPlaying( p_node->p_input );
  364.         mvar_AppendNewVar( itm, "now_playing", psz );
  365.         free( psz );
  366.         psz = input_item_GetPublisher( p_node->p_input );
  367.         mvar_AppendNewVar( itm, "publisher", psz );
  368.         free( psz );
  369.         psz = input_item_GetEncodedBy( p_node->p_input );
  370.         mvar_AppendNewVar( itm, "encoded_by", psz );
  371.         free( psz );
  372.         psz = input_item_GetArtURL( p_node->p_input );
  373.         mvar_AppendNewVar( itm, "art_url", psz );
  374.         free( psz );
  375.         psz = input_item_GetTrackID( p_node->p_input );
  376.         mvar_AppendNewVar( itm, "track_id", psz );
  377.         free( psz );
  378.         mvar_AppendVar( s, itm );
  379.     }
  380.     else
  381.     {
  382.         char value[512];
  383.         int i_child;
  384.         mvar_t *itm = mvar_New( name, "set" );
  385.         mvar_AppendNewVar( itm, "name", p_node->p_input->psz_name );
  386.         mvar_AppendNewVar( itm, "uri", p_node->p_input->psz_name );
  387.         sprintf( value, "Node" );
  388.         mvar_AppendNewVar( itm, "type", value );
  389.         sprintf( value, "%d", p_node->i_id );
  390.         mvar_AppendNewVar( itm, "index", value );
  391.         sprintf( value, "%d", p_node->i_children);
  392.         mvar_AppendNewVar( itm, "i_children", value );
  393.         sprintf( value, "%d", i_depth );
  394.         mvar_AppendNewVar( itm, "depth", value );
  395.         if( p_node->i_flags & PLAYLIST_RO_FLAG )
  396.             mvar_AppendNewVar( itm, "ro", "ro" );
  397.         else
  398.             mvar_AppendNewVar( itm, "ro", "rw" );
  399.         mvar_AppendVar( s, itm );
  400.         for( i_child = 0 ; i_child < p_node->i_children ; i_child++ )
  401.              PlaylistListNode( p_intf, p_pl, p_node->pp_children[i_child],
  402.                                name, s, i_depth + 1);
  403.     }
  404. }
  405. /****************************************************************************
  406.  * Seek command parsing handling
  407.  ****************************************************************************/
  408. void HandleSeek( intf_thread_t *p_intf, char *p_value )
  409. {
  410.     intf_sys_t     *p_sys = p_intf->p_sys;
  411.     vlc_value_t val;
  412.     int i_stock = 0;
  413.     uint64_t i_length;
  414.     int i_value = 0;
  415.     int i_relative = 0;
  416. #define POSITION_ABSOLUTE 12
  417. #define POSITION_REL_FOR 13
  418. #define POSITION_REL_BACK 11
  419. #define VL_TIME_ABSOLUTE 0
  420. #define VL_TIME_REL_FOR 1
  421. #define VL_TIME_REL_BACK -1
  422.     if( p_sys->p_input )
  423.     {
  424.         var_Get( p_sys->p_input, "length", &val );
  425.         i_length = val.i_time;
  426.         while( p_value[0] != '' )
  427.         {
  428.             switch(p_value[0])
  429.             {
  430.                 case '+':
  431.                 {
  432.                     i_relative = VL_TIME_REL_FOR;
  433.                     p_value++;
  434.                     break;
  435.                 }
  436.                 case '-':
  437.                 {
  438.                     i_relative = VL_TIME_REL_BACK;
  439.                     p_value++;
  440.                     break;
  441.                 }
  442.                 case '0': case '1': case '2': case '3': case '4':
  443.                 case '5': case '6': case '7': case '8': case '9':
  444.                 {
  445.                     i_stock = strtol( p_value , &p_value , 10 );
  446.                     break;
  447.                 }
  448.                 case '%': /* for percentage ie position */
  449.                 {
  450.                     i_relative += POSITION_ABSOLUTE;
  451.                     i_value = i_stock;
  452.                     i_stock = 0;
  453.                     p_value[0] = '';
  454.                     break;
  455.                 }
  456.                 case ':':
  457.                 {
  458.                     i_value = 60 * (i_value + i_stock) ;
  459.                     i_stock = 0;
  460.                     p_value++;
  461.                     break;
  462.                 }
  463.                 case 'h': case 'H': /* hours */
  464.                 {
  465.                     i_value += 3600 * i_stock;
  466.                     i_stock = 0;
  467.                     /* other characters which are not numbers are not
  468.                      * important */
  469.                     while( ((p_value[0] < '0') || (p_value[0] > '9'))
  470.                            && (p_value[0] != '') )
  471.                     {
  472.                         p_value++;
  473.                     }
  474.                     break;
  475.                 }
  476.                 case 'm': case 'M': case ''': /* minutes */
  477.                 {
  478.                     i_value += 60 * i_stock;
  479.                     i_stock = 0;
  480.                     p_value++;
  481.                     while( ((p_value[0] < '0') || (p_value[0] > '9'))
  482.                            && (p_value[0] != '') )
  483.                     {
  484.                         p_value++;
  485.                     }
  486.                     break;
  487.                 }
  488.                 case 's': case 'S': case '"':  /* seconds */
  489.                 {
  490.                     i_value += i_stock;
  491.                     i_stock = 0;
  492.                     while( ((p_value[0] < '0') || (p_value[0] > '9'))
  493.                            && (p_value[0] != '') )
  494.                     {
  495.                         p_value++;
  496.                     }
  497.                     break;
  498.                 }
  499.                 default:
  500.                 {
  501.                     p_value++;
  502.                     break;
  503.                 }
  504.             }
  505.         }
  506.         /* if there is no known symbol, I consider it as seconds.
  507.          * Otherwise, i_stock = 0 */
  508.         i_value += i_stock;
  509.         switch(i_relative)
  510.         {
  511.             case VL_TIME_ABSOLUTE:
  512.             {
  513.                 if( (uint64_t)( i_value ) * 1000000 <= i_length )
  514.                     val.i_time = (uint64_t)( i_value ) * 1000000;
  515.                 else
  516.                     val.i_time = i_length;
  517.                 var_Set( p_sys->p_input, "time", val );
  518.                 msg_Dbg( p_intf, "requested seek position: %dsec", i_value );
  519.                 break;
  520.             }
  521.             case VL_TIME_REL_FOR:
  522.             {
  523.                 var_Get( p_sys->p_input, "time", &val );
  524.                 if( (uint64_t)( i_value ) * 1000000 + val.i_time <= i_length )
  525.                 {
  526.                     val.i_time = ((uint64_t)( i_value ) * 1000000) + val.i_time;
  527.                 } else
  528.                 {
  529.                     val.i_time = i_length;
  530.                 }
  531.                 var_Set( p_sys->p_input, "time", val );
  532.                 msg_Dbg( p_intf, "requested seek position forward: %dsec", i_value );
  533.                 break;
  534.             }
  535.             case VL_TIME_REL_BACK:
  536.             {
  537.                 var_Get( p_sys->p_input, "time", &val );
  538.                 if( (int64_t)( i_value ) * 1000000 > val.i_time )
  539.                 {
  540.                     val.i_time = 0;
  541.                 } else
  542.                 {
  543.                     val.i_time = val.i_time - ((uint64_t)( i_value ) * 1000000);
  544.                 }
  545.                 var_Set( p_sys->p_input, "time", val );
  546.                 msg_Dbg( p_intf, "requested seek position backward: %dsec", i_value );
  547.                 break;
  548.             }
  549.             case POSITION_ABSOLUTE:
  550.             {
  551.                 val.f_float = __MIN( __MAX( ((float) i_value ) / 100.0 ,
  552.                                             0.0 ), 100.0 );
  553.                 var_Set( p_sys->p_input, "position", val );
  554.                 msg_Dbg( p_intf, "requested seek percent: %d%%", i_value );
  555.                 break;
  556.             }
  557.             case POSITION_REL_FOR:
  558.             {
  559.                 var_Get( p_sys->p_input, "position", &val );
  560.                 val.f_float += __MIN( __MAX( ((float) i_value ) / 100.0,
  561.                                              0.0 ) , 100.0 );
  562.                 var_Set( p_sys->p_input, "position", val );
  563.                 msg_Dbg( p_intf, "requested seek percent forward: %d%%",
  564.                          i_value );
  565.                 break;
  566.             }
  567.             case POSITION_REL_BACK:
  568.             {
  569.                 var_Get( p_sys->p_input, "position", &val );
  570.                 val.f_float -= __MIN( __MAX( ((float) i_value ) / 100.0,
  571.                                              0.0 ) , 100.0 );
  572.                 var_Set( p_sys->p_input, "position", val );
  573.                 msg_Dbg( p_intf, "requested seek percent backward: %d%%",
  574.                          i_value );
  575.                 break;
  576.             }
  577.             default:
  578.             {
  579.                 msg_Dbg( p_intf, "invalid seek request" );
  580.                 break;
  581.             }
  582.         }
  583.     }
  584. #undef POSITION_ABSOLUTE
  585. #undef POSITION_REL_FOR
  586. #undef POSITION_REL_BACK
  587. #undef VL_TIME_ABSOLUTE
  588. #undef VL_TIME_REL_FOR
  589. #undef VL_TIME_REL_BACK
  590. }
  591. /****************************************************************************
  592.  * URI Parsing functions
  593.  ****************************************************************************/
  594. int TestURIParam( char *psz_uri, const char *psz_name )
  595. {
  596.     char *p = psz_uri;
  597.     while( (p = strstr( p, psz_name )) )
  598.     {
  599.         /* Verify that we are dealing with a post/get argument */
  600.         if( (p == psz_uri || *(p - 1) == '&' || *(p - 1) == 'n')
  601.               && p[strlen(psz_name)] == '=' )
  602.         {
  603.             return true;
  604.         }
  605.         p++;
  606.     }
  607.     return false;
  608. }
  609. static const char *FindURIValue( const char *psz_uri, const char *restrict psz_name,
  610.                            size_t *restrict p_len )
  611. {
  612.     const char *p = psz_uri, *end;
  613.     size_t len;
  614.     while( (p = strstr( p, psz_name )) )
  615.     {
  616.         /* Verify that we are dealing with a post/get argument */
  617.         if( (p == psz_uri || *(p - 1) == '&' || *(p - 1) == 'n')
  618.               && p[strlen(psz_name)] == '=' )
  619.             break;
  620.         p++;
  621.     }
  622.     if( p == NULL )
  623.     {
  624.         *p_len = 0;
  625.         return NULL;
  626.     }
  627.     p += strlen( psz_name );
  628.     if( *p == '=' ) p++;
  629.     if( ( end = strchr( p, 'n' ) ) != NULL )
  630.     {
  631.         /* POST method */
  632.         if( ( end > p ) && ( end[-1] == 'r' ) )
  633.             end--;
  634.         len = end - p;
  635.     }
  636.     else
  637.     {
  638.         /* GET method */
  639.         if( ( end = strchr( p, '&' ) ) != NULL )
  640.             len = end - p;
  641.         else
  642.             len = strlen( p );
  643.     }
  644.     *p_len = len;
  645.     return p;
  646. }
  647. const char *ExtractURIValue( const char *restrict psz_uri,
  648.                            const char *restrict psz_name,
  649.                            char *restrict psz_buf, size_t bufsize )
  650. {
  651.     size_t len;
  652.     const char *psz_value = FindURIValue( psz_uri, psz_name, &len );
  653.     const char *psz_next;
  654.     if( psz_value == NULL )
  655.     {
  656.         if( bufsize > 0 )
  657.             *psz_buf = '';
  658.         return NULL;
  659.     }
  660.     psz_next = psz_value + len;
  661.     if( len >= bufsize )
  662.         len = bufsize - 1;
  663.     if( len > 0 )
  664.         strncpy( psz_buf, psz_value, len );
  665.     if( bufsize > 0 )
  666.         psz_buf[len] = '';
  667.     return psz_next;
  668. }
  669. char *ExtractURIString( const char *restrict psz_uri,
  670.                             const char *restrict psz_name )
  671. {
  672.     size_t len;
  673.     const char *psz_value = FindURIValue( psz_uri, psz_name, &len );
  674.     if( psz_value == NULL )
  675.         return NULL;
  676.     char *res = malloc( len + 1 );
  677.     if( res == NULL )
  678.         return NULL;
  679.     memcpy( res, psz_value, len );
  680.     res[len] = '';
  681.     return res;
  682. }
  683. /* Since the resulting string is smaller we can work in place, so it is
  684.  * permitted to have psz == new. new points to the first word of the
  685.  * string, the function returns the remaining string. */
  686. char *FirstWord( char *psz, char *new )
  687. {
  688.     bool b_end;
  689.     while( *psz == ' ' )
  690.         psz++;
  691.     while( *psz != '' && *psz != ' ' )
  692.     {
  693.         if( *psz == ''' )
  694.         {
  695.             char c = *psz++;
  696.             while( *psz != '' && *psz != c )
  697.             {
  698.                 if( *psz == '\' && psz[1] != '' )
  699.                     psz++;
  700.                 *new++ = *psz++;
  701.             }
  702.             if( *psz == c )
  703.                 psz++;
  704.         }
  705.         else
  706.         {
  707.             if( *psz == '\' && psz[1] != '' )
  708.                 psz++;
  709.             *new++ = *psz++;
  710.         }
  711.     }
  712.     b_end = !*psz;
  713.     *new++ = '';
  714.     if( !b_end )
  715.         return psz + 1;
  716.     else
  717.         return NULL;
  718. }
  719. /**********************************************************************
  720.  * MRLParse: parse the MRL, find the MRL string and the options,
  721.  * create an item with all information in it, and return the item.
  722.  * return NULL if there is an error.
  723.  **********************************************************************/
  724. /* Function analog to FirstWord except that it relies on colon instead
  725.  * of space to delimit option boundaries. */
  726. static char *FirstOption( char *psz, char *new )
  727. {
  728.     bool b_end, b_start = true;
  729.     while( *psz == ' ' )
  730.         psz++;
  731.     while( *psz != '' && (*psz != ' ' || psz[1] != ':') )
  732.     {
  733.         if( *psz == ''' )
  734.         {
  735.             char c = *psz++;
  736.             while( *psz != '' && *psz != c )
  737.             {
  738.                 if( *psz == '\' && psz[1] != '' )
  739.                     psz++;
  740.                 *new++ = *psz++;
  741.                 b_start = false;
  742.             }
  743.             if( *psz == c )
  744.                 psz++;
  745.         }
  746.         else
  747.         {
  748.             if( *psz == '\' && psz[1] != '' )
  749.                 psz++;
  750.             *new++ = *psz++;
  751.             b_start = false;
  752.         }
  753.     }
  754.     b_end = !*psz;
  755.     if ( !b_start )
  756.         while (new[-1] == ' ')
  757.             new--;
  758.     *new++ = '';
  759.     if( !b_end )
  760.         return psz + 1;
  761.     else
  762.         return NULL;
  763. }
  764. input_item_t *MRLParse( intf_thread_t *p_intf, const char *mrl,
  765.                                    char *psz_name )
  766. {
  767.     char *psz = strdup( mrl ), *s_mrl = psz, *s_temp;
  768.     if( psz == NULL )
  769.         return NULL;
  770.     /* extract the mrl */
  771.     s_temp = FirstOption( s_mrl, s_mrl );
  772.     if( s_temp == NULL )
  773.     {
  774.         s_temp = s_mrl + strlen( s_mrl );
  775.     }
  776.     input_item_t *p_input = input_item_New( p_intf, s_mrl, psz_name );
  777.     if( p_input == NULL )
  778.         return NULL;
  779.     s_mrl = s_temp;
  780.     /* now we can take care of the options */
  781.     while ( *s_mrl != '' )
  782.     {
  783.         s_temp = FirstOption( s_mrl, s_mrl );
  784.         if( s_mrl == '' )
  785.             break;
  786.         if( s_temp == NULL )
  787.         {
  788.             s_temp = s_mrl + strlen( s_mrl );
  789.         }
  790.         input_item_AddOption( p_input, s_mrl, VLC_INPUT_OPTION_TRUSTED );
  791.         s_mrl = s_temp;
  792.     }
  793.     return p_input;
  794. }
  795. /**********************************************************************
  796.  * RealPath: parse ../, ~ and path stuff
  797.  **********************************************************************/
  798. char *RealPath( const char *psz_src )
  799. {
  800.     char *psz_dir;
  801.     char *p;
  802.     int i_len = strlen(psz_src);
  803.     psz_dir = malloc( i_len + 2 );
  804.     strcpy( psz_dir, psz_src );
  805.     /* Add a trailing sep to ease the .. step */
  806.     psz_dir[i_len] = DIR_SEP_CHAR;
  807.     psz_dir[i_len + 1] = '';
  808. #if (DIR_SEP_CHAR != '/')
  809.     /* Convert all / to native separator */
  810.     p = psz_dir;
  811.     while( (p = strchr( p, '/' )) != NULL )
  812.     {
  813.         *p = DIR_SEP_CHAR;
  814.     }
  815. #endif
  816.     /* FIXME: this could be O(N) rather than O(N²)... */
  817.     /* Remove multiple separators and /./ */
  818.     p = psz_dir;
  819.     while( (p = strchr( p, DIR_SEP_CHAR )) != NULL )
  820.     {
  821.         if( p[1] == DIR_SEP_CHAR )
  822.             memmove( &p[1], &p[2], strlen(&p[2]) + 1 );
  823.         else if( p[1] == '.' && p[2] == DIR_SEP_CHAR )
  824.             memmove( &p[1], &p[3], strlen(&p[3]) + 1 );
  825.         else
  826.             p++;
  827.     }
  828.     if( psz_dir[0] == '~' )
  829.     {
  830.         char *dir;
  831.         asprintf( &dir, "%s%s", config_GetHomeDir(), psz_dir + 1 );
  832.         free( psz_dir );
  833.         psz_dir = dir;
  834.     }
  835.     if( strlen(psz_dir) > 2 )
  836.     {
  837.         /* Fix all .. dir */
  838.         p = psz_dir + 3;
  839.         while( (p = strchr( p, DIR_SEP_CHAR )) != NULL )
  840.         {
  841.             if( p[-1] == '.' && p[-2] == '.' && p[-3] == DIR_SEP_CHAR )
  842.             {
  843.                 char *q;
  844.                 p[-3] = '';
  845.                 if( (q = strrchr( psz_dir, DIR_SEP_CHAR )) != NULL )
  846.                 {
  847.                     memmove( q + 1, p + 1, strlen(p + 1) + 1 );
  848.                     p = q + 1;
  849.                 }
  850.                 else
  851.                 {
  852.                     memmove( psz_dir, p, strlen(p) + 1 );
  853.                     p = psz_dir + 3;
  854.                 }
  855.             }
  856.             else
  857.                 p++;
  858.         }
  859.     }
  860.     /* Remove trailing sep if there are at least 2 sep in the string
  861.      * (handles the C: stuff) */
  862.     p = strrchr( psz_dir, DIR_SEP_CHAR );
  863.     if( p != NULL && p[1] == '' && p != strchr( psz_dir, DIR_SEP_CHAR ) )
  864.         *p = '';
  865.     return psz_dir;
  866. }