From ae6fe977cf9f52e274d2cca0ec4cbc161057caef Mon Sep 17 00:00:00 2001 From: Miguel Freitas Date: Sat, 4 Feb 2006 12:08:22 +0000 Subject: add browsable capability to input_smb by Xavier CVS patchset: 7864 CVS date: 2006/02/04 12:08:22 --- src/input/input_smb.c | 269 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 267 insertions(+), 2 deletions(-) diff --git a/src/input/input_smb.c b/src/input/input_smb.c index 0ecc6dfba..8c1c62625 100644 --- a/src/input/input_smb.c +++ b/src/input/input_smb.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: input_smb.c,v 1.6 2006/02/02 22:35:30 f1rmb Exp $ + * $Id: input_smb.c,v 1.7 2006/02/04 12:08:22 miguelfreitas Exp $ */ @@ -38,9 +38,14 @@ #include #endif +#define MAXFILES 65535 + typedef struct { input_class_t input_class; xine_t *xine; + + int mrls_allocated_entries; + xine_mrl_t **mrls; } smb_input_class_t; typedef struct { @@ -155,6 +160,266 @@ static const char return "smb"; } +/* + * Sorting function, it comes from GNU fileutils package. + */ +#define S_N 0x0 +#define S_I 0x4 +#define S_F 0x8 +#define S_Z 0xC +#define CMP 2 +#define LEN 3 +#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9) +static int _strverscmp(const char *s1, const char *s2) { + const unsigned char *p1 = (const unsigned char *) s1; + const unsigned char *p2 = (const unsigned char *) s2; + unsigned char c1, c2; + int state; + int diff; + static const unsigned int next_state[] = { + S_N, S_I, S_Z, S_N, + S_N, S_I, S_I, S_I, + S_N, S_F, S_F, S_F, + S_N, S_F, S_Z, S_Z + }; + static const int result_type[] = { + CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP, + CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, + CMP, -1, -1, CMP, 1, LEN, LEN, CMP, + 1, LEN, LEN, CMP, CMP, CMP, CMP, CMP, + CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP, + CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, + CMP, 1, 1, CMP, -1, CMP, CMP, CMP, + -1, CMP, CMP, CMP + }; + + if(p1 == p2) + return 0; + + c1 = *p1++; + c2 = *p2++; + + state = S_N | ((c1 == '0') + (ISDIGIT(c1) != 0)); + + while((diff = c1 - c2) == 0 && c1 != '\0') { + state = next_state[state]; + c1 = *p1++; + c2 = *p2++; + state |= (c1 == '0') + (ISDIGIT(c1) != 0); + } + + state = result_type[state << 2 | ((c2 == '0') + (ISDIGIT(c2) != 0))]; + + switch(state) { + case CMP: + return diff; + + case LEN: + while(ISDIGIT(*p1++)) + if(!ISDIGIT(*p2++)) + return 1; + + return ISDIGIT(*p2) ? -1 : diff; + + default: + return state; + } +} + +/* + * Wrapper to _strverscmp() for qsort() calls, which sort mrl_t type array. + */ +static int _sortfiles_default(const xine_mrl_t *s1, const xine_mrl_t *s2) { + return(_strverscmp(s1->mrl, s2->mrl)); +} + + +static xine_mrl_t **smb_class_get_dir (input_class_t *this_gen, + const char *filename, int *nFiles) { + + smb_input_class_t *this = (smb_input_class_t *) this_gen; + int (*func) () = _sortfiles_default; + unsigned int dir; + struct smbc_dirent *pdirent; + char current_path [XINE_PATH_MAX + 1]; + char current_path_smb [XINE_PATH_MAX + 1]; + int num_files=0; + if (filename != NULL && strlen(filename)>6){ + snprintf(current_path, XINE_PATH_MAX, "%s",filename); + snprintf(current_path_smb, XINE_PATH_MAX, "%s/",current_path); + }else{ + snprintf(current_path, XINE_PATH_MAX, "smb:/"); + snprintf(current_path_smb, XINE_PATH_MAX, "smb://"); + } + + if ((dir = smbc_opendir(current_path_smb)) >= 0){ + xine_mrl_t *dir_files = (xine_mrl_t *) xine_xmalloc(sizeof(xine_mrl_t) * MAXFILES); + xine_mrl_t *norm_files = (xine_mrl_t *) xine_xmalloc(sizeof(xine_mrl_t) * MAXFILES); + int num_dir_files=0; + int num_norm_files=0; + while ((pdirent = smbc_readdir(dir)) != NULL){ + if (pdirent->smbc_type == SMBC_WORKGROUP){ + dir_files[num_dir_files].link = NULL; + dir_files[num_dir_files].type = mrl_file | mrl_file_directory; + dir_files[num_dir_files].origin = strdup(current_path); + dir_files[num_dir_files].mrl = (char *) xine_xmalloc( + strlen(current_path) + 1 + strlen(pdirent->name) + 1); + sprintf(dir_files[num_dir_files].mrl, "%s/%s", current_path, pdirent->name); + dir_files[num_dir_files].size = pdirent->dirlen; + num_dir_files ++; + }else if (pdirent->smbc_type == SMBC_SERVER){ + if (num_dir_files == 0) { + dir_files[num_dir_files].link = NULL; + dir_files[num_dir_files].type = mrl_file | mrl_file_directory; + dir_files[num_dir_files].origin = strdup("smb:/"); + dir_files[num_dir_files].mrl = (char *) xine_xmalloc(strlen("smb:/") + 4); + sprintf(dir_files[num_dir_files].mrl, "%s/%s", "smb:/", ".."); + dir_files[num_dir_files].size = pdirent->dirlen; + num_dir_files ++; + } + dir_files[num_dir_files].link = NULL; + dir_files[num_dir_files].type = mrl_file | mrl_file_directory; + dir_files[num_dir_files].origin = strdup("smb:/"); + dir_files[num_dir_files].mrl = + (char *) xine_xmalloc(strlen("smb:/") + 1 + strlen(pdirent->name) + 1); + sprintf(dir_files[num_dir_files].mrl, "%s/%s", "smb:/", pdirent->name); + dir_files[num_dir_files].size = pdirent->dirlen; + num_dir_files ++; + } else if (pdirent->smbc_type == SMBC_FILE_SHARE){ + if (num_dir_files == 0) { + dir_files[num_dir_files].link = NULL; + dir_files[num_dir_files].type = mrl_file | mrl_file_directory; + dir_files[num_dir_files].origin = strdup(current_path); + dir_files[num_dir_files].mrl = (char *) xine_xmalloc( + strlen(current_path) + 3); + sprintf(dir_files[num_dir_files].mrl, "%s/%s", current_path, ".."); + dir_files[num_dir_files].type |= mrl_file_directory; + dir_files[num_dir_files].size = pdirent->dirlen; + num_dir_files ++; + } + if (pdirent->name[strlen(pdirent->name)-1]!='$'){ + dir_files[num_dir_files].link = NULL; + dir_files[num_dir_files].type = mrl_file | mrl_file_directory; + dir_files[num_dir_files].origin = strdup(current_path); + dir_files[num_dir_files].mrl = (char *) xine_xmalloc( + strlen(current_path) + 1 + strlen(pdirent->name) + 1); + sprintf(dir_files[num_dir_files].mrl, "%s/%s", current_path, pdirent->name); + dir_files[num_dir_files].size = pdirent->dirlen; + num_dir_files ++; + } + } else if (pdirent->smbc_type == SMBC_DIR){ + dir_files[num_dir_files].link = NULL; + dir_files[num_dir_files].type = mrl_file | mrl_file_directory; + dir_files[num_dir_files].origin = strdup(current_path); + dir_files[num_dir_files].mrl = + (char *) xine_xmalloc(strlen(current_path) + 1 + strlen(pdirent->name) + 1); + sprintf(dir_files[num_dir_files].mrl, "%s/%s", current_path, pdirent->name); + dir_files[num_dir_files].size = pdirent->dirlen; + num_dir_files ++; + }else if (pdirent->smbc_type == SMBC_FILE){ + norm_files[num_norm_files].link = NULL; + norm_files[num_norm_files].type = mrl_file | mrl_file_normal; + norm_files[num_norm_files].origin = strdup(current_path); + norm_files[num_norm_files].mrl = + (char *) xine_xmalloc(strlen(current_path) + 1 + strlen(pdirent->name) + 1); + sprintf(norm_files[num_norm_files].mrl, "%s/%s", current_path, pdirent->name); + norm_files[num_norm_files].size = pdirent->dirlen; + num_norm_files ++; + } + } + smbc_closedir(dir); + + if (num_dir_files == 0) { + dir_files[num_dir_files].link = NULL; + dir_files[num_dir_files].origin = strdup(current_path); + dir_files[num_dir_files].mrl = (char *) xine_xmalloc(strlen(current_path) + 4); + sprintf(dir_files[num_dir_files].mrl, "%s/%s", current_path, ".."); + dir_files[num_dir_files].type = mrl_file | mrl_file_directory; + dir_files[num_dir_files].size = 0; + num_dir_files ++; + } + + /* + * Sort arrays + */ + if(num_dir_files) + qsort(dir_files, num_dir_files, sizeof(xine_mrl_t), func); + + if(num_norm_files) + qsort(norm_files, num_norm_files, sizeof(xine_mrl_t), func); + + /* + * Add directories entries + */ + int i; + for(i = 0; i < num_dir_files; i++) { + if (num_files >= this->mrls_allocated_entries) { + ++this->mrls_allocated_entries; + this->mrls = realloc(this->mrls, + (this->mrls_allocated_entries+1) * sizeof(xine_mrl_t*)); + this->mrls[num_files] = (xine_mrl_t *) xine_xmalloc(sizeof(xine_mrl_t)); + }else + memset(this->mrls[num_files], 0, sizeof(xine_mrl_t)); + + MRL_DUPLICATE(&dir_files[i], this->mrls[num_files]); + + num_files++; + } + + /* + * Add other files entries + */ + for(i = 0; i < num_norm_files; i++) { + if(num_files >= this->mrls_allocated_entries) { + ++this->mrls_allocated_entries; + this->mrls = realloc(this->mrls, + (this->mrls_allocated_entries+1) * sizeof(xine_mrl_t*)); + this->mrls[num_files] = (xine_mrl_t *) xine_xmalloc(sizeof(xine_mrl_t)); + }else + memset(this->mrls[num_files], 0, sizeof(xine_mrl_t)); + + MRL_DUPLICATE(&norm_files[i], this->mrls[num_files]); + + num_files++; + } + + /* Some cleanups before leaving */ + for(i = num_dir_files; i == 0; i--) + MRL_ZERO(&dir_files[i]); + free(dir_files); + + for(i = num_norm_files; i == 0; i--) + MRL_ZERO(&norm_files[i]); + free(norm_files); + }else { + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "input_smb: smbc_opendir(\"%s\") failed: %d - %s\n", + current_path, errno, strerror(errno)); + *nFiles = 0; + return NULL; + } + + /* + * Inform caller about files found number. + */ + *nFiles = num_files; + + /* + * Freeing exceeded mrls if exists. + */ + while(this->mrls_allocated_entries > num_files) { + MRL_ZERO(this->mrls[this->mrls_allocated_entries - 1]); + free(this->mrls[this->mrls_allocated_entries--]); + } + + /* + * This is useful to let UI know where it should stops ;-). + */ + this->mrls[num_files] = NULL; + + return this->mrls; +} + static int smb_plugin_get_optional_data (input_plugin_t *this_gen, void *data, int data_type) @@ -253,7 +518,7 @@ static void this->input_class.get_instance = smb_class_get_instance; this->input_class.get_identifier = smb_class_get_identifier; this->input_class.get_description = smb_class_get_description; - this->input_class.get_dir = NULL; + this->input_class.get_dir = smb_class_get_dir; this->input_class.get_autoplay_list = NULL; this->input_class.dispose = smb_class_dispose; this->input_class.eject_media = NULL; -- cgit v1.2.3