[easytag/wip/core-refactoring: 7/7] Port Musepack header reading to use GFile



commit b1359d94b4bf72db88848dc23cdb164c2be5d937
Author: David King <amigadave amigadave com>
Date:   Thu Jan 28 22:45:23 2016 +0100

    Port Musepack header reading to use GFile

 src/tags/libapetag/info_mpc.c |  261 ++++++++++++++++++++++++++---------------
 src/tags/libapetag/info_mpc.h |    5 +-
 src/tags/musepack_header.c    |   10 +--
 3 files changed, 173 insertions(+), 103 deletions(-)
---
diff --git a/src/tags/libapetag/info_mpc.c b/src/tags/libapetag/info_mpc.c
index 240b1dd..be1dd64 100644
--- a/src/tags/libapetag/info_mpc.c
+++ b/src/tags/libapetag/info_mpc.c
@@ -26,23 +26,22 @@
     -Thomas Juerges <thomas juerges astro ruhr-uni-bochum de> 
 */
 
+#include <errno.h>
 #include <glib/gstdio.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include "info_mpc.h"
 #include "is_tag.h"
- 
+
+#define MPC_HEADER_LENGTH 16
 
 /*
 *.MPC,*.MP+,*.MPP
 */
+/* Profile is 0...15, where 7...13 is used. */
 static const char *
-profile_stringify(unsigned int profile);    // profile is 0...15, where 7...13 is used
-
-
-static const char *
-profile_stringify(unsigned int profile)    // profile is 0...15, where 7...13 is used
+profile_stringify (unsigned int profile)
 {
     static const char na[] = "n.a.";
     static const char *Names[] = {
@@ -57,119 +56,193 @@ profile_stringify(unsigned int profile)    // profile is 0...15, where 7...13 is
 }
 
 /*
-    return 0; Info has all info
-    return 1; File not found
-    return 2; no Mpc file
+* info_mpc_read:
+* @file: file from which to read a header
+* @stream_info: stream information to fill
+* @error: a #Gerror, or %NULL
+*
+* Read header from the given MusePack @file.
+*
+* Returns: %TRUE on success, %FALSE and with @error set on failure
 */
-int
-info_mpc_read(const char *fn, StreamInfoMpc * Info)
+gboolean
+info_mpc_read (GFile *file,
+               StreamInfoMpc *stream_info,
+               GError **error)
 {
-    unsigned int HeaderData[16];
-    FILE *tmpFile = NULL;
-    long SkipSizeID3;
+    GFileInfo *info;
+    GFileInputStream *istream;
+    guint32 header_buffer[MPC_HEADER_LENGTH];
+    gsize bytes_read;
+    gsize id3_size;
     
-    // load file
-    tmpFile = g_fopen (fn, "rb");
+    info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_SIZE,
+                              G_FILE_QUERY_INFO_NONE, NULL, error);
+
+    if (!info)
+    {
+        return FALSE;
+    }
+
+    stream_info->FileSize = g_file_info_get_size (info);
+    g_object_unref (info);
+
+    {
+        gchar *path;
+        FILE *fp;
+
+        path = g_file_get_path (file);
+        fp = g_fopen (path, "rb");
+        g_free (path);
+
+        if (!fp)
+        {
+            /* TODO: Add specific error domain and message. */
+            g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, "%s",
+                         g_strerror (EINVAL));
+            return FALSE;
+        }
+
+        /* Skip id3v2. */
+        /* FIXME: is_id3v2 (and is_id3v1 and is_ape) should accept an istream
+         * or GFile. */
+        id3_size = is_id3v2 (fp);
+
+        fseek (fp, 0, SEEK_END);
+        stream_info->FileSize = ftell (fp);
+
+        /* Stream size. */
+        stream_info->ByteLength = stream_info->FileSize - is_id3v1 (fp)
+                                  - is_ape (fp) - id3_size;
+
+        fclose (fp);
+    }
         
