Initial SVN import
[maemo-recorder] / src / maemo-recorder-file.c
diff --git a/src/maemo-recorder-file.c b/src/maemo-recorder-file.c
new file mode 100644 (file)
index 0000000..d813fda
--- /dev/null
@@ -0,0 +1,392 @@
+/* vim: set ts=4 sw=4 et: */
+/*
+ * maemo-recorder-file.c
+ * File-related operations
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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-1307 USA
+ *
+ */
+
+
+#include <libgnomevfs/gnome-vfs.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "maemo-recorder.h"
+#include "maemo-recorder-file.h"
+#include "maemo-recorder-au.h"
+
+static gboolean moveFile(const gchar *src, const gchar *dst);
+
+#if 0 
+/* DEPRECATED */
+gboolean 
+doSave(const gchar *current, const gchar *target, AudioFormat format)
+{
+    if (!current|| !target)
+        return FALSE;
+
+    switch (format)
+    {
+        case FORMAT_PCMA:
+            break;
+
+        case FORMAT_PCMU:
+            break;
+
+        case FORMAT_PCM:
+            break;
+            
+        case FORMAT_ILBC:
+        default:
+            return moveFile(current, target);
+    }
+
+    return moveFile(current, target);
+}
+#endif
+
+static gboolean 
+moveFile(const gchar *src, const gchar *dst)
+{
+    gchar *tmpcmd = NULL;
+    gint ret;
+
+    /* TODO: escape */
+    tmpcmd = g_strdup_printf("mv '%s' '%s'", src, dst);
+    ret = system(tmpcmd);
+    g_free(tmpcmd);
+
+    if (ret == -1)
+        return FALSE;
+
+    return TRUE;
+}
+
+const gchar * 
+getExtension(gint format)
+{
+    switch (format)
+    {
+        case FORMAT_ILBC:
+            return EXTENSION_ILBC;
+        case FORMAT_PCMA:
+            /* return EXTENSION_PCMA; */
+        case FORMAT_PCMU:
+            return EXTENSION_AU;
+            /* return EXTENSION_PCMU; */
+        case FORMAT_PCM:
+        default:
+            return EXTENSION_RAW;
+    }
+    return EXTENSION_RAW;
+}
+
+/* saveFile
+ *
+ * @param filename the filename from save dialog
+ * @param tmpfile the tmpfile where the actual data is
+ * @param format format of the tmpfile
+ * @param newfile the file (filename + extension) where the data was saved is returned here
+ */
+gboolean 
+saveFile(const gchar *filename, const gchar *tmpfile, AudioFormat format, gchar **newfile)
+{
+    const gchar *ext;
+    GnomeVFSHandle *tmp_handle = NULL;
+    GnomeVFSHandle *to_handle = NULL;
+    gchar *newfile_tmp;
+
+    if (!filename || !tmpfile)
+        return FALSE;
+
+    ext = getExtension(format);
+
+    /* don't append extension if the filename already has it */
+    if (g_str_has_suffix(filename, ext))
+        newfile_tmp = g_strdup(filename);
+    else 
+        newfile_tmp = g_strconcat(filename, ext, NULL);
+
+    g_assert(newfile_tmp);
+
+    if (strcmp(ext, EXTENSION_AU) == 0)
+    {
+        GnomeVFSFileSize len = 0;
+        guint32 encoding = 0;
+        gint written = -1;
+        GnomeVFSURI *uri = NULL;
+        gchar *text_uri;
+        GnomeVFSResult res;
+
+        len = getFileLength(tmpfile);
+        if (len == 0)
+        {
+            ULOG_WARN("%s: file length was zero", G_STRFUNC);
+            goto save_error;
+        }
+
+        encoding = au_get_encoding(format);
+        if (encoding == 0)
+            goto save_error;
+
+        /* open tmpfile(r) */
+        text_uri = g_strconcat("file://", tmpfile, NULL);
+        
+        if (gnome_vfs_open(&tmp_handle, text_uri, GNOME_VFS_OPEN_READ) != GNOME_VFS_OK)
+        {
+            ULOG_WARN("%s: gnome_vfs_open() failed", G_STRFUNC);
+            g_free(text_uri);
+            goto save_error;
+        }
+        
+        g_free(text_uri);
+        text_uri = NULL;
+
+        /* open/create newfile for writing */
+        text_uri = g_strconcat("file://", newfile_tmp, NULL);
+        uri = gnome_vfs_uri_new(text_uri);
+        g_free(text_uri);
+        text_uri = NULL;
+
+        /* TODO: check for symlink and other dangerous stuff */
+        res = gnome_vfs_create_uri(&to_handle, uri, 
+                    GNOME_VFS_OPEN_WRITE, 
+                    0 /* exclusive */,
+                    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH  /* perm */);
+        if (res != GNOME_VFS_OK)
+        {
+            ULOG_WARN("%s: gnome_vfs_create_uri() failed for '%s': %s", G_STRFUNC, gnome_vfs_uri_to_string(uri, GNOME_VFS_URI_HIDE_NONE), gnome_vfs_result_to_string(res));
+            gnome_vfs_uri_unref(uri);
+            goto save_error;
+        }
+
+        /* TODO: future work: get rate and channels from AudioFormatSpec */
+        written = au_write_copy(to_handle, encoding, DEFAULT_RATE, DEFAULT_CHANNELS, tmp_handle, len);
+
+        gnome_vfs_uri_unref(uri);
+        /* not very clever check but should catch most errors */
+        if (written < len)
+        {
+            ULOG_WARN("%s: au_write_copy() failed", G_STRFUNC);
+            goto save_error;
+        }
+
+        /* todo esta bien, close things and exit */
+        gnome_vfs_close(tmp_handle);
+        gnome_vfs_close(to_handle);
+
+        /* finally, place the filename into newfile */
+        *newfile = newfile_tmp;
+
+        return TRUE;
+    }
+    else
+    {
+        /* everything but AU files are RAW, just rename */
+        if (moveFile(tmpfile, newfile_tmp))
+        {
+            *newfile = newfile_tmp;
+            return TRUE;
+        }
+        goto save_error;
+    }
+
+save_error:
+
+    if (tmp_handle)
+        gnome_vfs_close(tmp_handle);
+    
+    if (to_handle)
+        gnome_vfs_close(to_handle);
+
+    if (newfile_tmp)
+    {
+        g_free(newfile_tmp);
+        /* don't touch newfile if we're returning false */
+        /* *newfile = NULL; */
+    }
+    return FALSE;
+}
+    
+/* openFile takes in the filename and returns:
+ * - whether it is supported format (the boolean return value)
+ * - audio format (FORMAT_XXX)
+ * - the tmpfile where the raw data is (or the same file name if the file was raw)
+ * TODO: add parameter (GError?) to report back an error string
+ */
+gboolean openFile(const gchar *filename, AudioFormat *format, gchar **tmpfile)
+{
+    if (g_strrstr(filename, EXTENSION_PCMA))
+    {
+        ULOG_INFO("%s() - file was %s, assuming raw %s, %d Hz, 1 ch", G_STRFUNC, EXTENSION_PCMA, GST_TYPE_PCMA, PCM_RATE);
+        *format = FORMAT_PCMA;
+        *tmpfile = g_strdup(filename);
+    }
+    else if (g_strrstr(filename, EXTENSION_PCMU))
+    {
+        ULOG_INFO("%s() - file was %s, assuming raw %s, %d Hz, 1 ch", G_STRFUNC, EXTENSION_PCMU, GST_TYPE_PCMU, PCM_RATE);
+        *format = FORMAT_PCMU;
+        *tmpfile = g_strdup(filename);
+    }
+    else if (g_strrstr(filename, EXTENSION_RAW))
+    {
+        ULOG_INFO("%s() - file was %s, assuming raw %s, %d Hz, 1 ch, 16-bit", G_STRFUNC, EXTENSION_RAW, GST_TYPE_PCM, PCM_RATE);
+        *format = FORMAT_PCM;
+        *tmpfile = g_strdup(filename);
+    }
+    else if (g_strrstr(filename, EXTENSION_MP3))
+    {
+        ULOG_INFO("%s() - file was %s", G_STRFUNC, EXTENSION_MP3);
+        *format = FORMAT_MP3;
+        *tmpfile = g_strdup(filename);
+    }
+    else if (g_strrstr(filename, EXTENSION_WAV))
+    {
+        ULOG_INFO("%s() - file was %s", G_STRFUNC, EXTENSION_WAV);
+        *format = FORMAT_WAV;
+        *tmpfile = g_strdup(filename);
+    }
+    else if (g_strrstr(filename, EXTENSION_ILBC))
+    {
+        ULOG_INFO("%s() - file was %s", G_STRFUNC, EXTENSION_ILBC);
+        *format = FORMAT_ILBC;
+        *tmpfile = g_strdup(filename);
+    }
+    else if (g_strrstr(filename, EXTENSION_AU) || g_strrstr(filename, EXTENSION_SND))
+    {
+        gchar *text_uri;
+        GnomeVFSHandle *from_handle, *tmp_handle;
+        GnomeVFSResult res;
+        guint32 fmt, rate, channels, data_size, data_offset;
+        GnomeVFSURI *uri;
+
+        gint ret = 0;
+
+        ULOG_INFO("%s() - file was AU/SND", G_STRFUNC);
+        /* decode and extract raw AU data */
+        text_uri = g_strdup_printf("file://%s", filename);
+        if (gnome_vfs_open(&from_handle, text_uri, GNOME_VFS_OPEN_READ) != GNOME_VFS_OK)
+        {
+            ULOG_WARN("%s() -  gnome_vfs_open() failed", G_STRFUNC);
+            g_free(text_uri);
+            return FALSE;
+        }
+        g_free(text_uri);
+        text_uri = NULL;
+        if ((ret = au_get_info(from_handle, &fmt, &rate, &channels, &data_size, &data_offset)) <= 0)
+        {
+            ULOG_WARN("%s() - au_get_info() failed", G_STRFUNC);
+            gnome_vfs_close(from_handle);
+            return FALSE;
+        }
+
+        ULOG_DEBUG("%s() - format: %u, rate: %u, channels: %u, data_size: %u, data_offset: %u", G_STRFUNC, fmt, rate, channels, data_size, data_offset);
+        if (rate != DEFAULT_RATE || channels != DEFAULT_CHANNELS || data_size == 0)
+        {
+            ULOG_WARN("%s() - unsupported format", G_STRFUNC);
+            gnome_vfs_close(from_handle);
+            return FALSE;
+        }
+
+        switch (fmt)
+        {
+            case FORMAT_PCMA:
+                text_uri = g_strdup_printf("file://%s", DEFAULT_TMP_PCMA_FILE);
+                break;
+            case FORMAT_PCMU:
+                text_uri = g_strdup_printf("file://%s", DEFAULT_TMP_PCMU_FILE);
+                break;
+            case FORMAT_PCM:
+            default: 
+                text_uri = g_strdup_printf("file://%s", DEFAULT_TMP_FILE);
+                break;
+        }
+
+        uri = gnome_vfs_uri_new(text_uri);
+        g_free(text_uri);
+        text_uri = NULL;
+
+        /* TODO: check for symlink and other dangerous stuff */
+        res = gnome_vfs_create_uri(&tmp_handle, uri, 
+                    GNOME_VFS_OPEN_WRITE, 
+                    0 /* exclusive */,
+                    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH  /* perm */);
+        if (res != GNOME_VFS_OK)
+        {
+            ULOG_WARN("%s() - gnome_vfs_create() failed for '%s': %s", G_STRFUNC, gnome_vfs_uri_to_string(uri, GNOME_VFS_URI_HIDE_NONE), gnome_vfs_result_to_string(res));
+            gnome_vfs_uri_unref(uri);
+            return FALSE;
+        }
+
+        ret = au_copy_data(tmp_handle, from_handle, data_offset /* from_offset */);
+        gnome_vfs_close(from_handle);
+        if (ret <= 0)
+        {
+            ULOG_WARN("%s() - couldn't copy file data to %s", G_STRFUNC, gnome_vfs_uri_to_string(uri, GNOME_VFS_URI_HIDE_NONE));
+            gnome_vfs_uri_unref(uri);
+            return FALSE;
+        }
+
+        /* everything ok, tmpfile created */
+
+        *format = fmt;
+        *tmpfile = g_strdup(gnome_vfs_uri_get_path(uri));
+        ULOG_DEBUG("%s() - created tmpfile '%s'", G_STRFUNC, *tmpfile);
+
+        gnome_vfs_uri_unref(uri);
+        uri = NULL;
+    }
+    else
+    {
+        ULOG_WARN("%s() - non-matching file name", G_STRFUNC); 
+        return FALSE;
+    }
+    return TRUE;
+}
+
+GnomeVFSFileSize getFileLength(const gchar *file)
+{
+    GnomeVFSFileInfo *info;
+    GnomeVFSResult res;
+    gchar *text_uri;
+    GnomeVFSFileSize ret = 0;
+
+    if (NULL == file)
+        return ret;
+
+    text_uri = g_strdup_printf("file://%s", file);
+    info = gnome_vfs_file_info_new();
+    res = gnome_vfs_get_file_info(text_uri,
+                info,
+                GNOME_VFS_FILE_INFO_DEFAULT);
+    g_free(text_uri);
+
+    if (res == GNOME_VFS_OK && (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE))
+    {
+        ret = info->size;
+    }
+    else 
+    {
+        ULOG_WARN("%s: couldn't get file size", G_STRFUNC);
+        ret = 0;
+    }
+
+    gnome_vfs_file_info_unref(info);
+
+    return ret;
+}