Merge remote-tracking branch 'remotes/origin/cairocanvas' into windows
[ardour.git] / libs / evoral / src / libsmf / smf_load.c
index 98c7789dce50377622cdfe12f04007a906ebd8fd..fed4d28bb7effa542f7369e8203a54a5be610047 100644 (file)
 #include <math.h>
 #include <errno.h>
 #include <ctype.h>
+#ifdef PLATFORM_WINDOWS
+#include <winsock2.h>
+#else
 #include <arpa/inet.h>
+#endif
 #include "smf.h"
 #include "smf_private.h"
 
@@ -56,7 +60,6 @@ next_chunk(smf_t *smf)
 
        assert(smf->file_buffer != NULL);
        assert(smf->file_buffer_length > 0);
-       assert(smf->next_chunk_offset >= 0);
 
        if (smf->next_chunk_offset + sizeof(struct chunk_header_struct) >= smf->file_buffer_length) {
                g_critical("SMF warning: no more chunks left.");
@@ -120,7 +123,7 @@ parse_mthd_header(smf_t *smf)
                return (-1);
        }
 
-       tmp_mthd = smf->file_buffer;
+       tmp_mthd = (struct chunk_header_struct*)smf->file_buffer;
 
        if (!chunk_signature_matches(tmp_mthd, "MThd")) {
                g_critical("SMF error: MThd signature not found, is that a MIDI file?");
@@ -207,14 +210,12 @@ parse_mthd_chunk(smf_t *smf)
  * Explanation of Variable Length Quantities is here: http://www.borg.com/~jglatt/tech/midifile/vari.htm
  * Returns 0 iff everything went OK, different value in case of error.
  */
-static int
-extract_vlq(const unsigned char *buf, const int buffer_length, int *value, int *len)
+int
+smf_extract_vlq(const unsigned char *buf, const size_t buffer_length, uint32_t *value, uint32_t *len)
 {
-       int val = 0;
+       uint32_t val = 0;
        const unsigned char *c = buf;
 
-       assert(buffer_length > 0);
-
        for (;;) {
                if (c >= buf + buffer_length) {
                        g_critical("End of buffer in extract_vlq().");
@@ -229,6 +230,7 @@ extract_vlq(const unsigned char *buf, const int buffer_length, int *value, int *
                        break;
        };
 
+       assert(c >= buf);
        *value = val;
        *len = c - buf + 1;
 
@@ -274,10 +276,11 @@ is_escape_byte(const unsigned char status)
  * contains VLQ telling how many bytes it takes, "on the wire" format does not have
  * this.
  */
-static int
-expected_sysex_length(const unsigned char status, const unsigned char *second_byte, const int buffer_length, int *consumed_bytes)
+static int32_t
+expected_sysex_length(const unsigned char status, const unsigned char *second_byte, const size_t buffer_length, int32_t *consumed_bytes)
 {
-       int sysex_length, len;
+       uint32_t sysex_length = 0;
+       uint32_t len = 0;
 
        assert(status == 0xF0);
 
@@ -286,7 +289,7 @@ expected_sysex_length(const unsigned char status, const unsigned char *second_by
                return (-1);
        }
 
-       extract_vlq(second_byte, buffer_length, &sysex_length, &len);
+       smf_extract_vlq(second_byte, buffer_length, &sysex_length, &len);
 
        if (consumed_bytes != NULL)
                *consumed_bytes = len;
@@ -295,8 +298,8 @@ expected_sysex_length(const unsigned char status, const unsigned char *second_by
        return (sysex_length + 1);
 }
 
-static int
-expected_escaped_length(const unsigned char status, const unsigned char *second_byte, const int buffer_length, int *consumed_bytes)
+static int32_t
+expected_escaped_length(const unsigned char status, const unsigned char *second_byte, const size_t buffer_length, int32_t *consumed_bytes)
 {
        /* -1, because we do not want to account for 0x7F status. */
        return (expected_sysex_length(status, second_byte, buffer_length, consumed_bytes) - 1);
@@ -307,8 +310,8 @@ expected_escaped_length(const unsigned char status, const unsigned char *second_
  * The "second_byte" points to the expected second byte of the MIDI message.  "buffer_length" is the buffer
  * length limit, counting from "second_byte".  Returns value < 0 iff there was an error.
  */
-static int
-expected_message_length(unsigned char status, const unsigned char *second_byte, const int buffer_length)
+static int32_t
+expected_message_length(unsigned char status, const unsigned char *second_byte, const size_t buffer_length)
 {
        /* Make sure this really is a valid status byte. */
        assert(is_status_byte(status));
@@ -319,9 +322,6 @@ expected_message_length(unsigned char status, const unsigned char *second_byte,
        /* We cannot use this routine for escaped events. */
        assert(!is_escape_byte(status));
 
-       /* Buffer length may be zero, for e.g. realtime messages. */
-       assert(buffer_length >= 0);
-
        /* Is this a metamessage? */
        if (status == 0xFF) {
                if (buffer_length < 2) {
@@ -382,9 +382,12 @@ expected_message_length(unsigned char status, const unsigned char *second_byte,
 }
 
 static int
-extract_sysex_event(const unsigned char *buf, const int buffer_length, smf_event_t *event, int *len, int last_status)
+extract_sysex_event(const unsigned char *buf, const size_t buffer_length, smf_event_t *event, uint32_t *len, int last_status)
 {
-       int status, message_length, vlq_length;
+       (void) last_status;
+       
+       int status;
+       int32_t vlq_length, message_length;
        const unsigned char *c = buf;
 
        status = *buf;
@@ -400,13 +403,13 @@ extract_sysex_event(const unsigned char *buf, const int buffer_length, smf_event
 
        c += vlq_length;
 
-       if (vlq_length + message_length >= buffer_length) {
+       if (vlq_length + (size_t)message_length >= buffer_length) {
                g_critical("End of buffer in extract_sysex_event().");
                return (-5);
        }
 
        event->midi_buffer_length = message_length;
-       event->midi_buffer = malloc(event->midi_buffer_length);
+       event->midi_buffer = (uint8_t*)malloc(event->midi_buffer_length);
        if (event->midi_buffer == NULL) {
                g_critical("Cannot allocate memory in extract_sysex_event(): %s", strerror(errno));
                return (-4);
@@ -421,9 +424,13 @@ extract_sysex_event(const unsigned char *buf, const int buffer_length, smf_event
 }
 
 static int
-extract_escaped_event(const unsigned char *buf, const int buffer_length, smf_event_t *event, int *len, int last_status)
+extract_escaped_event(const unsigned char *buf, const size_t buffer_length, smf_event_t *event, uint32_t *len, int last_status)
 {
-       int status, message_length, vlq_length;
+       (void) last_status;
+       
+       int status;
+       int32_t message_length = 0;
+       int32_t vlq_length = 0;
        const unsigned char *c = buf;
 
        status = *buf;
@@ -439,13 +446,13 @@ extract_escaped_event(const unsigned char *buf, const int buffer_length, smf_eve
 
        c += vlq_length;
 
-       if (vlq_length + message_length >= buffer_length) {
+       if (vlq_length + (size_t)message_length >= buffer_length) {
                g_critical("End of buffer in extract_escaped_event().");
                return (-5);
        }
 
        event->midi_buffer_length = message_length;
-       event->midi_buffer = malloc(event->midi_buffer_length);
+       event->midi_buffer = (uint8_t*)malloc(event->midi_buffer_length);
        if (event->midi_buffer == NULL) {
                g_critical("Cannot allocate memory in extract_escaped_event(): %s", strerror(errno));
                return (-4);
@@ -474,9 +481,10 @@ extract_escaped_event(const unsigned char *buf, const int buffer_length, smf_eve
  * Returns 0 iff everything went OK, value < 0 in case of error.
  */
 static int
-extract_midi_event(const unsigned char *buf, const int buffer_length, smf_event_t *event, int *len, int last_status)
+extract_midi_event(const unsigned char *buf, const size_t buffer_length, smf_event_t *event, uint32_t *len, int last_status)
 {
-       int status, message_length;
+       int status;
+       int32_t message_length;
        const unsigned char *c = buf;
 
        assert(buffer_length > 0);
@@ -508,13 +516,13 @@ extract_midi_event(const unsigned char *buf, const int buffer_length, smf_event_
        if (message_length < 0)
                return (-3);
 
-       if (message_length - 1 > buffer_length - (c - buf)) {
+       if ((size_t)message_length > buffer_length - (c - buf) + 1) {
                g_critical("End of buffer in extract_midi_event().");
                return (-5);
        }
 
        event->midi_buffer_length = message_length;
-       event->midi_buffer = malloc(event->midi_buffer_length);
+       event->midi_buffer = (uint8_t*)malloc(event->midi_buffer_length);
        if (event->midi_buffer == NULL) {
                g_critical("Cannot allocate memory in extract_midi_event(): %s", strerror(errno));
                return (-4);
@@ -537,7 +545,9 @@ extract_midi_event(const unsigned char *buf, const int buffer_length, smf_event_
 static smf_event_t *
 parse_next_event(smf_track_t *track)
 {
-       int time = 0, len, buffer_length;
+       uint32_t time = 0;
+       uint32_t len;
+       size_t buffer_length;
        unsigned char *c, *start;
 
        smf_event_t *event = smf_event_new();
@@ -554,7 +564,7 @@ parse_next_event(smf_track_t *track)
        assert(buffer_length > 0);
 
        /* First, extract time offset from previous event. */
-       if (extract_vlq(c, buffer_length, &time, &len))
+       if (smf_extract_vlq(c, buffer_length, &time, &len))
                goto error;
 
        c += len;
@@ -588,7 +598,7 @@ error:
  * and makes ordinary, zero-terminated string from it.  May return NULL if there was any problem.
  */ 
 static char *
-make_string(const unsigned char *buf, const int buffer_length, int len)
+make_string(const unsigned char *buf, const size_t buffer_length, uint32_t len)
 {
        char *str;
 
@@ -601,7 +611,7 @@ make_string(const unsigned char *buf, const int buffer_length, int len)
                len = buffer_length;
        }
 
-       str = malloc(len + 1);
+       str = (char*)malloc(len + 1);
        if (str == NULL) {
                g_critical("Cannot allocate memory in make_string().");
                return (NULL);
@@ -641,7 +651,8 @@ smf_event_is_textual(const smf_event_t *event)
 char *
 smf_event_extract_text(const smf_event_t *event)
 {
-       int string_length = -1, length_length = -1;
+       uint32_t string_length = 0;
+       uint32_t length_length = 0;
 
        if (!smf_event_is_textual(event))
                return (NULL);
@@ -651,14 +662,14 @@ smf_event_extract_text(const smf_event_t *event)
                return (NULL);
        }
 
-       extract_vlq((void *)&(event->midi_buffer[2]), event->midi_buffer_length - 2, &string_length, &length_length);
+       smf_extract_vlq((const unsigned char*)(void *)&(event->midi_buffer[2]), event->midi_buffer_length - 2, &string_length, &length_length);
 
        if (string_length <= 0) {
                g_critical("smf_event_extract_text: truncated MIDI message.");
                return (NULL);
        }
 
-       return (make_string((void *)(&event->midi_buffer[2] + length_length), event->midi_buffer_length - 2 - length_length, string_length));
+       return (make_string((const unsigned char*)(void *)(&event->midi_buffer[2] + length_length), event->midi_buffer_length - 2 - length_length, string_length));
 }
 
 /**
@@ -714,6 +725,8 @@ smf_event_length_is_valid(const smf_event_t *event)
 {
        assert(event);
        assert(event->midi_buffer);
+       
+       int32_t expected;
 
        if (event->midi_buffer_length < 1)
                return (0);
@@ -722,9 +735,10 @@ smf_event_length_is_valid(const smf_event_t *event)
        if (smf_event_is_sysex(event))
                return (1);
 
-       if (event->midi_buffer_length != expected_message_length(event->midi_buffer[0],
-               &(event->midi_buffer[1]), event->midi_buffer_length - 1)) {
 
+       expected = expected_message_length(event->midi_buffer[0],
+                       &(event->midi_buffer[1]), event->midi_buffer_length - 1);
+       if (expected < 0 || event->midi_buffer_length != (size_t)expected) {
                return (0);
        }
 
@@ -787,12 +801,12 @@ parse_mtrk_chunk(smf_track_t *track)
 }
 
 /**
- * Allocate buffer of proper size and read file contents into it.  Close file afterwards.
+ * Allocate buffer of proper size and read file contents into it.
  */
 static int
-load_file_into_buffer(void **file_buffer, int *file_buffer_length, const char *file_name)
+load_file_into_buffer(void **file_buffer, size_t *file_buffer_length, FILE* stream)
 {
-       FILE *stream = fopen(file_name, "r");
+       long offset;
 
        if (stream == NULL) {
                g_critical("Cannot open input file: %s", strerror(errno));
@@ -806,12 +820,13 @@ load_file_into_buffer(void **file_buffer, int *file_buffer_length, const char *f
                return (-2);
        }
 
-       *file_buffer_length = ftell(stream);
-       if (*file_buffer_length == -1) {
+       offset = ftell(stream);
+       if (offset < 0) {
                g_critical("ftell(3) failed: %s", strerror(errno));
 
                return (-3);
        }
+       *file_buffer_length = (size_t)offset;
 
        if (fseek(stream, 0, SEEK_SET)) {
                g_critical("fseek(3) failed: %s", strerror(errno));
@@ -822,22 +837,17 @@ load_file_into_buffer(void **file_buffer, int *file_buffer_length, const char *f
        *file_buffer = malloc(*file_buffer_length);
        if (*file_buffer == NULL) {
                g_critical("malloc(3) failed: %s", strerror(errno));
-
+               
                return (-5);
        }
 
        if (fread(*file_buffer, 1, *file_buffer_length, stream) != *file_buffer_length) {
                g_critical("fread(3) failed: %s", strerror(errno));
-
+               free (*file_buffer);
+               *file_buffer = NULL;
                return (-6);
        }
        
-       if (fclose(stream)) {
-               g_critical("fclose(3) failed: %s", strerror(errno));
-
-               return (-7);
-       }
-
        return (0);
 }
 
@@ -846,7 +856,7 @@ load_file_into_buffer(void **file_buffer, int *file_buffer_length, const char *f
  * \return SMF or NULL, if loading failed.
   */
 smf_t *
-smf_load_from_memory(const void *buffer, const int buffer_length)
+smf_load_from_memory(const void *buffer, const size_t buffer_length)
 {
        int i;
 
@@ -870,6 +880,7 @@ smf_load_from_memory(const void *buffer, const int buffer_length)
                if (parse_mtrk_chunk(track)) {
                        g_warning("SMF warning: Cannot load track.");
                        smf_track_delete(track);
+                       continue;
                }
 
                track->file_buffer = NULL;
@@ -886,7 +897,7 @@ smf_load_from_memory(const void *buffer, const int buffer_length)
 
        smf->file_buffer = NULL;
        smf->file_buffer_length = 0;
-       smf->next_chunk_offset = -1;
+       smf->next_chunk_offset = 0;
 
        return (smf);
 }
@@ -894,17 +905,17 @@ smf_load_from_memory(const void *buffer, const int buffer_length)
 /**
  * Loads SMF file.
  *
- * \param file_name Path to the file.
+ * \param file Open file.
  * \return SMF or NULL, if loading failed.
  */
 smf_t *
-smf_load(const char *file_name)
+smf_load(FILE *file)
 {
-       int file_buffer_length;
+       size_t file_buffer_length;
        void *file_buffer;
        smf_t *smf;
 
-       if (load_file_into_buffer(&file_buffer, &file_buffer_length, file_name))
+       if (load_file_into_buffer(&file_buffer, &file_buffer_length, file))
                return (NULL);
 
        smf = smf_load_from_memory(file_buffer, file_buffer_length);