-    if (tmpFile == NULL) 
-        return 1;    // file not found or read-protected
-    // skip id3v2 
-    SkipSizeID3=is_id3v2(tmpFile);
-    fseek(tmpFile,SkipSizeID3 , SEEK_SET);
-    if (fread ((void *) HeaderData, sizeof (int), 16, tmpFile) != 16)
+    istream = g_file_read (file, NULL, error);
+
+    if (!istream)
     {
-        fclose (tmpFile);
-        return 1;
+        return FALSE;
+    }
+
+    if (!g_seekable_seek (G_SEEKABLE (istream), id3_size, G_SEEK_SET, NULL,
+                          error))
+    {
+        return FALSE;
+    }
+
+    /* Read 16 guint32. */
+    if (!g_input_stream_read_all (G_INPUT_STREAM (istream), header_buffer,
+                                  MPC_HEADER_LENGTH * 4, &bytes_read, NULL,
+                                  error))
+    {
+        g_debug ("Only %" G_GSIZE_FORMAT "bytes out of 16 bytes of data were "
+                 "read", bytes_read);
+        return FALSE;
+    }
+
+    /* FIXME: Read 4 bytes, take as a uint32, then byteswap if necessary. (The
+     * official Musepack decoder expects the user(!) to request the
+     * byteswap.) */
+    if (memcmp (header_buffer, "MP+", 3) != 0)
+    {
+        /* TODO: Add specific error domain and message. */
+        g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, "%s",
+                     g_strerror (EINVAL));
+        return FALSE;
     }
-    fseek(tmpFile, 0, SEEK_END);
-    Info->FileSize=ftell(tmpFile);
-    // stream size 
-    Info->ByteLength = Info->FileSize-is_id3v1(tmpFile)-is_ape(tmpFile)-SkipSizeID3;
-    
-    fclose(tmpFile);
-    
-    if (0 != memcmp(HeaderData, "MP+", 3))
-        return 2; // no musepack file
     
