Author Topic: Port CHDK file browser (file_man.mo)  (Read 64568 times)

gerk.raisen

  • Member
  • ***
  • Posts: 161
Port CHDK file browser (file_man.mo)
« on: May 20, 2013, 10:38:45 AM »
Hello,

I think is becoming even more useful to have a file browser to interact with file oncamera.
With this you can also delete *.DNG and raw recording, renaming it and directly and more.

Why not trying to port the file browser of CHKD? Even if as a module?
It can be a good start point.


a1ex

  • Administrator
  • Hero Member
  • *****
  • Posts: 12564
Re: Port CHDK file browser
« Reply #1 on: May 20, 2013, 10:42:05 AM »
+1, who's going to do it?

feureau

  • Hero Member
  • *****
  • Posts: 604
Re: Port CHDK file browser
« Reply #2 on: May 26, 2013, 07:15:20 AM »
Is it outside the scope for a beginner btw? I understand the modules are written in picoc?

I've been wanting to dive into ML programming. Got some experience with C but I'm better with python/java.

gerk.raisen

  • Member
  • ***
  • Posts: 161
Re: Port CHDK file browser
« Reply #3 on: May 27, 2013, 09:28:17 AM »
Any help is welcome..
You can try and then submit a pull request for review/approve :)

a1ex

  • Administrator
  • Hero Member
  • *****
  • Posts: 12564
Re: Port CHDK file browser
« Reply #4 on: May 28, 2013, 01:49:42 PM »
@minimimi did it:
https://bitbucket.org/minimimi/magic-lantern-filer

I've polished it a little and it's now in the main repo:
https://bitbucket.org/hudson/magic-lantern/src/tip/modules/file_man/

You need to compile the file_man module (and, of course, enable module support).

Text file viewing and file deletion (with confirmation) seems to work.

Andy600

  • Contributor
  • Hero Member
  • *****
  • Posts: 1863
  • Have you tried turning it off and on again?
Re: Port CHDK file browser
« Reply #5 on: May 28, 2013, 02:32:50 PM »
Great work guys. Gonna compile it :)
Colorist working with Davinci Resolve, Baselight, Nuke, After Effects & Premier Pro. Occasional Sunday afternoon DOP. Developer of Cinelog-C Colorspace Management and LUTs - www.cinelogdcp.com

a.d.

  • Member
  • ***
  • Posts: 126
Re: Port CHDK file browser
« Reply #6 on: May 28, 2013, 02:36:47 PM »
Currently the implementation of the file browser is not ideal, 'cause user could delete system files!! It's not better "chroot" it to 100EOS5D folder?

1%

  • Developer
  • Hero Member
  • *****
  • Posts: 5936
  • 600D/6D/50D/EOSM/7D
Re: Port CHDK file browser
« Reply #7 on: May 28, 2013, 02:40:45 PM »
Lol, now I can view log files in camera.

Quote
'cause user could delete system files!!

So don't.... maybe should make system files red.

Andy600

  • Contributor
  • Hero Member
  • *****
  • Posts: 1863
  • Have you tried turning it off and on again?
Re: Port CHDK file browser
« Reply #8 on: May 28, 2013, 02:43:27 PM »
ok, so I won't compile it yet then  ;D
Colorist working with Davinci Resolve, Baselight, Nuke, After Effects & Premier Pro. Occasional Sunday afternoon DOP. Developer of Cinelog-C Colorspace Management and LUTs - www.cinelogdcp.com

a.d.

  • Member
  • ***
  • Posts: 126
Re: Port CHDK file browser
« Reply #9 on: May 28, 2013, 02:58:38 PM »
Lol, now I can view log files in camera.

So don't.... maybe should make system files red.
To be clear, minimi did a great job, but ...
why we should prevent user to format the system files,  however you can delete them in the file browser afterward?
you still could read your log files in the chrooted folder, if we change the folder structure.

g3gg0

  • Developer
  • Hero Member
  • *****
  • Posts: 3190
Re: Port CHDK file browser
« Reply #10 on: May 28, 2013, 03:14:37 PM »
uhm. simply check for autoexec.bin and display an additional confirmation message.

seriously, people who simply delete stuff without thinking, should not install ML.
the same can happen with their windows explorer anyway.
i still hope that people use their brain before deleting.
Help us with datasheets - Help us with register dumps
magic lantern: 1Magic9991E1eWbGvrsx186GovYCXFbppY, server expenses: paypal@g3gg0.de
ONLY donate for things we have done, not for things you expect!

a.d.

  • Member
  • ***
  • Posts: 126
Re: Port CHDK file browser
« Reply #11 on: May 28, 2013, 03:26:52 PM »
I hope, I'm wrong.  ;D
After, 5D3 dot, dot, dot  :o ... we will see

gerk.raisen

  • Member
  • ***
  • Posts: 161
Re: Port CHDK file browser
« Reply #12 on: May 28, 2013, 03:54:36 PM »
All you are the best...

Audionut

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3657
  • Blunt and to the point
Re: Port CHDK file browser
« Reply #13 on: May 28, 2013, 03:59:51 PM »
I hope, I'm wrong.  ;D
After, 5D3 dot, dot, dot  :o ... we will see

Understanding that deleting the autoexec.bin file, that is needed for ML to run, might cause a problem, isn't exactly rocket science.
Software such as ML shouldn't be designed with the lowest percentile in mind IMO.

minimimi

  • Freshman
  • **
  • Posts: 68
Re: [DONE] Port CHDK file browser
« Reply #14 on: June 01, 2013, 10:03:14 AM »
It's already done , but I would like to collect testers for implove this module.

I just added copy and move codes for A1ex refucterd code.
If you have compile environment, please test it with Non-important SD card for Testing

Code: [Select]
diff -r de0bcff3619c modules/file_man/file_man.c
--- a/modules/file_man/file_man.c       Sat Jun 01 02:08:29 2013 +0300
+++ b/modules/file_man/file_man.c       Sat Jun 01 16:57:08 2013 +0900
@@ -8,6 +8,8 @@

 #define MAX_PATH_LEN 0x80
 static char gPath[MAX_PATH_LEN];
+static char gSrcFile[MAX_PATH_LEN];
+static unsigned int op_mode;

 static int cf_present;
 static int sd_present;
@@ -26,6 +28,13 @@
 #define TYPE_FILE 1
 #define TYPE_ACTION 2

