Index: apps/plugin.c
===================================================================
RCS file: /cvsroot/rockbox/apps/plugin.c,v
retrieving revision 1.204
diff -u -b -r1.204 plugin.c
--- apps/plugin.c	7 Dec 2006 17:23:52 -0000	1.204
+++ apps/plugin.c	17 Dec 2006 05:32:41 -0000
@@ -486,6 +486,10 @@
     sound_default,
     pcm_record_more,
 #endif
+
+#if CONFIG_CODEC == SWCODEC
+    audio_pre_ff_rewind,
+#endif
 };
 
 int plugin_load(const char* plugin, void* parameter)
Index: apps/plugin.h
===================================================================
RCS file: /cvsroot/rockbox/apps/plugin.h,v
retrieving revision 1.208
diff -u -b -r1.208 plugin.h
--- apps/plugin.h	7 Dec 2006 17:23:52 -0000	1.208
+++ apps/plugin.h	17 Dec 2006 05:32:42 -0000
@@ -602,6 +602,10 @@
     int (*sound_default)(int setting);
     void (*pcm_record_more)(void *start, size_t size);
 #endif
+
+#if CONFIG_CODEC == SWCODEC
+    void (*audio_pre_ff_rewind)(void);
+#endif
 };
 
 /* plugin header */
Index: apps/plugins/SOURCES
===================================================================
RCS file: /cvsroot/rockbox/apps/plugins/SOURCES,v
retrieving revision 1.144
diff -u -b -r1.144 SOURCES
--- apps/plugins/SOURCES	30 Nov 2006 22:29:48 -0000	1.144
+++ apps/plugins/SOURCES	17 Dec 2006 05:32:42 -0000
@@ -1,3 +1,5 @@
+cuesheet.c
+
 /* plugins common to all models */
 battery_bench.c
 chessclock.c