-    Info->StreamVersion = HeaderData[0] >> 24;
-    if (Info->StreamVersion >= 7) {
+    stream_info->StreamVersion = header_buffer[0] >> 24;
+
+    if (stream_info->StreamVersion >= 7)
+    {
         const long samplefreqs[4] = { 44100, 48000, 37800, 32000 };
         
         // read the file-header (SV7 and above)
-        Info->Bitrate = 0;
-        Info->Frames = HeaderData[1];
-        Info->SampleFreq = samplefreqs[(HeaderData[2] >> 16) & 0x0003];
-        Info->MaxBand = (HeaderData[2] >> 24) & 0x003F;
-        Info->MS = (HeaderData[2] >> 30) & 0x0001;
-        Info->Profile = (HeaderData[2] << 8) >> 28;
-        Info->IS = (HeaderData[2] >> 31) & 0x0001;
-        Info->BlockSize = 1;
+        stream_info->Bitrate = 0;
+        stream_info->Frames = header_buffer[1];
+        stream_info->SampleFreq = samplefreqs[(header_buffer[2] >> 16) & 0x0003];
+        stream_info->MaxBand = (header_buffer[2] >> 24) & 0x003F;
+        stream_info->MS = (header_buffer[2] >> 30) & 0x0001;
+        stream_info->Profile = (header_buffer[2] << 8) >> 28;
+        stream_info->IS = (header_buffer[2] >> 31) & 0x0001;
+        stream_info->BlockSize = 1;
         
-        Info->EncoderVersion = (HeaderData[6] >> 24) & 0x00FF;
-        Info->Channels = 2;
+        stream_info->EncoderVersion = (header_buffer[6] >> 24) & 0x00FF;
+        stream_info->Channels = 2;
         // gain
-        Info->EstPeakTitle = HeaderData[2] & 0xFFFF;    // read the ReplayGain data
-        Info->GainTitle = (HeaderData[3] >> 16) & 0xFFFF;
-        Info->PeakTitle = HeaderData[3] & 0xFFFF;
-        Info->GainAlbum = (HeaderData[4] >> 16) & 0xFFFF;
-        Info->PeakAlbum = HeaderData[4] & 0xFFFF;
+        stream_info->EstPeakTitle = header_buffer[2] & 0xFFFF;    // read the ReplayGain data
+        stream_info->GainTitle = (header_buffer[3] >> 16) & 0xFFFF;
+        stream_info->PeakTitle = header_buffer[3] & 0xFFFF;
+        stream_info->GainAlbum = (header_buffer[4] >> 16) & 0xFFFF;
+        stream_info->PeakAlbum = header_buffer[4] & 0xFFFF;
         // gaples
-        Info->IsTrueGapless = (HeaderData[5] >> 31) & 0x0001;    // true gapless: used?
-        Info->LastFrameSamples = (HeaderData[5] >> 20) & 0x07FF;    // true gapless: valid samples for last 
frame
+        stream_info->IsTrueGapless = (header_buffer[5] >> 31) & 0x0001;    // true gapless: used?
+        stream_info->LastFrameSamples = (header_buffer[5] >> 20) & 0x07FF;    // true gapless: valid samples 
for last frame
         
-        if (Info->EncoderVersion == 0) {
-            sprintf(Info->Encoder, "<= 1.05"); // Buschmann 1.7.x, Klemm <= 1.05
-        } else {
-            switch (Info->EncoderVersion % 10) {
+        if (stream_info->EncoderVersion == 0)
+        {
+            sprintf (stream_info->Encoder, "<= 1.05"); // Buschmann 1.7.x, Klemm <= 1.05
+        }
+        else
+        {
+            switch (stream_info->EncoderVersion % 10)
+            {
             case 0:
-                sprintf(Info->Encoder, "%u.%u",
-                    Info->EncoderVersion / 100,
-                    Info->EncoderVersion / 10 % 10);
+                sprintf (stream_info->Encoder, "%u.%u",
+                         stream_info->EncoderVersion / 100,
+                         stream_info->EncoderVersion / 10 % 10);
                 break;
             case 2:
             case 4:
             case 6:
             case 8:
-                sprintf(Info->Encoder, "%u.%02u Beta",
-                    Info->EncoderVersion / 100,
-                    Info->EncoderVersion % 100);
+                sprintf (stream_info->Encoder, "%u.%02u Beta",
+                         stream_info->EncoderVersion / 100,
+                         stream_info->EncoderVersion % 100);
                 break;
             default:
-                sprintf(Info->Encoder, "%u.%02u Alpha",
-                    Info->EncoderVersion / 100,
-                    Info->EncoderVersion % 100);
+                sprintf (stream_info->Encoder, "%u.%02u Alpha",
+                         stream_info->EncoderVersion / 100,
+                         stream_info->EncoderVersion % 100);
                 break;
             }
         }
         // estimation, exact value needs too much time
-        Info->Bitrate = (long) (Info->ByteLength) * 8. * Info->SampleFreq / (1152 * Info->Frames - 576);
+        stream_info->Bitrate = (long) (stream_info->ByteLength) * 8. * stream_info->SampleFreq / (1152 * 
stream_info->Frames - 576);
         
-    } else {
+    }
+    else
+    {
         // read the file-header (SV6 and below)
-        Info->Bitrate = ((HeaderData[0] >> 23) & 0x01FF) * 1000;    // read the file-header (SV6 and below)
-        Info->MS = (HeaderData[0] >> 21) & 0x0001;
-        Info->IS = (HeaderData[0] >> 22) & 0x0001;
-        Info->StreamVersion = (HeaderData[0] >> 11) & 0x03FF;
-        Info->MaxBand = (HeaderData[0] >> 6) & 0x001F;
-        Info->BlockSize = (HeaderData[0]) & 0x003F;
+        stream_info->Bitrate = ((header_buffer[0] >> 23) & 0x01FF) * 1000;    // read the file-header (SV6 
and below)
+        stream_info->MS = (header_buffer[0] >> 21) & 0x0001;
+        stream_info->IS = (header_buffer[0] >> 22) & 0x0001;
+        stream_info->StreamVersion = (header_buffer[0] >> 11) & 0x03FF;
+        stream_info->MaxBand = (header_buffer[0] >> 6) & 0x001F;
+        stream_info->BlockSize = (header_buffer[0]) & 0x003F;
         
-        Info->Profile = 0;
+        stream_info->Profile = 0;
         //gain
-        Info->GainTitle = 0;    // not supported
-        Info->PeakTitle = 0;
-        Info->GainAlbum = 0;
-        Info->PeakAlbum = 0;
+        stream_info->GainTitle = 0;    // not supported
+        stream_info->PeakTitle = 0;
+        stream_info->GainAlbum = 0;
+        stream_info->PeakAlbum = 0;
         //gaples
-        Info->LastFrameSamples = 0;
-        Info->IsTrueGapless = 0;
+        stream_info->LastFrameSamples = 0;
+        stream_info->IsTrueGapless = 0;
         
-        if (Info->StreamVersion >= 5)
-            Info->Frames = HeaderData[1];    // 32 bit
+        if (stream_info->StreamVersion >= 5)
+        {
+            stream_info->Frames = header_buffer[1];    // 32 bit
+        }
         else
-            Info->Frames = (HeaderData[1] >> 16);    // 16 bit
+        {
+            stream_info->Frames = (header_buffer[1] >> 16);    // 16 bit
+        }
         
-        Info->EncoderVersion = 0;
-        Info->Encoder[0] = '\0';
+        stream_info->EncoderVersion = 0;
+        stream_info->Encoder[0] = '\0';
 #if 0
         if (Info->StreamVersion == 7)
             return ERROR_CODE_SV7BETA;    // are there any unsupported parameters used?
@@ -180,15 +253,19 @@ info_mpc_read(const char *fn, StreamInfoMpc * Info)
         if (Info->BlockSize != 1)
             return ERROR_CODE_BLOCKSIZE;
 #endif
-        if (Info->StreamVersion < 6)    // Bugfix: last frame was invalid for up to SV5
-            Info->Frames -= 1;
+        if (stream_info->StreamVersion < 6)    // Bugfix: last frame was invalid for up to SV5
+        {
+            stream_info->Frames -= 1;
+        }
         
-        Info->SampleFreq = 44100;    // AB: used by all files up to SV7
-        Info->Channels = 2;
+        stream_info->SampleFreq = 44100;    // AB: used by all files up to SV7
+        stream_info->Channels = 2;
     }
     
-    Info->ProfileName=profile_stringify(Info->Profile);
+    stream_info->ProfileName = profile_stringify (stream_info->Profile);
     
-    Info->Duration = (int) (Info->Frames * 1152 / (Info->SampleFreq/1000.0));
-    return 0;
+    stream_info->Duration = (int) (stream_info->Frames * 1152
+                                   / (stream_info->SampleFreq / 1000.0));
+
+    return TRUE;
 }
diff --git a/src/tags/libapetag/info_mpc.h b/src/tags/libapetag/info_mpc.h
index d82a9bb..88356eb 100644
--- a/src/tags/libapetag/info_mpc.h
+++ b/src/tags/libapetag/info_mpc.h
@@ -20,6 +20,8 @@
 #ifndef INFO_MPC_H
 #define INFO_MPC_H
 
+#include <gio/gio.h>
+
 /** \file info_mpc.h 
     \brief Get information from MusePack file.
 
@@ -86,7 +88,6 @@ typedef struct
     \retval 1 file not found or write protected
     \retval 2 not musepack audio file
 */
-int
-info_mpc_read(const char *fn, StreamInfoMpc *Info);
+gboolean info_mpc_read (GFile *file, StreamInfoMpc *Info, GError **error);
 
 #endif /* INFO_MPC_H */
diff --git a/src/tags/musepack_header.c b/src/tags/musepack_header.c
index 9cf7481..a579157 100644
--- a/src/tags/musepack_header.c
+++ b/src/tags/musepack_header.c
@@ -32,24 +32,16 @@ et_mpc_header_read_file_info (GFile *file,
                               ET_File_Info *ETFileInfo,
                               GError **error)
 {
-    gchar *filename;
     StreamInfoMpc Info;
 
     g_return_val_if_fail (file != NULL && ETFileInfo != NULL, FALSE);
     g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-    filename = g_file_get_path (file);
-
-    if (info_mpc_read (filename, &Info))
+    if (!info_mpc_read (file, &Info, error))
     {
-        g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "%s",
-                     _("Error opening Musepack file"));
-        g_free (filename);
         return FALSE;
     }
 
-    g_free (filename);
-
     ETFileInfo->mpc_profile = g_strdup(Info.ProfileName);
     ETFileInfo->version     = Info.StreamVersion;
     ETFileInfo->bitrate     = Info.Bitrate/1000.0;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]