+enum _FILER_OP {
+    FILE_OP_NONE,
+    FILE_OP_COPY,
+    FILE_OP_MOVE,
+    FILE_OP_PREVIEW
+};
+
 static struct file_entry * file_entries = 0;

 /* view file mode */
@@ -144,6 +153,26 @@
         return;
     }

+    if(op_mode != FILE_OP_NONE)
+    {
+        console_printf("ScanDir\n");
+        char srcpath[MAX_PATH_LEN];
+        strcpy(srcpath,gSrcFile);
+        char *p = srcpath+strlen(srcpath);
+        while (p > srcpath && *p != '/') p--;
+        *(p+1) = 0;
+
+        console_printf("src: %s\n",srcpath);
+        console_printf("dst: %s\n",path);
+
+
+        if(strcmp(path,srcpath) != 0){
+            add_file_entry("***Select Here***", TYPE_DIR, 0);
+            add_file_entry("*** Cancel OP ***", TYPE_DIR, 0);
+        }
+    }
+
+
     add_file_entry("../", TYPE_DIR, 0);

     struct fio_file file;
@@ -230,6 +259,100 @@
     }
 }

+static int
+ML_FIO_CopyFile(char *src,char *dst){
+    const int bufsize = 128*1024;
+    void* buf = alloc_dma_memory(bufsize);
+    if (!buf) return 1;
+
+    FILE* f = FIO_Open(src, O_RDONLY | O_SYNC);
+    if (f == INVALID_PTR) return 1;
+
+    FILE* g = FIO_CreateFile(dst);
+    if (g == INVALID_PTR) { FIO_CloseFile(f); return 1; }
+
+    int r = 0;
+    while ((r = FIO_ReadFile(f, buf, bufsize)))
+        FIO_WriteFile(g, buf, r);
+
+    FIO_CloseFile(f);
+    FIO_CloseFile(g);
+    msleep(1000); // this decreases the chances of getting corrupted files (fig    ure out why!)
+    free_dma_memory(buf);
+    return 0;
+}
+
+static int
+ML_FIO_MoveFile(char *src,char *dst){
+
+    ML_FIO_CopyFile(src,dst);
+    FIO_RemoveFile(src);
+    return 0;
+}
+
+static void
+FileCopy(void *unused)
+{
+    char fname[MAX_PATH_LEN];
+    size_t totallen = strlen(gSrcFile);
+    char *p = gSrcFile + totallen;
+    while (p > gSrcFile && *p != '/') p--;
+    strcpy(fname,p+1);
+
+    char dstfile[MAX_PATH_LEN];
+    snprintf(dstfile,MAX_PATH_LEN,"%s%s",gPath,fname);
+
+    console_printf("Copy\n");
+    console_printf("src: %s\n",gSrcFile);
+    console_printf("dst: %s\n",dstfile);
+    ML_FIO_CopyFile(gSrcFile,dstfile);
+
+}
+
+static void
+FileMove(void *unused)
+{
+    char fname[MAX_PATH_LEN];
+    size_t totallen = strlen(gSrcFile);
+    char *p = gSrcFile + totallen;
+    while (p > gSrcFile && *p != '/') p--;
+    strcpy(fname,p+1);
+
+    char dstfile[MAX_PATH_LEN];
+    snprintf(dstfile,MAX_PATH_LEN,"%s%s",gPath,fname);
+
+    console_printf("Move\n");
+    console_printf("src: %s\n",gSrcFile);
+    console_printf("dst: %s\n",dstfile);
+    ML_FIO_MoveFile(gSrcFile,dstfile);
+
+}
+
+
+static void FileOperation(){
+
+    switch(op_mode){
+    case FILE_OP_COPY:
+        task_create("FileCopy_task", 0x1b, 0x4000, FileCopy, 0);
+        break;
+    case FILE_OP_MOVE:
+        task_create("FileMove_task", 0x1b, 0x4000, FileMove, 0);
+        break;
+    case FILE_OP_PREVIEW:
+        break;
+    }
+    //cleanup
+    op_mode = FILE_OP_NONE;
+
+    ScanDir(gPath);
+}
+
+static void FileOpCancel(){
+    gSrcFile[0] = 0;
+    op_mode = FILE_OP_NONE;
+    ScanDir(gPath);
+}
+
 static MENU_SELECT_FUNC(BrowseUpMenu)
 {
     BrowseUp();
@@ -239,18 +362,18 @@
 {
     struct file_entry * fe = (struct file_entry *) priv;
     char* name = (char*) fe->name;
-    if ((name[0] == '.' &&
-         name[1] == '.' &&
-         name[2] == '/')
-         || (delta < 0)
-        )
-    {
-       BrowseUp();
-    }
+    if(!strcmp(name,"***Select Here***")){
+        FileOperation();
+    }else if(!strcmp(name,"*** Cancel OP ***")){
+        FileOpCancel();
+    }else if (!strcmp(name,"../") || (delta < 0))
+        {
+            BrowseUp();
+        }
     else
-    {
-       BrowseDown(name);
-    }
+        {
+            BrowseDown(name);
+        }
 }

 static MENU_UPDATE_FUNC(update_dir)
@@ -288,6 +411,30 @@
     return str;
 }