Index: apps/plugins/cuesheet.c
===================================================================
RCS file: apps/plugins/cuesheet.c
diff -N apps/plugins/cuesheet.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ apps/plugins/cuesheet.c	17 Dec 2006 05:32:42 -0000
@@ -0,0 +1,222 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: cuesheet.c,v 1.17 2006-12-05 10:09:06 markun Exp $
+ *
+ *
+ * Copyright (C) 2006 Jonathan Gordon, Nicolas Pennequin
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "plugin.h"
+PLUGIN_HEADER
+
+static struct plugin_api* rb;
+
+#define MAX_NAME 64
+#define MAX_TRACKS 99
+
+char cd_title[MAX_NAME];
+char cd_performer[MAX_NAME];
+char cd_filename[MAX_PATH];
+
+struct track_info {
+    char title[MAX_NAME];
+    char performer[MAX_NAME];
+    unsigned long offset; /* ms from start of track */
+} tracks[MAX_TRACKS];
+int track_count = 0;
+
+struct mp3entry* id3;
+
+#define MATCH(l,s) !rb->strncmp(l,s,rb->strlen(s)) 
+
+char *skip_whitespace(char* buf)
+{
+    char *r = buf;
+    while (*r && (*r < 33))
+        r++;
+    return r;
+}
+
+bool parse_cuesheet(char *file)
+{
+    char line[MAX_PATH];
+    char *s, *start, *end;
+    int fd = rb->open(file,O_RDONLY);
+    if (fd<0)
+    {
+        rb->splash(HZ*2,true,"Couldnt open file: %s",file);
+        return false;
+    }
+    track_count = -1;
+    while (rb->read_line(fd,line,MAX_PATH))
+    {
+        s = skip_whitespace(line);
+        if (MATCH(s, "TITLE"))
+        {
+            start = rb->strchr(s,'"');
+            if (!start)
+                break;
+            end = rb->strchr(++start,'"');
+            if (!end)
+                break;
+            *end = '\0';
+            if (track_count < 0)
+                rb->strncpy(cd_title,start,MAX_NAME);
+            else rb->strncpy(tracks[track_count].title,
+                                start,MAX_NAME);
+        }
+        else if (MATCH(s, "PERFORMER"))
+        {
+            start = rb->strchr(s,'"');
+            if (!start)
+                break;
+            end = rb->strchr(++start,'"');
+            if (!end)
+                break;
+            *end = '\0';
+            if (track_count < 0)
+                rb->strncpy(cd_performer,start,MAX_NAME);
+            else rb->strncpy(tracks[track_count].performer,
+                                start,MAX_NAME);
+        }
+        else if (MATCH(s, "FILE"))
+        {
+            start = rb->strchr(s,'"');
+            if (!start)
+                break;
+            end = rb->strchr(++start,'"');
+            if (!end)
+                break;
+            *end = '\0';
+            rb->strncpy(cd_filename,start,MAX_PATH);
+        }
+        else if (MATCH(s, "TRACK"))
+            track_count++;
+        else if (MATCH(s, "INDEX"))
+        {
+            char min[3], sec[3], fr[3];
+            s = rb->strchr(s,' ');
+            s = skip_whitespace(s);
+            s = rb->strchr(s,' ');
+            s = skip_whitespace(s);
+            rb->strncpy(min,s,3);
+            s += 3;min[2] ='\0';
+            rb->strncpy(sec,s,3);
+            s += 3;sec[2] ='\0';
+            rb->strncpy(fr,s,3);fr[2] ='\0';
+            tracks[track_count].offset = (13*rb->atoi(fr))
+                                          + (1000*rb->atoi(sec))
+                                          + (1000*rb->atoi(min)*60);
+            LOGF("%d %ld",track_count, tracks[track_count].offset);
+        }
+    }
+    return true;
+}
+
+bool seek(unsigned int pos){
+    if (!(rb->audio_status() & AUDIO_STATUS_PLAY) || pos > id3->length)
+    {
+        return false;
+    }
+    else
+    {
+        rb->audio_pre_ff_rewind();
+        rb->audio_ff_rewind(pos);
+        return true;
+    }
+}
+
+int find_current_track(void)
+{
+    int i=0;
+    while (tracks[i+1].offset < id3->elapsed)
+    {
+        i++;
+    }
+    return i;
+}
+
+char *list_get_name_cb(int selected_item,
+                             void *data,
+                             char *buffer)
+{
+    if (selected_item % 2 == 0)
+    {
+        rb->snprintf(buffer,MAX_PATH,"%d %s",
+                     selected_item/2+1,tracks[selected_item/2].performer);
+    }
+    else
+    {
+        rb->snprintf(buffer,MAX_PATH,(selected_item+1)/2>9 ? "   %s" : "  %s",
+                     tracks[selected_item/2].title);
+    }
+    return buffer;
+}
+
+void browse(void)
+{
+    struct gui_synclist lists;
+    int action;
+    bool done = false;
+    int sel;
+    rb->gui_synclist_init(&lists,list_get_name_cb,0,false,2);
+    rb->gui_synclist_set_nb_items(&lists,2*track_count);
+    rb->gui_synclist_select_item(&lists,2*find_current_track());
+
+    while (!done)
+    {
+        rb->gui_synclist_draw(&lists);
+        action = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK);
+        if (rb->gui_synclist_do_button(&lists,action,LIST_WRAP_UNLESS_HELD))
+            continue;
+        switch (action)
+        {
+            case ACTION_STD_OK:
+                id3 = rb->audio_current_track();
+                sel = rb->gui_synclist_get_sel_pos(&lists);
+                if (!seek(tracks[sel/2].offset))
+                {
+                    rb->splash(HZ, true, "Seeking there isn't allowed");
+                }
+                break;
+            case ACTION_STD_CANCEL:
+                done = true;
+        }
+    }
+}
+
+enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
+{
+    char filename[MAX_PATH], *s;
+    rb = api;
+    if (!parameter)
+        return PLUGIN_ERROR;
+
+    rb->strcpy(filename,(char*)parameter);
+    if (!parse_cuesheet(filename))
+        return PLUGIN_ERROR;
+
+    s = rb->strrchr(filename,'/');
+    if (!s)
+    {
+        rb->splash(HZ,true,"Cuesheet Failed!");
+        return PLUGIN_ERROR;
+    }
+    rb->strcpy(s+1,cd_filename);
+
+    id3 = rb->audio_current_track();
+    browse();
+    return PLUGIN_OK;
+}
Index: apps/plugins/viewers.config
===================================================================
RCS file: /cvsroot/rockbox/apps/plugins/viewers.config,v
retrieving revision 1.37
diff -u -b -r1.37 viewers.config
--- apps/plugins/viewers.config	30 Nov 2006 22:29:48 -0000	1.37
+++ apps/plugins/viewers.config	17 Dec 2006 05:32:42 -0000
@@ -28,3 +28,4 @@
 tzx,viewers/zxbox,66 52 4A 66 52 4A
 z80,viewers/zxbox,66 52 4A 66 52 4A
 zzz,viewers/properties,00 00 00 00 00 00
+cue,viewers/cuesheet,11 22 AA BB CC 77
