1191 lines
32 KiB
C++
1191 lines
32 KiB
C++
//////////////////////////////////////////////////////////////////////////
|
|
/**
|
|
* SigmaPlayer source project - file explorer wrapper impl.
|
|
* \file script-explorer.cpp
|
|
* \author bombur
|
|
* \version 0.1
|
|
* \date 12.10.2006
|
|
*
|
|
* 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, USA.
|
|
*/
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <sys/time.h>
|
|
#include <ctype.h>
|
|
#include <dirent.h>
|
|
|
|
#include <libsp/sp_misc.h>
|
|
#include <libsp/sp_msg.h>
|
|
#include <libsp/sp_cdrom.h>
|
|
#include <libsp/sp_flash.h>
|
|
#include <libsp/sp_fip.h>
|
|
#include <libsp/sp_khwl.h>
|
|
|
|
#include <gui/rect.h>
|
|
#include <gui/image.h>
|
|
#include <gui/text.h>
|
|
#include <gui/console.h>
|
|
#include <mmsl/mmsl.h>
|
|
|
|
#include <settings.h>
|
|
#include <cdda.h>
|
|
#include <script.h>
|
|
#include <script-internal.h>
|
|
|
|
|
|
static const StringPair items_sort_pairs[] =
|
|
{
|
|
{ "none", ITEMS_SORT_NONE },
|
|
{ "normal", ITEMS_SORT_NORMAL },
|
|
{ "inverse", ITEMS_SORT_INVERSE },
|
|
{ "random", ITEMS_SORT_RANDOM },
|
|
{ NULL, -1 },
|
|
};
|
|
|
|
static const StringPair item_type_pairs[] =
|
|
{
|
|
{ "", ITEMS_SORT_NONE },
|
|
{ "file", ITEM_TYPE_FILE },
|
|
{ "track", ITEM_TYPE_TRACK },
|
|
{ "folder", ITEM_TYPE_FOLDER },
|
|
{ "up", ITEM_TYPE_UP },
|
|
{ "dvd", ITEM_TYPE_DVD },
|
|
{ NULL, -1 },
|
|
};
|
|
|
|
// used for items hash
|
|
Item *tmpit = NULL;
|
|
|
|
static int ItemsListCompareFuncNormal(Item **i1, Item **i2)
|
|
{
|
|
return (*i1)->name.CompareNoCase((*i2)->name);
|
|
}
|
|
static int ItemsListCompareFuncReverse(Item **i1, Item **i2)
|
|
{
|
|
return -(*i1)->name.CompareNoCase((*i2)->name);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void ItemsList::Update()
|
|
{
|
|
if (cur >= 0 && cur < items.GetN())
|
|
{
|
|
// get extension
|
|
int eidx = items[cur]->name.ReverseFind('.');
|
|
if (eidx < 0)
|
|
eidx = items[cur]->name.GetLength();
|
|
fname = items[cur]->name.Left(eidx);
|
|
if (fname.FindNoCase("/cdrom/") == 0)
|
|
fname = fname.Mid(7);
|
|
if (fname.FindNoCase("/hdd/") == 0)
|
|
fname = fname.Mid(5);
|
|
if (fname.FindNoCase("/") == 0)
|
|
fname = fname.Mid(1);
|
|
ext = items[cur]->name.Mid(eidx);
|
|
if (itemhash != NULL) // playlist
|
|
path = items[cur]->name;
|
|
else
|
|
path = folder + items[cur]->name;
|
|
type = items[cur]->type;
|
|
filetime = items[cur]->datetime;
|
|
mask_index = items[cur]->mask_index;
|
|
filesize = MAX(items[cur]->size, 0);
|
|
|
|
params->lastitem = items[cur];
|
|
|
|
if (params->curtarget != NULL && params->curtarget->itemhash != NULL)
|
|
{
|
|
tmpit->SetName(path);
|
|
copied = (params->curtarget->itemhash->Get(*tmpit) != NULL);
|
|
}
|
|
} else
|
|
{
|
|
if (cur < 0)
|
|
cur = -1;
|
|
if (cur > items.GetN())
|
|
cur = items.GetN();
|
|
fname = "";
|
|
ext = "";
|
|
path = "";
|
|
type = ITEM_TYPE_NONE;
|
|
copied = FALSE;
|
|
filetime = 0;
|
|
filesize = 0;
|
|
mask_index = 0;
|
|
|
|
params->lastitem = NULL;
|
|
}
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_POSITION);
|
|
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_PATH);
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_FILENAME);
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_EXTENSION);
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_TYPE);
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_COPIED);
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_FILETIME);
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_MASKINDEX);
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_FILESIZE);
|
|
}
|
|
|
|
bool mask_compare(char *str, const SPString & msk)
|
|
{
|
|
// empty mask - not allowed!
|
|
if (msk[0] == '\0')
|
|
return false;
|
|
|
|
// process multiple masks
|
|
char *comma = strchr(msk, ',');
|
|
int mlen = msk.GetLength();
|
|
if (comma != NULL)
|
|
{
|
|
// if one of other masks match
|
|
if (mask_compare(str, SPString(comma + 1)))
|
|
return true;
|
|
mlen = comma - *msk;
|
|
}
|
|
|
|
int end = 0, omaski = 0;
|
|
int len = strlen(str);
|
|
int ml;
|
|
for (int i = 0; i < len && omaski <= mlen; omaski++)
|
|
{
|
|
const char *m = *msk + omaski;
|
|
for (int j = omaski; j < mlen && *m != '*'; j++)
|
|
m++;
|
|
if (*m == '*')
|
|
ml = m - msk - omaski;
|
|
else
|
|
ml = mlen - omaski + 1;
|
|
BOOL fl0 = false;
|
|
for (; i <= end; i++)
|
|
{
|
|
const char *tmp1 = str + i;
|
|
const char *tmp2 = *msk + omaski;
|
|
BOOL fl = true;
|
|
for (int j = 0; (j < ml); j++, tmp1++, tmp2++)
|
|
{
|
|
if (tolower(*tmp1) != tolower(*tmp2 == ',' ? 0 : *tmp2) && *tmp2 != '?')
|
|
{
|
|
fl = false;
|
|
break;
|
|
}
|
|
}
|
|
if (fl)
|
|
{
|
|
omaski += ml;
|
|
i += ml;
|
|
end = len;
|
|
fl0 = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!fl0)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static void items_sub_sort(int idx1, int idx2)
|
|
{
|
|
if (idx1 == idx2)
|
|
return;
|
|
if (params->sort == ITEMS_SORT_NORMAL)
|
|
{
|
|
params->curitem->items.Sort(ItemsListCompareFuncNormal, idx1, idx2);
|
|
}
|
|
else if (params->sort == ITEMS_SORT_INVERSE)
|
|
{
|
|
params->curitem->items.Sort(ItemsListCompareFuncReverse, idx1, idx2);
|
|
}
|
|
else if (params->sort == ITEMS_SORT_RANDOM)
|
|
{
|
|
int n = idx2 - idx1 + 1;
|
|
for (int k = idx1; k <= idx2; k++)
|
|
{
|
|
int j;
|
|
// find random swap pos
|
|
do
|
|
{
|
|
j = (rand() % n) + idx1;
|
|
} while (j == k);
|
|
|
|
// swap
|
|
Item *tmp = params->curitem->items[j];
|
|
params->curitem->items[j] = params->curitem->items[k];
|
|
params->curitem->items[k] = tmp;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void items_list_sort()
|
|
{
|
|
params->lastitem = NULL;
|
|
if (params->curitem != NULL && params->sort != ITEMS_SORT_NONE)
|
|
{
|
|
int k, idx1 = 0, idx2 = 0, maxidx = 0;
|
|
// save current index
|
|
bool need_new_idx = params->curitem->cur >= 0 && params->curitem->cur < params->curitem->items.GetN();
|
|
if (need_new_idx)
|
|
{
|
|
params->curitem->items[params->curitem->cur]->oldidx = params->curitem->cur;
|
|
}
|
|
|
|
for (k = 0; k < ITEM_TYPE_MAX && params->filter[k] != ITEM_TYPE_NONE; k++)
|
|
{
|
|
//idx1 = params->curitem->add4types[k];
|
|
idx2 = (k < ITEM_TYPE_MAX && params->filter[k] != ITEM_TYPE_NONE)
|
|
? params->curitem->add4types[k]-1 : params->curitem->items.GetN() - 1;
|
|
if (idx2 + 1 > maxidx)
|
|
maxidx = idx2 + 1;
|
|
if (idx2 < idx1)
|
|
continue;
|
|
items_sub_sort(idx1, idx2);
|
|
idx1 = idx2 + 1;
|
|
}
|
|
if (maxidx < params->curitem->items.GetN())
|
|
items_sub_sort(maxidx, params->curitem->items.GetN() - 1);
|
|
|
|
if (need_new_idx)
|
|
{
|
|
int cur = params->curitem->cur;
|
|
params->curitem->cur = 0;
|
|
for (k = 0; k < params->curitem->items.GetN(); k++)
|
|
{
|
|
if (params->curitem->items[k]->oldidx == cur)
|
|
{
|
|
params->curitem->items[k]->oldidx = -1;
|
|
params->curitem->cur = k;
|
|
break;
|
|
}
|
|
}
|
|
params->curitem->Update();
|
|
}
|
|
}
|
|
}
|
|
|
|
void explorer_get_folder_name(SPString &folder)
|
|
{
|
|
// skip the 'up' folder
|
|
if (folder == ".." || folder.GetLength() < 1)
|
|
return;
|
|
folder.Replace('\\', '/');
|
|
if (folder.Find("/") != 0)
|
|
folder = "/" + folder;
|
|
if (folder.ReverseFind('/') != folder.GetLength() - 1)
|
|
folder = folder + "/";
|
|
}
|
|
|
|
void script_explorer_reset()
|
|
{
|
|
if (params != NULL)
|
|
{
|
|
params->lists.DeleteObjects();
|
|
params->playlists.DeleteObjects();
|
|
params->curtarget = NULL;
|
|
params->curitem = NULL;
|
|
params->lastitem = NULL;
|
|
params->folder = "";
|
|
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_COUNT);
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_FOLDER);
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_DRIVE_LETTER);
|
|
}
|
|
}
|
|
|
|
void on_explorer_get(int var_id, MmslVariable *var, void *, int , MMSL_OBJECT *)
|
|
{
|
|
if (var == NULL)
|
|
return;
|
|
switch (var_id)
|
|
{
|
|
case SCRIPT_VAR_EXPLORER_CHARSET:
|
|
var->Set(params->iso_lang);
|
|
break;
|
|
case SCRIPT_VAR_EXPLORER_FOLDER:
|
|
{
|
|
SPString f = params->folder;
|
|
if (f.ReverseFind('/') == f.GetLength() - 1)
|
|
f = f.Left(f.GetLength() - 1);
|
|
var->Set(f);
|
|
}
|
|
break;
|
|
case SCRIPT_VAR_EXPLORER_DRIVE_LETTER:
|
|
{
|
|
SPString f;
|
|
if (params->folder.FindNoCase("/hdd/") == 0)
|
|
{
|
|
f = params->folder.Mid(5);
|
|
if (f != "")
|
|
{
|
|
static const char led_drive_table[] = { 'A', 'b', 'C', 'd', 'E', 'F', 'G', 'H',
|
|
'I', 'J', 'k', 'L', 'm', 'N', 'O', 'P', 'q', 'r', 'S', 't', 'U', 'v' };
|
|
char ch = (char)toupper(f[0]);
|
|
if (ch > 'A' && ch < sizeof(led_drive_table) + 'A')
|
|
ch = led_drive_table[ch - 'A'];
|
|
f = SPString(ch, 1);
|
|
var->Set(f);
|
|
break;
|
|
}
|
|
}
|
|
var->Set(f);
|
|
}
|
|
break;
|
|
case SCRIPT_VAR_EXPLORER_TARGET:
|
|
{
|
|
SPString f = params->target;
|
|
if (f.ReverseFind('/') == f.GetLength() - 1)
|
|
f = f.Left(f.GetLength() - 1);
|
|
var->Set(f);
|
|
}
|
|
break;
|
|
case SCRIPT_VAR_EXPLORER_FILTER:
|
|
{
|
|
const char *flt[] = { "", "file", "track", "folder", "up", "dvd" };
|
|
SPString filter;
|
|
for (int i = 0; i < ITEM_TYPE_MAX; i++)
|
|
{
|
|
if (params->filter[i] != ITEM_TYPE_NONE)
|
|
{
|
|
if (filter != "")
|
|
filter += ",";
|
|
filter += flt[params->filter[i]];
|
|
}
|
|
}
|
|
|
|
var->Set(filter);
|
|
}
|
|
break;
|
|
case SCRIPT_VAR_EXPLORER_MASK1:
|
|
case SCRIPT_VAR_EXPLORER_MASK2:
|
|
case SCRIPT_VAR_EXPLORER_MASK3:
|
|
case SCRIPT_VAR_EXPLORER_MASK4:
|
|
case SCRIPT_VAR_EXPLORER_MASK5:
|
|
var->Set(params->mask[var_id - SCRIPT_VAR_EXPLORER_MASK1]);
|
|
break;
|
|
case SCRIPT_VAR_EXPLORER_PATH:
|
|
var->Set(params->curitem != NULL ? params->curitem->path : SPString());
|
|
break;
|
|
case SCRIPT_VAR_EXPLORER_FILENAME:
|
|
var->Set(params->curitem != NULL ? params->curitem->fname : SPString());
|
|
break;
|
|
case SCRIPT_VAR_EXPLORER_EXTENSION:
|
|
var->Set(params->curitem != NULL ? params->curitem->ext : SPString());
|
|
break;
|
|
case SCRIPT_VAR_EXPLORER_TYPE:
|
|
{
|
|
int typ = params->curitem != NULL ? params->curitem->type : -1;
|
|
StringPair::Set(var, item_type_pairs, typ);
|
|
}
|
|
break;
|
|
case SCRIPT_VAR_EXPLORER_FILESIZE:
|
|
{
|
|
if (params->curitem == NULL)
|
|
var->Set(0);
|
|
else
|
|
{
|
|
int fsize = (params->curitem->filesize < 0x7fffffff) ?
|
|
(int)params->curitem->filesize : -(int)(params->curitem->filesize/1024);
|
|
var->Set(fsize);
|
|
}
|
|
}
|
|
break;
|
|
case SCRIPT_VAR_EXPLORER_FILETIME:
|
|
{
|
|
static SPString ft;
|
|
ft = "";
|
|
if (params->curitem->filetime != 0)
|
|
ft.Strftime("%d.%m.%Y %H:%M", params->curitem->filetime);
|
|
var->Set(ft);
|
|
}
|
|
break;
|
|
case SCRIPT_VAR_EXPLORER_MASKINDEX:
|
|
var->Set(params->curitem != NULL ? params->curitem->mask_index : 0);
|
|
break;
|
|
case SCRIPT_VAR_EXPLORER_COUNT:
|
|
var->Set(params->curitem != NULL ? params->curitem->items.GetN() : 0);
|
|
break;
|
|
case SCRIPT_VAR_EXPLORER_SORT:
|
|
StringPair::Set(var, items_sort_pairs, params->sort);
|
|
break;
|
|
case SCRIPT_VAR_EXPLORER_POSITION:
|
|
var->Set(params->curitem != NULL ? params->curitem->cur : -1);
|
|
break;
|
|
case SCRIPT_VAR_EXPLORER_COMMAND:
|
|
case SCRIPT_VAR_EXPLORER_FIND:
|
|
var->Set("");
|
|
break;
|
|
case SCRIPT_VAR_EXPLORER_COPIED:
|
|
var->Set(params->curitem != NULL ? params->curitem->copied : 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void on_explorer_set(int var_id, MmslVariable *var, void *, int , MMSL_OBJECT *)
|
|
{
|
|
if (var == NULL)
|
|
return;
|
|
switch (var_id)
|
|
{
|
|
case SCRIPT_VAR_EXPLORER_CHARSET:
|
|
params->iso_lang = var->GetString();
|
|
params->iso_lang_changed = true;
|
|
params->list_changed = true;
|
|
break;
|
|
case SCRIPT_VAR_EXPLORER_FOLDER:
|
|
{
|
|
params->folder = var->GetString();
|
|
if (params->folder.FindNoCase("/cdrom/") == 0 || params->folder.FindNoCase("/hdd/") == 0 ||
|
|
params->folder.FindNoCase("/") == 0)
|
|
params->list_changed = true;
|
|
explorer_get_folder_name(params->folder);
|
|
}
|
|
break;
|
|
case SCRIPT_VAR_EXPLORER_TARGET:
|
|
{
|
|
params->target = var->GetString();
|
|
explorer_get_folder_name(params->target);
|
|
params->curtarget = NULL;
|
|
for (int i = 0; i < params->playlists.GetN(); i++)
|
|
{
|
|
if (params->target.FindNoCase(params->playlists[i]->folder) == 0)
|
|
{
|
|
params->curtarget = params->playlists[i];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case SCRIPT_VAR_EXPLORER_FILTER:
|
|
{
|
|
SPString filter = var->GetString();
|
|
int i;
|
|
for (i = 0; i < ITEM_TYPE_MAX; i++)
|
|
{
|
|
if (filter.FindNoCase("up") == 0)
|
|
params->filter[i] = ITEM_TYPE_UP;
|
|
else if (filter.FindNoCase("folder") == 0)
|
|
params->filter[i] = ITEM_TYPE_FOLDER;
|
|
else if (filter.FindNoCase("file") == 0)
|
|
params->filter[i] = ITEM_TYPE_FILE;
|
|
else if (filter.FindNoCase("track") == 0)
|
|
params->filter[i] = ITEM_TYPE_TRACK;
|
|
else if (filter.FindNoCase("dvd") == 0)
|
|
params->filter[i] = ITEM_TYPE_DVD;
|
|
else
|
|
break;
|
|
int nxt = filter.Find(',');
|
|
if (nxt < 0)
|
|
filter = "";
|
|
filter = filter.Mid(nxt + 1);
|
|
}
|
|
for (; i < ITEM_TYPE_MAX; i++)
|
|
params->filter[i] = ITEM_TYPE_NONE;
|
|
params->list_changed = true;
|
|
}
|
|
break;
|
|
case SCRIPT_VAR_EXPLORER_MASK1:
|
|
case SCRIPT_VAR_EXPLORER_MASK2:
|
|
case SCRIPT_VAR_EXPLORER_MASK3:
|
|
case SCRIPT_VAR_EXPLORER_MASK4:
|
|
case SCRIPT_VAR_EXPLORER_MASK5:
|
|
{
|
|
SPString m = var->GetString();
|
|
|
|
// for easy mask concatenation
|
|
m.TrimLeft();
|
|
m.TrimRight();
|
|
if (m.GetLength() > 0 && m[(int)m.GetLength() - 1] != ',')
|
|
m += SPString(",");
|
|
params->mask[var_id - SCRIPT_VAR_EXPLORER_MASK1] = m;
|
|
|
|
params->allmask = SPString();
|
|
for (int i = 0; i < num_file_masks; i++)
|
|
params->allmask += params->mask[i];
|
|
|
|
params->list_changed = true;
|
|
}
|
|
break;
|
|
case SCRIPT_VAR_EXPLORER_SORT:
|
|
params->sort = (ITEMS_SORT)StringPair::Get(var, items_sort_pairs, ITEMS_SORT_NONE);
|
|
items_list_sort();
|
|
params->list_changed = true;
|
|
break;
|
|
case SCRIPT_VAR_EXPLORER_POSITION:
|
|
if (params->curitem != NULL && params->curitem->items.GetN() > 0)
|
|
{
|
|
params->curitem->cur = var->GetInteger();
|
|
params->curitem->Update();
|
|
}
|
|
break;
|
|
case SCRIPT_VAR_EXPLORER_COMMAND:
|
|
{
|
|
// our generated random indexes aren't valid any more...
|
|
if (params->curitem != NULL)
|
|
{
|
|
if (params->list_changed)
|
|
{
|
|
SPSafeDeleteArray(params->curitem->random_idx);
|
|
SPSafeDeleteArray(params->curitem->random_ridx);
|
|
params->curitem->cur_random_pos = -1;
|
|
params->list_changed = false;
|
|
}
|
|
}
|
|
|
|
SPString cmd = var->GetString();
|
|
if (cmd.CompareNoCase("update") == 0)
|
|
{
|
|
int i;
|
|
params->curitem = NULL;
|
|
|
|
msg("Explorer: Update!\n");
|
|
|
|
if (params->folder == "..")
|
|
{
|
|
if (params->lists.GetN() > 1)
|
|
{
|
|
int idx = params->lists.GetN() - 1;
|
|
SPSafeDelete(params->lists[idx]);
|
|
params->lists.Remove(idx);
|
|
|
|
// if we don't need update
|
|
if (params->lists[idx - 1]->allmask.CompareNoCase(params->allmask) != 0)
|
|
{
|
|
params->folder = params->lists[idx - 1]->folder;
|
|
} else
|
|
{
|
|
params->curitem = params->lists[idx - 1];
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_COUNT);
|
|
params->curitem->Update();
|
|
params->folder = params->curitem->folder;
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_FOLDER);
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_DRIVE_LETTER);
|
|
break;
|
|
}
|
|
} else
|
|
{
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_COUNT);
|
|
params->folder = "";
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_FOLDER);
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_DRIVE_LETTER);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// translate virtual path
|
|
SPString oldfolder = params->folder;
|
|
params->folder = cdrom_getrealpath(params->folder);
|
|
if (params->folder != oldfolder)
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_FOLDER);
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_DRIVE_LETTER);
|
|
|
|
if (params->folder.FindNoCase("/cdrom/") == 0 || params->folder.FindNoCase("/hdd/") == 0)
|
|
{
|
|
int from_which = -1;
|
|
for (i = params->lists.GetN() - 1; i >= 0; i--)
|
|
{
|
|
if (params->folder.FindNoCase(params->lists[i]->folder) == 0)
|
|
{
|
|
// exactly the same!
|
|
if (params->folder.CompareNoCase(params->lists[i]->folder) == 0)
|
|
{
|
|
#if 0
|
|
params->curitem = params->lists[i];
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_COUNT);
|
|
params->curitem->Update();
|
|
params->folder = params->curitem->folder;
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_FOLDER);
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_DRIVE_LETTER);
|
|
break;
|
|
#endif
|
|
from_which = i - 1;
|
|
}
|
|
else
|
|
from_which = i;
|
|
break;
|
|
}
|
|
}
|
|
// delete sub-lists
|
|
for (i = params->lists.GetN() - 1; i > from_which; i--)
|
|
{
|
|
SPSafeDelete(params->lists[i]);
|
|
params->lists.Remove(i);
|
|
}
|
|
}
|
|
|
|
// detect source type
|
|
if (params->folder.FindNoCase("/cdrom/") == 0 || params->folder.FindNoCase("/hdd/") == 0 ||
|
|
params->folder == "/")
|
|
{
|
|
params->curitem = new ItemsList();
|
|
|
|
// read items
|
|
explorer_get_folder_name(params->folder);
|
|
params->curitem->folder = params->folder;
|
|
params->curitem->allmask = params->allmask;
|
|
for (i = 0; i < num_file_masks; i++)
|
|
params->curitem->mask[i] = params->mask[i];
|
|
|
|
srand((unsigned int)time(NULL));
|
|
|
|
// first, add audio tracks (for root folder only!)
|
|
char tmp[10];
|
|
if (params->folder.CompareNoCase("/cdrom/") == 0)
|
|
{
|
|
Cdda *cdda = cdda_open();
|
|
if (cdda != NULL)
|
|
{
|
|
for (i = 0; i < cdda->tracks.GetN(); i++)
|
|
{
|
|
Item *it = new Item();
|
|
it->parent = params->curitem;
|
|
sprintf(tmp, "%02d.cda", i + 1);
|
|
// we don't need hash for '/cdrom' lists
|
|
if (params->curitem->itemhash == NULL)
|
|
{
|
|
it->name = tmp;
|
|
it->namehash = 0;
|
|
} else
|
|
it->SetName(tmp);
|
|
it->datetime = 0;
|
|
it->mask_index = 0;
|
|
it->size = 0;
|
|
it->type = ITEM_TYPE_TRACK;
|
|
bool was = false, filterset = false;
|
|
for (int ins = 0; ins < ITEM_TYPE_MAX; ins++)
|
|
{
|
|
if (params->filter[ins] != ITEM_TYPE_NONE)
|
|
filterset = true;
|
|
if (params->filter[ins] == ITEM_TYPE_TRACK)
|
|
{
|
|
params->curitem->items.Insert(it, params->curitem->add4types[ins]);
|
|
was = true;
|
|
}
|
|
if (was)
|
|
params->curitem->add4types[ins]++;
|
|
}
|
|
if (!filterset)
|
|
params->curitem->items.Add(it);
|
|
else if (!was)
|
|
delete it;
|
|
}
|
|
}
|
|
}
|
|
|
|
//if (has_data)
|
|
{
|
|
if (!cdrom_ismounted() || params->iso_lang_changed)
|
|
{
|
|
cdrom_mount(params->iso_lang, FALSE);
|
|
params->iso_lang_changed = false;
|
|
}
|
|
|
|
// determine DVD folder
|
|
bool is_dvd = false;
|
|
int p = params->folder.FindNoCase("VIDEO_TS/");
|
|
if (p >= 0 && p == params->folder.GetLength() - 9)
|
|
{
|
|
is_dvd = true;
|
|
}
|
|
|
|
bool root_folder = (params->folder == "/");
|
|
|
|
DIR *dir = cdrom_opendir(params->folder);
|
|
static char path[4097];
|
|
strcpy(path, params->folder);
|
|
int path_add = strlen(path);
|
|
if (path_add < 4000)
|
|
while (dir != NULL)
|
|
{
|
|
struct dirent *d = cdrom_readdir(dir);
|
|
if (d == NULL)
|
|
break;
|
|
if (d->d_name[0] == '.' && d->d_name[1] == '\0')
|
|
continue;
|
|
struct stat64 statbuf;
|
|
|
|
strcpy(path + path_add, d->d_name);
|
|
int mask_index = 0;
|
|
if (cdrom_stat(path, &statbuf) < 0)
|
|
{
|
|
msg("Cannot stat %s\n", path);
|
|
statbuf.st_mode = 0;
|
|
}
|
|
ITEM_TYPE ittype;
|
|
if (!root_folder && d->d_name[0] == '.' && d->d_name[1] == '.' && d->d_name[2] == '\0')
|
|
{
|
|
if (params->lists.GetN() == 0)
|
|
continue;
|
|
ittype = ITEM_TYPE_UP;
|
|
}
|
|
else if (S_ISDIR(statbuf.st_mode))
|
|
{
|
|
if (d->d_name[0] == '.') // hidden
|
|
continue;
|
|
|
|
// don't show other root folders except mounted ones.
|
|
if (root_folder)
|
|
{
|
|
if (strcasecmp(d->d_name, "cdrom") != 0 &&
|
|
strcasecmp(d->d_name, "hdd") != 0)
|
|
continue;
|
|
}
|
|
ittype = ITEM_TYPE_FOLDER;
|
|
}
|
|
else
|
|
{
|
|
if (is_dvd && (strcasecmp(d->d_name, "VIDEO_TS.IFO") == 0 ||
|
|
strcasecmp(d->d_name, "VIDEO_TS.BUP") == 0))
|
|
{
|
|
ittype = ITEM_TYPE_DVD;
|
|
is_dvd = false;
|
|
} else
|
|
{
|
|
ittype = ITEM_TYPE_FILE;
|
|
BOOL found = FALSE;
|
|
for (int mi = 0; mi < num_file_masks; mi++)
|
|
{
|
|
if (mask_compare(d->d_name, params->mask[mi]))
|
|
{
|
|
found = TRUE;
|
|
mask_index = mi + 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!found)
|
|
continue;
|
|
}
|
|
}
|
|
Item *it = new Item();
|
|
it->parent = params->curitem;
|
|
// we don't need hash for '/cdrom' lists
|
|
if (params->curitem->itemhash == NULL)
|
|
{
|
|
it->name = d->d_name;
|
|
it->namehash = 0;
|
|
} else
|
|
it->SetName(d->d_name);
|
|
it->datetime = statbuf.st_mtime;
|
|
it->size = ittype == ITEM_TYPE_FILE ? statbuf.st_size : 0;
|
|
it->type = ittype;
|
|
it->mask_index = mask_index;
|
|
bool was = false, filterset = false;
|
|
for (int ins = 0; ins < ITEM_TYPE_MAX; ins++)
|
|
{
|
|
if (params->filter[ins] != ITEM_TYPE_NONE)
|
|
filterset = true;
|
|
if (params->filter[ins] == ittype)
|
|
{
|
|
params->curitem->items.Insert(it, params->curitem->add4types[ins]);
|
|
was = true;
|
|
}
|
|
if (was)
|
|
{
|
|
params->curitem->add4types[ins]++;
|
|
}
|
|
}
|
|
if (!filterset)
|
|
params->curitem->items.Add(it);
|
|
else if (!was)
|
|
delete it;
|
|
|
|
// script_update();
|
|
}
|
|
cdrom_closedir(dir);
|
|
}
|
|
|
|
if (params->sort != ITEMS_SORT_NONE)
|
|
items_list_sort();
|
|
|
|
params->lists.Add(params->curitem);
|
|
}
|
|
else if (params->folder.FindNoCase("/dvd/") == 0)
|
|
{
|
|
}
|
|
else // other playlists
|
|
{
|
|
for (i = 0; i < params->playlists.GetN(); i++)
|
|
{
|
|
if (params->folder.FindNoCase(params->playlists[i]->folder) == 0)
|
|
{
|
|
params->curitem = params->playlists[i];
|
|
// If we need to apply a new mask to playlist,
|
|
// we use actual list in itemhash to create filtered items list.
|
|
if (params->curitem->allmask.CompareNoCase(params->allmask) != 0
|
|
&& params->curitem->itemhash != NULL)
|
|
{
|
|
params->curitem->items.Clear();
|
|
Item *cur = params->curitem->itemhash->GetFirst();
|
|
while (cur != NULL)
|
|
{
|
|
if (mask_compare(cur->name, params->allmask))
|
|
params->curitem->items.Add(cur);
|
|
cur = params->curitem->itemhash->GetNext(*cur);
|
|
}
|
|
params->curitem->allmask = params->allmask;
|
|
for (int mi = 0; mi < num_file_masks; mi++)
|
|
params->curitem->mask[mi] = params->mask[mi];
|
|
// we must apply sorting because hash list is unordered.
|
|
ITEMS_SORT oldsort = params->sort;
|
|
if (params->sort == ITEMS_SORT_NONE)
|
|
params->sort = ITEMS_SORT_NORMAL;
|
|
items_list_sort();
|
|
params->sort = oldsort;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_COUNT);
|
|
|
|
if (params->curitem != NULL)
|
|
{
|
|
Item *lastit = params->lastitem;
|
|
params->curitem->cur = 0;
|
|
params->curitem->Update();
|
|
if (lastit != NULL)
|
|
params->lastitem = lastit;
|
|
}
|
|
}
|
|
else if (cmd.CompareNoCase("first") == 0)
|
|
{
|
|
if (params->curitem != NULL && params->curitem->items.GetN() > 0)
|
|
{
|
|
params->curitem->cur = 0;
|
|
params->curitem->Update();
|
|
}
|
|
}
|
|
else if (cmd.CompareNoCase("last") == 0)
|
|
{
|
|
if (params->curitem != NULL && params->curitem->items.GetN() > 0)
|
|
{
|
|
params->curitem->cur = params->curitem->items.GetN() - 1;
|
|
params->curitem->Update();
|
|
}
|
|
}
|
|
else if (cmd.CompareNoCase("next") == 0)
|
|
{
|
|
if (params->curitem != NULL && params->curitem->items.GetN() > 0 && params->curitem->cur < params->curitem->items.GetN())
|
|
{
|
|
params->curitem->cur++;
|
|
params->curitem->Update();
|
|
}
|
|
}
|
|
else if (cmd.CompareNoCase("prev") == 0)
|
|
{
|
|
if (params->curitem != NULL && params->curitem->items.GetN() > 0 && params->curitem->cur >= 0)
|
|
{
|
|
params->curitem->cur--;
|
|
params->curitem->Update();
|
|
}
|
|
}
|
|
else if (cmd.CompareNoCase("randomize") == 0)
|
|
{
|
|
if (params->curitem != NULL && params->curitem->items.GetN() > 0)
|
|
{
|
|
int k, n = params->curitem->items.GetN();
|
|
SPSafeDeleteArray(params->curitem->random_idx);
|
|
SPSafeDeleteArray(params->curitem->random_ridx);
|
|
params->curitem->random_idx = new int [n];
|
|
params->curitem->random_ridx = new int [n];
|
|
for (k = 0; k < n; k++)
|
|
params->curitem->random_idx[k] = k;
|
|
if (n > 1)
|
|
for (k = 0; k < n; k++)
|
|
{
|
|
int j; // find random swap pos
|
|
do
|
|
{
|
|
j = (rand() % n);
|
|
} while (j == k);
|
|
// swap
|
|
int tmp = params->curitem->random_idx[j];
|
|
params->curitem->random_idx[j] = params->curitem->random_idx[k];
|
|
params->curitem->random_idx[k] = tmp;
|
|
}
|
|
for (k = 0; k < n; k++)
|
|
params->curitem->random_ridx[params->curitem->random_idx[k]] = k;
|
|
params->curitem->cur_random_pos = 0;
|
|
params->curitem->cur = params->curitem->random_idx[params->curitem->cur_random_pos];
|
|
params->curitem->Update();
|
|
}
|
|
}
|
|
else if (cmd.CompareNoCase("nextrandom") == 0 || cmd.CompareNoCase("prevrandom") == 0)
|
|
{
|
|
if (params->curitem != NULL && params->curitem->items.GetN() > 0)
|
|
{
|
|
if (params->curitem->random_idx != NULL && params->curitem->random_ridx != NULL)
|
|
{
|
|
if (params->curitem->cur >= 0 && params->curitem->cur < params->curitem->items.GetN())
|
|
params->curitem->cur_random_pos = params->curitem->random_ridx[params->curitem->cur];
|
|
|
|
if (cmd.CompareNoCase("nextrandom") == 0)
|
|
params->curitem->cur_random_pos++;
|
|
else
|
|
params->curitem->cur_random_pos--;
|
|
|
|
if (params->curitem->cur_random_pos < 0 || params->curitem->cur_random_pos >= params->curitem->items.GetN())
|
|
{
|
|
params->curitem->cur = -1;
|
|
params->curitem->cur_random_pos = -1;
|
|
} else
|
|
{
|
|
params->curitem->cur = params->curitem->random_idx[params->curitem->cur_random_pos];
|
|
}
|
|
params->curitem->Update();
|
|
}
|
|
}
|
|
|
|
}
|
|
else if (cmd.CompareNoCase("remove") == 0)
|
|
{
|
|
if (params->curitem != NULL && params->curitem->items.GetN() > 0 &&
|
|
params->curitem->cur >= 0 && params->curitem->cur < params->curitem->items.GetN())
|
|
{
|
|
if (params->curitem->itemhash != NULL)
|
|
params->curitem->itemhash->Remove(*params->curitem->items[params->curitem->cur]);
|
|
SPSafeDelete(params->curitem->items[params->curitem->cur]);
|
|
params->curitem->items.Remove(params->curitem->cur);
|
|
if (params->curitem->cur == params->curitem->items.GetN() - 1)
|
|
params->curitem->cur--;
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_COUNT);
|
|
params->curitem->Update();
|
|
}
|
|
}
|
|
else if (cmd.CompareNoCase("removeall") == 0)
|
|
{
|
|
if (params->curitem != NULL)
|
|
{
|
|
if (params->curitem->itemhash != NULL)
|
|
params->curitem->itemhash->Clear();
|
|
params->curitem->items.DeleteObjects();
|
|
params->curitem->cur = -1;
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_COUNT);
|
|
params->curitem->Update();
|
|
}
|
|
}
|
|
else if (cmd.CompareNoCase("copy") == 0 || cmd.CompareNoCase("copyall") == 0)
|
|
{
|
|
// first, find existing play-list
|
|
explorer_get_folder_name(params->target);
|
|
|
|
int i;
|
|
ItemsList *pl = NULL;
|
|
for (i = params->playlists.GetN() - 1; i >= 0; i--)
|
|
{
|
|
// exactly the same!
|
|
if (params->target.CompareNoCase(params->playlists[i]->folder) == 0)
|
|
{
|
|
pl = params->playlists[i];
|
|
break;
|
|
}
|
|
}
|
|
if (pl == NULL) // create a new play-list
|
|
{
|
|
pl = new ItemsList();
|
|
if (pl == NULL)
|
|
break;
|
|
pl->allmask = params->allmask;
|
|
for (int mi = 0; mi < num_file_masks; mi++)
|
|
pl->mask[mi] = params->mask[mi];
|
|
pl->folder = params->target;
|
|
|
|
pl->itemhash = new SPHashListAbstract<Item, Item>(items_num_hash);
|
|
|
|
params->playlists.Add(pl);
|
|
}
|
|
params->curtarget = pl;
|
|
if (params->curitem == NULL || pl == params->curitem)
|
|
{
|
|
msg_error("Cannot copy items from current source.\n");
|
|
break;
|
|
}
|
|
bool copyall = cmd.CompareNoCase("copyall") == 0;
|
|
|
|
if (!copyall)
|
|
{
|
|
if (params->curitem->cur < 0 || params->curitem->cur >= params->curitem->items.GetN())
|
|
{
|
|
msg_error("Cannot copy current item.\n");
|
|
break;
|
|
}
|
|
i = params->curitem->cur;
|
|
} else
|
|
i = 0;
|
|
for (; i < params->curitem->items.GetN(); i++)
|
|
{
|
|
Item *srcit = params->curitem->items[i];
|
|
if (srcit != NULL && (srcit->type == ITEM_TYPE_FILE || srcit->type == ITEM_TYPE_TRACK))
|
|
{
|
|
// check if item already exists
|
|
Item *item = NULL;
|
|
static SPString nam;
|
|
nam = params->folder + srcit->name;
|
|
if (pl->itemhash != NULL)
|
|
{
|
|
tmpit->SetName(nam);
|
|
item = pl->itemhash->Get(*tmpit);
|
|
}
|
|
// not in the playlist yet.
|
|
if (item == NULL)
|
|
{
|
|
item = new Item();
|
|
item->SetName(nam);
|
|
item->type = srcit->type;
|
|
item->datetime = srcit->datetime;
|
|
item->mask_index = srcit->mask_index;
|
|
item->size = srcit->size;
|
|
item->parent = srcit->parent; // inherit parent
|
|
pl->itemhash->Add(item);
|
|
|
|
srcit->playlist = pl;
|
|
srcit->playlist_idx = pl->items.Add(item);
|
|
if (i == params->curitem->cur)
|
|
params->curitem->Update();
|
|
}
|
|
}
|
|
if (!copyall)
|
|
break;
|
|
}
|
|
}
|
|
else if (cmd.CompareNoCase("targetremove") == 0 || cmd.CompareNoCase("targetremoveall") == 0)
|
|
{
|
|
// first, find existing play-list
|
|
explorer_get_folder_name(params->target);
|
|
|
|
ItemsList *pl = NULL;
|
|
for (int i = params->playlists.GetN() - 1; i >= 0; i--)
|
|
{
|
|
// exactly the same!
|
|
if (params->target.CompareNoCase(params->playlists[i]->folder) == 0)
|
|
{
|
|
pl = params->playlists[i];
|
|
break;
|
|
}
|
|
}
|
|
if (pl == NULL) // create a new play-list
|
|
{
|
|
msg_error("Cannot find target playlist.\n");
|
|
break;
|
|
}
|
|
params->curtarget = pl;
|
|
if (params->curitem == NULL)
|
|
{
|
|
msg_error("Cannot use items from current source for removing.\n");
|
|
break;
|
|
}
|
|
|
|
bool removed = false;
|
|
if (cmd.CompareNoCase("targetremoveall") == 0)
|
|
{
|
|
pl->itemhash->Clear();
|
|
pl->items.DeleteObjects();
|
|
removed = true;
|
|
} else
|
|
{
|
|
|
|
if (params->curitem->cur < 0 || params->curitem->cur >= params->curitem->items.GetN())
|
|
{
|
|
msg_error("Cannot remove current item from target playlist.\n");
|
|
break;
|
|
}
|
|
Item *srcit = params->curitem->items[params->curitem->cur];
|
|
if (srcit != NULL)
|
|
{
|
|
// check if item already exists
|
|
Item *item = NULL;
|
|
SPString nam = params->folder + srcit->name;
|
|
if (pl->itemhash != NULL)
|
|
{
|
|
tmpit->SetName(nam);
|
|
item = pl->itemhash->Get(*tmpit);
|
|
}
|
|
// not in the playlist yet.
|
|
if (item == NULL)
|
|
{
|
|
msg_error("Cannot find current item in the target playlist.\n");
|
|
break;
|
|
}
|
|
pl->itemhash->Remove(*item);
|
|
// find item in the linear list
|
|
for (int i = 0; i < pl->items.GetN(); i++)
|
|
{
|
|
if (pl->items[i] == item)
|
|
{
|
|
SPSafeDelete(pl->items[i]);
|
|
pl->items.Remove(i);
|
|
removed = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (removed)
|
|
{
|
|
if (params->curitem == pl)
|
|
{
|
|
if (params->curitem->cur == params->curitem->items.GetN() - 1)
|
|
params->curitem->cur--;
|
|
mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_COUNT);
|
|
}
|
|
params->curitem->Update();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case SCRIPT_VAR_EXPLORER_FIND:
|
|
{
|
|
SPString fpath = var->GetString();
|
|
if (params->curitem != NULL && params->curitem->items.GetN() > 0)
|
|
{
|
|
// first, a little optimization for current items in playlist
|
|
if (params->lastitem != NULL && params->lastitem->parent != NULL
|
|
&& fpath.CompareNoCase(params->lastitem->parent->folder + params->lastitem->name) == 0
|
|
&& params->lastitem->playlist == params->curitem
|
|
&& params->lastitem->playlist_idx >= 0
|
|
&& params->lastitem->playlist_idx < params->curitem->items.GetN())
|
|
{
|
|
params->curitem->cur = params->lastitem->playlist_idx;
|
|
}
|
|
else
|
|
{
|
|
params->curitem->cur = -1;
|
|
for (int i = 0; i < params->curitem->items.GetN(); i++)
|
|
{
|
|
Item *ci = params->curitem->items[i];
|
|
if (fpath.CompareNoCase(params->curitem->folder + ci->name) == 0)
|
|
{
|
|
params->curitem->cur = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
params->curitem->Update();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
}
|
|
|