+static MENU_SELECT_FUNC(CopyFile)
+{
+    strcpy(gSrcFile,gPath);
+    console_printf("Copysrc: %s\n",gSrcFile);
+    op_mode = FILE_OP_COPY;
+}
+
+static MENU_UPDATE_FUNC(CopyFileProgress)
+{
+
+}
+
+static MENU_SELECT_FUNC(MoveFile)
+{
+    strcpy(gSrcFile,gPath);
+    console_printf("Movesrc: %s\n",gSrcFile);
+    op_mode = FILE_OP_MOVE;
+}
+
+static MENU_UPDATE_FUNC(MoveFileProgress)
+{
+
+}
+
 static MENU_SELECT_FUNC(viewfile_toggle)
 {
     view_file = !view_file;
@@ -375,6 +522,14 @@
     e->menu_entry.select = BrowseUpMenu;
     e->menu_entry.select_Q = BrowseUpMenu;
     e->menu_entry.priv = e;
+
+    e = add_file_entry("Copy", TYPE_ACTION, 0);
+    e->menu_entry.select = CopyFile;
+    e->menu_entry.update = CopyFileProgress;
+
+    e = add_file_entry("Move", TYPE_ACTION, 0);
+    e->menu_entry.select = MoveFile;
+    e->menu_entry.update = MoveFileProgress;

     e = add_file_entry("View", TYPE_ACTION, 0);
     e->menu_entry.select = viewfile_toggle;
@@ -438,6 +593,7 @@
 unsigned int fileman_init()
 {
     menu_add("Debug", fileman_menu, COUNT(fileman_menu));
+    op_mode = FILE_OP_NONE;
     InitRootDir();
     return 0;
 }


g3gg0

  • Developer
  • Hero Member
  • *****
  • Posts: 3190
Re: [DONE] Port CHDK file browser
« Reply #15 on: June 01, 2013, 12:01:01 PM »
just wanted to thank for your work, this file manager works really cool.
Help us with datasheets - Help us with register dumps
magic lantern: 1Magic9991E1eWbGvrsx186GovYCXFbppY, server expenses: paypal@g3gg0.de
ONLY donate for things we have done, not for things you expect!

ted ramasola

  • Moderators
  • Hero Member
  • *****
  • Posts: 1251
Re: [DONE] Port CHDK file browser
« Reply #16 on: June 01, 2013, 12:17:36 PM »
file browser is a very useful feature. Thank you all for your work on this.
5DmkII  / 7D
www.ramasolaproductions.com
Texas

1%

  • Developer
  • Hero Member
  • *****
  • Posts: 5936
  • 600D/6D/50D/EOSM/7D
Re: [DONE] Port CHDK file browser
« Reply #17 on: June 01, 2013, 03:03:36 PM »
Can you post a fileman.c from the repo with patch applied already? Easier to copy paste the whole thing back and forth.

minimimi

  • Freshman
  • **
  • Posts: 68
Re: [DONE] Port CHDK file browser
« Reply #18 on: June 01, 2013, 03:09:12 PM »
1% I see.
And now , Copy and Move menu entry has some strange numbers shown on same line. I guess it's referenced from info->xx but I can't solve it now.
 

Code: [Select]
#define CONFIG_CONSOLE

#include <module.h>
#include <dryos.h>
#include <property.h>
#include <bmp.h>
#include <menu.h>

#define MAX_PATH_LEN 0x80
static char gPath[MAX_PATH_LEN];
static char gSrcFile[MAX_PATH_LEN];
static unsigned int op_mode;

static int cf_present;
static int sd_present;

struct file_entry
{
    struct file_entry * next;
    struct menu_entry menu_entry;
    char name[MAX_PATH_LEN];
    unsigned int size;
    unsigned int type: 2;
    unsigned int added: 1;
};

#define TYPE_DIR 0
#define TYPE_FILE 1
#define TYPE_ACTION 2

enum _FILER_OP {
    FILE_OP_NONE,
    FILE_OP_COPY,
    FILE_OP_MOVE,
    FILE_OP_PREVIEW
};

static struct file_entry * file_entries = 0;

/* view file mode */
static int view_file = 0;

static MENU_SELECT_FUNC(select_dir);
static MENU_UPDATE_FUNC(update_dir);
static MENU_SELECT_FUNC(select_file);
static MENU_UPDATE_FUNC(update_file);
static MENU_SELECT_FUNC(default_select_action);
static MENU_UPDATE_FUNC(update_action);
static MENU_SELECT_FUNC(BrowseUpMenu);

static struct menu_entry fileman_menu[] =
{
    {
        .name = "File Browser",
        .select = menu_open_submenu,
        .submenu_width = 710,
        .children =  (struct menu_entry[]) {
            MENU_EOL,
        }
    }
};

static void clear_file_menu()
{
    while (file_entries)
    {
        struct file_entry * next = file_entries->next;
        menu_remove("File Browser", &(file_entries->menu_entry), 1);
        console_printf("%s\n", file_entries->name);
        FreeMemory(file_entries);
        file_entries = next;
    }
}

static struct file_entry * add_file_entry(char* txt, int type, int size)
{
    struct file_entry * fe = AllocateMemory(sizeof(struct file_entry));
    if (!fe) return 0;
    memset(fe, 0, sizeof(struct file_entry));
    snprintf(fe->name, sizeof(fe->name), "%s", txt);
    fe->size = size;

    fe->menu_entry.name = fe->name;
    fe->menu_entry.priv = fe;

    fe->type = type;
    fe->menu_entry.select_Q = BrowseUpMenu;
    if (fe->type == TYPE_DIR)
    {
        fe->menu_entry.select = select_dir;
        fe->menu_entry.update = update_dir;
    }
    else if (fe->type == TYPE_FILE)
    {
        fe->menu_entry.select = select_file;
        fe->menu_entry.update = update_file;
    }
    else if (fe->type == TYPE_ACTION)
    {
        fe->menu_entry.select = default_select_action;
        fe->menu_entry.update = update_action;
        fe->menu_entry.icon_type = IT_ACTION;
    }
    fe->next = file_entries;
    file_entries = fe;
    return fe;
}

static void build_file_menu()
{
    /* HaCKeD Sort */
    int done = 0;
    while (!done)
    {
        done = 1;

        for (struct file_entry * fe = file_entries; fe; fe = fe->next)
        {
            if (!fe->added)
            {
                /* are there any entries that should be before "fe" ? */
                /* if yes, skip "fe", add those entries, and try again */
                int should_skip = 0;
                for (struct file_entry * e = file_entries; e; e = e->next)
                {
                    if (!e->added && e != fe)
                    {
                        if (e->type < fe->type) { should_skip = 1; break; }
                        if ((e->type == fe->type) && strcmp(e->name, fe->name) < 0) { should_skip = 1; break; }
                    }
                }

                if (!should_skip)
                {
                    menu_add("File Browser", &(fe->menu_entry), 1);
                    fe->added = 1;
                }
                else done = 0;
            }
        }
    }
}

static void ScanDir(char *path)
{
    clear_file_menu();

    if (strlen(path) == 0)
    {
        add_file_entry("A:/", TYPE_DIR, 0);
        add_file_entry("B:/", TYPE_DIR, 0);
        build_file_menu();
        return;
    }

    if(op_mode != FILE_OP_NONE)
    {
        console_printf("ScanDir\n");
        char srcpath[MAX_PATH_LEN];
        strcpy(srcpath,gSrcFile);
        char *p = srcpath+strlen(srcpath);
        while (p > srcpath && *p != '/') p--;
        *(p+1) = 0;

        console_printf("src: %s\n",srcpath);
        console_printf("dst: %s\n",path);


        if(strcmp(path,srcpath) != 0){
            add_file_entry("***Select Here***", TYPE_DIR, 0);
            add_file_entry("*** Cancel OP ***", TYPE_DIR, 0);
        }
    }


    add_file_entry("../", TYPE_DIR, 0);

    struct fio_file file;
    struct fio_dirent * dirent = 0;

    dirent = FIO_FindFirstEx( path, &file );
    if( IS_ERROR(dirent) )
    {
        build_file_menu();
        return;
    }

    do
    {
        if (file.name[0] == '.') continue;
        if (file.mode & ATTR_DIRECTORY)
        {
            int len = strlen(file.name);
            snprintf(file.name + len, sizeof(file.name) - len, "/");
            add_file_entry(file.name, TYPE_DIR, 0);
        }
        else
        {
            add_file_entry(file.name, TYPE_FILE, file.size);
        }
    }
    while( FIO_FindNextEx( dirent, &file ) == 0);

    build_file_menu();

    FIO_CleanupAfterFindNext_maybe(dirent);
}

static void Browse(char* path)
{
    snprintf(gPath, sizeof(gPath), path);
    ScanDir(gPath);
}

static void BrowseDown(char* path)
{
    STR_APPEND(gPath, "%s", path);
    ScanDir(gPath);
}

static void restore_menu_selection(char* old_dir)
{
    for (struct file_entry * fe = file_entries; fe; fe = fe->next)
    {
        if (streq(fe->name, old_dir))
        {
            fe->menu_entry.selected = 1;
            for (struct file_entry * e = file_entries; e; e = e->next)
                if (e != fe) e->menu_entry.selected = 0;
            break;
        }
    }
}

static void BrowseUp()
{
    char* p = gPath + strlen(gPath) - 2;
    while (p > gPath && *p != '/') p--;

    if (*p == '/') /* up one level */
    {
        char old_dir[MAX_PATH_LEN];
        snprintf(old_dir, sizeof(old_dir), p+1);
        *(p+1) = 0;
        ScanDir(gPath);
        restore_menu_selection(old_dir);
    }
    else if (cf_present && sd_present && strlen(gPath) > 0) /* two cards: show A:/ and B:/ in menu */
    {
        char old_dir[MAX_PATH_LEN];
        snprintf(old_dir, sizeof(old_dir), "%s", gPath);
        gPath[0] = 0;
        ScanDir("");
        restore_menu_selection(old_dir);
    }
    else /* already at the top, close the file browser */
    {
        menu_close_submenu();
    }
}

static int
ML_FIO_CopyFile(char *src,char *dst){
    const int bufsize = 128*1024;
    void* buf = alloc_dma_memory(bufsize);
    if (!buf) return 1;

    FILE* f = FIO_Open(src, O_RDONLY | O_SYNC);
    if (f == INVALID_PTR) return 1;

    FILE* g = FIO_CreateFile(dst);
    if (g == INVALID_PTR) { FIO_CloseFile(f); return 1; }

    int r = 0;
    while ((r = FIO_ReadFile(f, buf, bufsize)))
        FIO_WriteFile(g, buf, r);

    FIO_CloseFile(f);
    FIO_CloseFile(g);
    msleep(1000); // this decreases the chances of getting corrupted files (fig    ure out why!)
    free_dma_memory(buf);
    return 0;
}

static int
ML_FIO_MoveFile(char *src,char *dst){

    ML_FIO_CopyFile(src,dst);
    FIO_RemoveFile(src);
    return 0;
}

static void
FileCopy(void *unused)
{
    char fname[MAX_PATH_LEN];
    size_t totallen = strlen(gSrcFile);
    char *p = gSrcFile + totallen;
    while (p > gSrcFile && *p != '/') p--;
    strcpy(fname,p+1);

    char dstfile[MAX_PATH_LEN];
    snprintf(dstfile,MAX_PATH_LEN,"%s%s",gPath,fname);

    console_printf("Copy\n");
    console_printf("src: %s\n",gSrcFile);
    console_printf("dst: %s\n",dstfile);
    ML_FIO_CopyFile(gSrcFile,dstfile);

}

static void
FileMove(void *unused)
{
    char fname[MAX_PATH_LEN];
    size_t totallen = strlen(gSrcFile);
    char *p = gSrcFile + totallen;
    while (p > gSrcFile && *p != '/') p--;
    strcpy(fname,p+1);

    char dstfile[MAX_PATH_LEN];
    snprintf(dstfile,MAX_PATH_LEN,"%s%s",gPath,fname);

    console_printf("Move\n");
    console_printf("src: %s\n",gSrcFile);
    console_printf("dst: %s\n",dstfile);
    ML_FIO_MoveFile(gSrcFile,dstfile);

}


static void FileOperation(){

    switch(op_mode){
    case FILE_OP_COPY:
        task_create("FileCopy_task", 0x1b, 0x4000, FileCopy, 0);
        break;
    case FILE_OP_MOVE:
        task_create("FileMove_task", 0x1b, 0x4000, FileMove, 0);
        break;
    case FILE_OP_PREVIEW:
        break;
    }
    //cleanup
    op_mode = FILE_OP_NONE;

    ScanDir(gPath);
}

static void FileOpCancel(){
    gSrcFile[0] = 0;
    op_mode = FILE_OP_NONE;
    ScanDir(gPath);
}

static MENU_SELECT_FUNC(BrowseUpMenu)
{
    BrowseUp();
}

static MENU_SELECT_FUNC(select_dir)
{
    struct file_entry * fe = (struct file_entry *) priv;
    char* name = (char*) fe->name;
    if(!strcmp(name,"***Select Here***")){
        FileOperation();
    }else if(!strcmp(name,"*** Cancel OP ***")){
        FileOpCancel();
    }else if (!strcmp(name,"../") || (delta < 0))
        {
            BrowseUp();
        }
    else
        {
            BrowseDown(name);
        }
}

static MENU_UPDATE_FUNC(update_dir)
{
    MENU_SET_VALUE("");
    MENU_SET_ICON(MNI_AUTO, 0);
    MENU_SET_HELP(gPath);
    if (entry->selected) view_file = 0;
}

const char * format_size( unsigned size)
{
    static char str[ 32 ];

    if( size > 1024*1024*1024 )
    {
        int size_gb = (size/1024 + 5) * 10 / 1024 / 1024;
        snprintf( str, sizeof(str), "%d.%dGB", size_gb/10, size_gb%10);
    }
    else if( size > 1024*1024 )
    {
        int size_mb = (size/1024 + 5) * 10 / 1024;
        snprintf( str, sizeof(str), "%d.%dMB", size_mb/10, size_mb%10);
    }
    else if( size > 1024 )
    {
        int size_kb = (size/1024 + 5) * 10;
        snprintf( str, sizeof(str), "%d.%dkB", size_kb/10, size_kb%10);
    }
    else
    {
        snprintf( str, sizeof(str), "%db", size);
    }

    return str;
}

static MENU_SELECT_FUNC(CopyFile)
{
    strcpy(gSrcFile,gPath);
    console_printf("Copysrc: %s\n",gSrcFile);
    op_mode = FILE_OP_COPY;
}

static MENU_UPDATE_FUNC(CopyFileProgress)
{

}

static MENU_SELECT_FUNC(MoveFile)
{
    strcpy(gSrcFile,gPath);
    console_printf("Movesrc: %s\n",gSrcFile);
    op_mode = FILE_OP_MOVE;
}

static MENU_UPDATE_FUNC(MoveFileProgress)
{

}

static MENU_SELECT_FUNC(viewfile_toggle)
{
    view_file = !view_file;
}

static MENU_UPDATE_FUNC(viewfile_show)
{
    if (view_file)
    {
        static char buf[1025];
        FILE * file = FIO_Open( gPath, O_RDONLY | O_SYNC );
        if (file != INVALID_PTR)
        {
            int r = FIO_ReadFile(file, buf, sizeof(buf)-1);
            FIO_CloseFile(file);
            buf[r] = 0;
            info->custom_drawing = CUSTOM_DRAW_THIS_MENU;
            clrscr();
            big_bmp_printf(FONT_MED, 0, 0, "%s", buf);
        }
        else
        {
            MENU_SET_WARNING(MENU_WARN_ADVICE, "Error reading %s", gPath);
            view_file = 0;
        }
    }
    else
    {
        update_action(entry, info);
    }
}

static int delete_confirm_flag = 0;

static MENU_SELECT_FUNC(delete_file)
{
    if (streq(gPath+1, ":/AUTOEXEC.BIN"))
    {
        beep();
        return;
    }

    if (!delete_confirm_flag)
    {
        delete_confirm_flag = get_ms_clock_value();
        beep();
    }
    else
    {
        delete_confirm_flag = 0;
        FIO_RemoveFile(gPath);
        BrowseUp();
    }
}

static MENU_UPDATE_FUNC(delete_confirm)
{
    update_action(entry, info);

    /* delete confirmation timeout after 2 seconds */
    if (get_ms_clock_value() > delete_confirm_flag + 2000)
        delete_confirm_flag = 0;

    /* no question mark in in our font, fsck! */
    if (delete_confirm_flag)
        MENU_SET_RINFO("Press SET to confirm");
}

static MENU_SELECT_FUNC(select_file)
{
    struct file_entry * fe = (struct file_entry *) priv;

    /* fe will be freed in clear_file_menu; backup things that we are going to reuse */
    char name[MAX_PATH_LEN];
    snprintf(name, sizeof(name), "%s", fe->name);
    int size = fe->size;
    STR_APPEND(gPath, "%s", name);

    clear_file_menu();
    /* at this point, fe was freed and is no longer valid */
    fe = 0;

    struct file_entry * e = add_file_entry(name, TYPE_FILE, size);
    if (!e) return;
    e->menu_entry.select = BrowseUpMenu;
    e->menu_entry.select_Q = BrowseUpMenu;
    e->menu_entry.priv = e;

    e = add_file_entry("Copy", TYPE_ACTION, 0);
    e->menu_entry.select = CopyFile;
    e->menu_entry.update = CopyFileProgress;

    e = add_file_entry("Move", TYPE_ACTION, 0);
    e->menu_entry.select = MoveFile;
    e->menu_entry.update = MoveFileProgress;

    e = add_file_entry("View", TYPE_ACTION, 0);
    e->menu_entry.select = viewfile_toggle;
    e->menu_entry.update = viewfile_show;

    e = add_file_entry("Delete", TYPE_ACTION, 0);
    e->menu_entry.select = delete_file;
    e->menu_entry.update = delete_confirm;

    //~ e = add_file_entry("Copy", TYPE_ACTION, 0);
    //~ e = add_file_entry("Rename", TYPE_ACTION, 0);

    build_file_menu();
}

static MENU_UPDATE_FUNC(update_file)
{
    struct file_entry * fe = (struct file_entry *) entry->priv;
    MENU_SET_VALUE("");

    MENU_SET_RINFO("%s", format_size(fe->size));
    MENU_SET_ICON(MNI_OFF, 0);
    MENU_SET_HELP(gPath);
    if (entry->selected) view_file = 0;
}

static MENU_SELECT_FUNC(default_select_action)
{
    beep();
}

static MENU_UPDATE_FUNC(update_action)
{
    MENU_SET_VALUE("");
    MENU_SET_HELP(gPath);
    if (entry->selected) view_file = 0;
}

static int InitRootDir()
{
    cf_present = is_dir("A:/");
    sd_present = is_dir("B:/");

    if (cf_present && !sd_present)
    {
        Browse("A:/");
    }
    else if (sd_present && !cf_present)
    {
        Browse("B:/");
    }
    else if (sd_present && cf_present)
    {
        Browse("");
    }
    else return -1;

    return 0;
}

unsigned int fileman_init()
{
    menu_add("Debug", fileman_menu, COUNT(fileman_menu));
    op_mode = FILE_OP_NONE;
    InitRootDir();
    return 0;
}

unsigned int fileman_deinit()
{
    return 0;
}


MODULE_INFO_START()
    MODULE_INIT(fileman_init)
    MODULE_DEINIT(fileman_deinit)
MODULE_INFO_END()

MODULE_STRINGS_START()
    MODULE_STRING("Author", "ML dev.")
    MODULE_STRING("License", "GPL")
    MODULE_STRING("Description", "File browser")
MODULE_STRINGS_END()

1%

  • Developer
  • Hero Member
  • *****
  • Posts: 5936
  • 600D/6D/50D/EOSM/7D
Re: [DONE] Port CHDK file browser
« Reply #19 on: June 01, 2013, 03:18:22 PM »
Is the number the pointer to the file?

Copy works but you have to back out of the folder to see that it did. No problems on my SD Card on 6D.

Funny thing happens: Copy Vram0.bmp / ML

Vram0.bmp in ML.

Now move vram0.bmp to ML

2x vram0.bmp in ML

It survives reboot... on the PC only one vram0.bmp in camera 2

Deleted the file, 1 file remains on SD card on the PC and 1 file remains in ML.

minimimi

  • Freshman
  • **
  • Posts: 68
Re: [DONE] Port CHDK file browser
« Reply #20 on: June 01, 2013, 03:55:17 PM »
Oh, OK.
I'm only used FIO_CreateFile() , so maybe Dryos make a 2 different i-node files with same filename.
I need to overwrite check and use FIO_Open for overwrite.

a1ex

  • Administrator
  • Hero Member
  • *****
  • Posts: 12564
Re: [DONE] Port CHDK file browser
« Reply #21 on: June 01, 2013, 04:00:27 PM »
Use FIO_CreateFileEx, it handles this quirk.

minimimi

  • Freshman
  • **
  • Posts: 68
Re: [DONE] Port CHDK file browser
« Reply #22 on: June 01, 2013, 04:42:23 PM »
Thanks alex , I'm tested CreatefileEx(). It's succeed to overwrite with same filename.

minimimi

  • Freshman
  • **
  • Posts: 68
Re: [DONE] Port CHDK file browser
« Reply #23 on: June 01, 2013, 05:04:17 PM »
Added ScanDir() when it finished copy/move functions and still showing same dir.

Code: [Select]
#define CONFIG_CONSOLE

#include <module.h>
#include <dryos.h>
#include <property.h>
#include <bmp.h>
#include <menu.h>

#define MAX_PATH_LEN 0x80
static char gPath[MAX_PATH_LEN];
static char gSrcFile[MAX_PATH_LEN];
static unsigned int op_mode;

static int cf_present;
static int sd_present;

struct file_entry
{
    struct file_entry * next;
    struct menu_entry menu_entry;
    char name[MAX_PATH_LEN];
    unsigned int size;
    unsigned int type: 2;
    unsigned int added: 1;
};

#define TYPE_DIR 0
#define TYPE_FILE 1
#define TYPE_ACTION 2

enum _FILER_OP {
    FILE_OP_NONE,
    FILE_OP_COPY,
    FILE_OP_MOVE,
    FILE_OP_PREVIEW
};

static struct file_entry * file_entries = 0;

/* view file mode */
static int view_file = 0;

static MENU_SELECT_FUNC(select_dir);
static MENU_UPDATE_FUNC(update_dir);
static MENU_SELECT_FUNC(select_file);
static MENU_UPDATE_FUNC(update_file);
static MENU_SELECT_FUNC(default_select_action);
static MENU_UPDATE_FUNC(update_action);
static MENU_SELECT_FUNC(BrowseUpMenu);

static struct menu_entry fileman_menu[] =
{
    {
        .name = "File Browser",
        .select = menu_open_submenu,
        .submenu_width = 710,
        .children =  (struct menu_entry[]) {
            MENU_EOL,
        }
    }
};

static void clear_file_menu()
{
    while (file_entries)
    {
        struct file_entry * next = file_entries->next;
        menu_remove("File Browser", &(file_entries->menu_entry), 1);
        console_printf("%s\n", file_entries->name);
        FreeMemory(file_entries);
        file_entries = next;
    }
}

static struct file_entry * add_file_entry(char* txt, int type, int size)
{
    struct file_entry * fe = AllocateMemory(sizeof(struct file_entry));
    if (!fe) return 0;
    memset(fe, 0, sizeof(struct file_entry));
    snprintf(fe->name, sizeof(fe->name), "%s", txt);
    fe->size = size;

    fe->menu_entry.name = fe->name;
    fe->menu_entry.priv = fe;

    fe->type = type;
    fe->menu_entry.select_Q = BrowseUpMenu;
    if (fe->type == TYPE_DIR)
    {
        fe->menu_entry.select = select_dir;
        fe->menu_entry.update = update_dir;
    }
    else if (fe->type == TYPE_FILE)
    {
        fe->menu_entry.select = select_file;
        fe->menu_entry.update = update_file;
    }
    else if (fe->type == TYPE_ACTION)
    {
        fe->menu_entry.select = default_select_action;
        fe->menu_entry.update = update_action;
        fe->menu_entry.icon_type = IT_ACTION;
    }
    fe->next = file_entries;
    file_entries = fe;
    return fe;
}

static void build_file_menu()
{
    /* HaCKeD Sort */
    int done = 0;
    while (!done)
    {
        done = 1;

        for (struct file_entry * fe = file_entries; fe; fe = fe->next)
        {
            if (!fe->added)
            {
                /* are there any entries that should be before "fe" ? */
                /* if yes, skip "fe", add those entries, and try again */
                int should_skip = 0;
                for (struct file_entry * e = file_entries; e; e = e->next)
                {
                    if (!e->added && e != fe)
                    {
                        if (e->type < fe->type) { should_skip = 1; break; }
                        if ((e->type == fe->type) && strcmp(e->name, fe->name) < 0) { should_skip = 1; break; }
                    }
                }

                if (!should_skip)
                {
                    menu_add("File Browser", &(fe->menu_entry), 1);
                    fe->added = 1;
                }
                else done = 0;
            }
        }
    }
}

static void ScanDir(char *path)
{
    clear_file_menu();

    if (strlen(path) == 0)
    {
        add_file_entry("A:/", TYPE_DIR, 0);
        add_file_entry("B:/", TYPE_DIR, 0);
        build_file_menu();
        return;
    }

    if(op_mode != FILE_OP_NONE)
    {
        console_printf("ScanDir\n");
        char srcpath[MAX_PATH_LEN];
        strcpy(srcpath,gSrcFile);
        char *p = srcpath+strlen(srcpath);
        while (p > srcpath && *p != '/') p--;
        *(p+1) = 0;

        console_printf("src: %s\n",srcpath);
        console_printf("dst: %s\n",path);


        if(strcmp(path,srcpath) != 0){
            add_file_entry("***Select Here***", TYPE_DIR, 0);
            add_file_entry("*** Cancel OP ***", TYPE_DIR, 0);
        }
    }


    add_file_entry("../", TYPE_DIR, 0);

    struct fio_file file;
    struct fio_dirent * dirent = 0;

    dirent = FIO_FindFirstEx( path, &file );
    if( IS_ERROR(dirent) )
    {
        build_file_menu();
        return;
    }

    do
    {
        if (file.name[0] == '.') continue;
        if (file.mode & ATTR_DIRECTORY)
        {
            int len = strlen(file.name);
            snprintf(file.name + len, sizeof(file.name) - len, "/");
            add_file_entry(file.name, TYPE_DIR, 0);
        }
        else
        {
            add_file_entry(file.name, TYPE_FILE, file.size);
        }
    }
    while( FIO_FindNextEx( dirent, &file ) == 0);

    build_file_menu();

    FIO_CleanupAfterFindNext_maybe(dirent);
}

static void Browse(char* path)
{
    snprintf(gPath, sizeof(gPath), path);
    ScanDir(gPath);
}

static void BrowseDown(char* path)
{
    STR_APPEND(gPath, "%s", path);
    ScanDir(gPath);
}

static void restore_menu_selection(char* old_dir)
{
    for (struct file_entry * fe = file_entries; fe; fe = fe->next)
    {
        if (streq(fe->name, old_dir))
        {
            fe->menu_entry.selected = 1;
            for (struct file_entry * e = file_entries; e; e = e->next)
                if (e != fe) e->menu_entry.selected = 0;
            break;
        }
    }
}

static void BrowseUp()
{
    char* p = gPath + strlen(gPath) - 2;
    while (p > gPath && *p != '/') p--;

    if (*p == '/') /* up one level */
    {
        char old_dir[MAX_PATH_LEN];
        snprintf(old_dir, sizeof(old_dir), p+1);
        *(p+1) = 0;
        ScanDir(gPath);
        restore_menu_selection(old_dir);
    }
    else if (cf_present && sd_present && strlen(gPath) > 0) /* two cards: show A:/ and B:/ in menu */
    {
        char old_dir[MAX_PATH_LEN];
        snprintf(old_dir, sizeof(old_dir), "%s", gPath);
        gPath[0] = 0;
        ScanDir("");
        restore_menu_selection(old_dir);
    }
    else /* already at the top, close the file browser */
    {
        menu_close_submenu();
    }
}

static int
ML_FIO_CopyFile(char *src,char *dst){
    const int bufsize = 128*1024;
    void* buf = alloc_dma_memory(bufsize);
    if (!buf) return 1;

    FILE* f = FIO_Open(src, O_RDONLY | O_SYNC);
    if (f == INVALID_PTR) return 1;

    FILE* g = FIO_CreateFileEx(dst);
    if (g == INVALID_PTR) { FIO_CloseFile(f); return 1; }

    int r = 0;
    while ((r = FIO_ReadFile(f, buf, bufsize)))
        FIO_WriteFile(g, buf, r);

    FIO_CloseFile(f);
    FIO_CloseFile(g);
    msleep(1000); // this decreases the chances of getting corrupted files (fig    ure out why!)
    free_dma_memory(buf);
    return 0;
}

static int
ML_FIO_MoveFile(char *src,char *dst){

    ML_FIO_CopyFile(src,dst);
    FIO_RemoveFile(src);
    return 0;
}

static void
FileCopy(void *unused)
{
    char fname[MAX_PATH_LEN],tmpdst[MAX_PATH_LEN];
    strcpy(tmpdst,gPath);
    size_t totallen = strlen(gSrcFile);
    char *p = gSrcFile + totallen;
    while (p > gSrcFile && *p != '/') p--;
    strcpy(fname,p+1);

    char dstfile[MAX_PATH_LEN];
    snprintf(dstfile,MAX_PATH_LEN,"%s%s",gPath,fname);

    ML_FIO_CopyFile(gSrcFile,dstfile);

    if(!strcmp(gPath,tmpdst)) ScanDir(gPath);
}

static void
FileMove(void *unused)
{
    char fname[MAX_PATH_LEN],tmpdst[MAX_PATH_LEN];
    strcpy(tmpdst,gPath);
    size_t totallen = strlen(gSrcFile);
    char *p = gSrcFile + totallen;
    while (p > gSrcFile && *p != '/') p--;
    strcpy(fname,p+1);

    char dstfile[MAX_PATH_LEN];
    snprintf(dstfile,MAX_PATH_LEN,"%s%s",gPath,fname);

    console_printf("Move\n");
    console_printf("src: %s\n",gSrcFile);
    console_printf("dst: %s\n",dstfile);
    ML_FIO_MoveFile(gSrcFile,dstfile);

    if(!strcmp(gPath,tmpdst)) ScanDir(gPath);
}


static void FileOperation(){

    switch(op_mode){
    case FILE_OP_COPY:
        task_create("FileCopy_task", 0x1b, 0x4000, FileCopy, 0);
        break;
    case FILE_OP_MOVE:
        task_create("FileMove_task", 0x1b, 0x4000, FileMove, 0);
        break;
    case FILE_OP_PREVIEW:
        break;
    }
    //cleanup
    op_mode = FILE_OP_NONE;

    ScanDir(gPath);
}

static void FileOpCancel(){
    gSrcFile[0] = 0;
    op_mode = FILE_OP_NONE;
    ScanDir(gPath);
}

static MENU_SELECT_FUNC(BrowseUpMenu)
{
    BrowseUp();
}

static MENU_SELECT_FUNC(select_dir)
{
    struct file_entry * fe = (struct file_entry *) priv;
    char* name = (char*) fe->name;
    if(!strcmp(name,"***Select Here***")){
        FileOperation();
    }else if(!strcmp(name,"*** Cancel OP ***")){
        FileOpCancel();
    }else if (!strcmp(name,"../") || (delta < 0))
        {
            BrowseUp();
        }
    else
        {
            BrowseDown(name);
        }
}

static MENU_UPDATE_FUNC(update_dir)
{
    MENU_SET_VALUE("");
    MENU_SET_ICON(MNI_AUTO, 0);
    MENU_SET_HELP(gPath);
    if (entry->selected) view_file = 0;
}

const char * format_size( unsigned size)
{
    static char str[ 32 ];

    if( size > 1024*1024*1024 )
    {
        int size_gb = (size/1024 + 5) * 10 / 1024 / 1024;
        snprintf( str, sizeof(str), "%d.%dGB", size_gb/10, size_gb%10);
    }
    else if( size > 1024*1024 )
    {
        int size_mb = (size/1024 + 5) * 10 / 1024;
        snprintf( str, sizeof(str), "%d.%dMB", size_mb/10, size_mb%10);
    }
    else if( size > 1024 )
    {
        int size_kb = (size/1024 + 5) * 10;
        snprintf( str, sizeof(str), "%d.%dkB", size_kb/10, size_kb%10);
    }
    else
    {
        snprintf( str, sizeof(str), "%db", size);
    }

    return str;
}

static MENU_SELECT_FUNC(CopyFile)
{
    strcpy(gSrcFile,gPath);
    console_printf("Copysrc: %s\n",gSrcFile);
    op_mode = FILE_OP_COPY;
}

static MENU_UPDATE_FUNC(CopyFileProgress)
{

}

static MENU_SELECT_FUNC(MoveFile)
{
    strcpy(gSrcFile,gPath);
    console_printf("Movesrc: %s\n",gSrcFile);
    op_mode = FILE_OP_MOVE;
}

static MENU_UPDATE_FUNC(MoveFileProgress)
{

}

static MENU_SELECT_FUNC(viewfile_toggle)
{
    view_file = !view_file;
}

static MENU_UPDATE_FUNC(viewfile_show)
{
    if (view_file)
    {
        static char buf[1025];
        FILE * file = FIO_Open( gPath, O_RDONLY | O_SYNC );
        if (file != INVALID_PTR)
        {
            int r = FIO_ReadFile(file, buf, sizeof(buf)-1);
            FIO_CloseFile(file);
            buf[r] = 0;
            info->custom_drawing = CUSTOM_DRAW_THIS_MENU;
            clrscr();
            big_bmp_printf(FONT_MED, 0, 0, "%s", buf);
        }
        else
        {
            MENU_SET_WARNING(MENU_WARN_ADVICE, "Error reading %s", gPath);
            view_file = 0;
        }
    }
    else
    {
        update_action(entry, info);
    }
}

static int delete_confirm_flag = 0;

static MENU_SELECT_FUNC(delete_file)
{
    if (streq(gPath+1, ":/AUTOEXEC.BIN"))
    {
        beep();
        return;
    }

    if (!delete_confirm_flag)
    {
        delete_confirm_flag = get_ms_clock_value();
        beep();
    }
    else
    {
        delete_confirm_flag = 0;
        FIO_RemoveFile(gPath);
        BrowseUp();
    }
}

static MENU_UPDATE_FUNC(delete_confirm)
{
    update_action(entry, info);

    /* delete confirmation timeout after 2 seconds */
    if (get_ms_clock_value() > delete_confirm_flag + 2000)
        delete_confirm_flag = 0;

    /* no question mark in in our font, fsck! */
    if (delete_confirm_flag)
        MENU_SET_RINFO("Press SET to confirm");
}

static MENU_SELECT_FUNC(select_file)
{
    struct file_entry * fe = (struct file_entry *) priv;

    /* fe will be freed in clear_file_menu; backup things that we are going to reuse */
    char name[MAX_PATH_LEN];
    snprintf(name, sizeof(name), "%s", fe->name);
    int size = fe->size;
    STR_APPEND(gPath, "%s", name);

    clear_file_menu();
    /* at this point, fe was freed and is no longer valid */
    fe = 0;

    struct file_entry * e = add_file_entry(name, TYPE_FILE, size);
    if (!e) return;
    e->menu_entry.select = BrowseUpMenu;
    e->menu_entry.select_Q = BrowseUpMenu;
    e->menu_entry.priv = e;

    e = add_file_entry("Copy", TYPE_ACTION, 0);
    e->menu_entry.select = CopyFile;
    e->menu_entry.update = CopyFileProgress;

    e = add_file_entry("Move", TYPE_ACTION, 0);
    e->menu_entry.select = MoveFile;
    e->menu_entry.update = MoveFileProgress;

    e = add_file_entry("View", TYPE_ACTION, 0);
    e->menu_entry.select = viewfile_toggle;
    e->menu_entry.update = viewfile_show;

    e = add_file_entry("Delete", TYPE_ACTION, 0);
    e->menu_entry.select = delete_file;
    e->menu_entry.update = delete_confirm;

    //~ e = add_file_entry("Copy", TYPE_ACTION, 0);
    //~ e = add_file_entry("Rename", TYPE_ACTION, 0);

    build_file_menu();
}

static MENU_UPDATE_FUNC(update_file)
{
    struct file_entry * fe = (struct file_entry *) entry->priv;
    MENU_SET_VALUE("");

    MENU_SET_RINFO("%s", format_size(fe->size));
    MENU_SET_ICON(MNI_OFF, 0);
    MENU_SET_HELP(gPath);
    if (entry->selected) view_file = 0;
}

static MENU_SELECT_FUNC(default_select_action)
{
    beep();
}

static MENU_UPDATE_FUNC(update_action)
{
    MENU_SET_VALUE("");
    MENU_SET_HELP(gPath);
    if (entry->selected) view_file = 0;
}

static int InitRootDir()
{
    cf_present = is_dir("A:/");
    sd_present = is_dir("B:/");

    if (cf_present && !sd_present)
    {
        Browse("A:/");
    }
    else if (sd_present && !cf_present)
    {
        Browse("B:/");
    }
    else if (sd_present && cf_present)
    {
        Browse("");
    }
    else return -1;

    return 0;
}

unsigned int fileman_init()
{
    menu_add("Debug", fileman_menu, COUNT(fileman_menu));
    op_mode = FILE_OP_NONE;
    InitRootDir();
    return 0;
}

unsigned int fileman_deinit()
{
    return 0;
}


MODULE_INFO_START()
    MODULE_INIT(fileman_init)
    MODULE_DEINIT(fileman_deinit)
MODULE_INFO_END()

MODULE_STRINGS_START()
    MODULE_STRING("Author", "ML dev.")
    MODULE_STRING("License", "GPL")
    MODULE_STRING("Description", "File browser")
MODULE_STRINGS_END()

1%

  • Developer
  • Hero Member
  • *****
  • Posts: 5936
  • 600D/6D/50D/EOSM/7D
Re: [DONE] Port CHDK file browser
« Reply #24 on: June 01, 2013, 07:04:10 PM »
Problem with move/copy seems gone.

Numbers are still there