From a5a278c99e8244723da1fe4f3c7e5c670a037c3b Mon Sep 17 00:00:00 2001
From: Kubat <mael.martin31@gmail.com>
Date: Tue, 19 May 2020 11:48:35 +0200
Subject: [PATCH] Seems ok, but only get a length of 0, but mkvinfo get the
 correct one

---
 LICENSE             |  2 +-
 inc/common/common.h |  9 +++++++
 inc/lektor/mkv.h    |  2 +-
 src/common.c        | 13 ++++++++++
 src/main/debug.c    |  4 +--
 src/mkv/mkv.c       | 60 +++++++++++++++++++++++++++++++--------------
 6 files changed, 68 insertions(+), 22 deletions(-)

diff --git a/LICENSE b/LICENSE
index 58c0cabf..bc67651d 100644
--- a/LICENSE
+++ b/LICENSE
@@ -10,4 +10,4 @@ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
 OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
-THIS SOFTWARE.
\ No newline at end of file
+THIS SOFTWARE.
diff --git a/inc/common/common.h b/inc/common/common.h
index df31e411..3831a078 100644
--- a/inc/common/common.h
+++ b/inc/common/common.h
@@ -4,6 +4,11 @@
 #include <unistd.h>
 #include <stdint.h>
 
+/* May be usefull (gcc, see something else for clang):
+   __FLOAT_WORD_ORDER__
+   __ORDER_LITTLE_ENDIAN__
+   __ORDER_BIG_ENDIAN__ */
+
 #define not_implemented() __not_implemented(__func__,__FILE__,__LINE__)
 extern void __not_implemented(const char *func, char *file, int line);
 
@@ -27,6 +32,10 @@ uint32_t be_uint32_t(const uint8_t bytes[], size_t n);
    Restriction: n <= 8 */
 uint64_t be_uint64_t(const uint8_t bytes[], size_t n);
 
+/* Same as `be_uint64_t` but for Big-endian doubles.
+   Restriction: n <= 8 */
+double be_double_t(const uint8_t bytes[], size_t n);
+
 /* Trim the string `str` of the char `c` from the right and the left.
    The string may not be null terminated.
    Returns a pointer to the the trimmed string
diff --git a/inc/lektor/mkv.h b/inc/lektor/mkv.h
index 692b9f7d..c2d4efd0 100644
--- a/inc/lektor/mkv.h
+++ b/inc/lektor/mkv.h
@@ -49,7 +49,7 @@ int kara_metadata_read(struct kara_metadata *dst, const char *filename);
 
 /* Reads the duration of the .mkv file `filename`. Returns 0 on success
    and -1 on error. */
-int kara_read_length(size_t *len, const char *filename);
+int kara_read_length(double *len, const char *filename);
 
 /* Write metadata to a mkv file. Returns 0 on success and -1 on error */
 int kara_metadata_write(struct kara_metadata *mdt, const char *filename, const char *mkvpropedit);
diff --git a/src/common.c b/src/common.c
index bb330464..705f096d 100644
--- a/src/common.c
+++ b/src/common.c
@@ -33,6 +33,19 @@ be_uint32_t(const uint8_t bytes[], size_t n)
     return res;
 }
 
+double
+be_double_t(const uint8_t bytes[], size_t n)
+{
+    union {
+        uint8_t _bytes[8];
+        double _double;
+    } res;
+    for (size_t i = 0; i < n; ++i) {
+        res._bytes[i] = bytes[i];
+    }
+    return res._double;
+}
+
 uint64_t
 be_uint64_t(const uint8_t bytes[], size_t n)
 {
diff --git a/src/main/debug.c b/src/main/debug.c
index 88680a3f..2798d281 100644
--- a/src/main/debug.c
+++ b/src/main/debug.c
@@ -4,7 +4,7 @@
 int
 main(int argc, char **argv)
 {
-    size_t len = 0;
+    double len = 0;
 
     if (argc != 2)
         return 1;
@@ -12,6 +12,6 @@ main(int argc, char **argv)
     if (kara_read_length(&len, argv[1]) < 0)
         return 2;
 
-    printf("Kara length: %ld\n", len);
+    printf("Kara length: %f\n", len);
     return 0;
 }
diff --git a/src/mkv/mkv.c b/src/mkv/mkv.c
index 7f0c9e2e..da4c86c5 100644
--- a/src/mkv/mkv.c
+++ b/src/mkv/mkv.c
@@ -131,6 +131,31 @@ mkv_read_uint(struct bufferfd *bf, uint64_t *res)
     return n + (ssize_t) data_len;
 }
 
+/* From https://www.matroska.org/technical/specs/index.html:
+   Float - Big-endian, defined for 4 and 8 octets (32, 64 bits).
+   Here we always return a double. */
+static ssize_t
+mkv_read_float(struct bufferfd *bf, double *res)
+{
+    uint8_t data[8];
+    uint64_t data_len;
+    ssize_t n;
+
+    if ((n = mkv_read_element_length(bf, &data_len)) < 0 || 8 < data_len)
+        return -1;
+
+    if (data_len == 0)
+        *res = 0.;
+    else {
+        if (bufferfd_bytes(bf, data_len, data) < 0)
+            return -1;
+
+        *res = be_double_t(data, data_len);
+    }
+
+    return n + (ssize_t) data_len;
+}
+
 /*
 static ssize_t mkv_read_binary(struct bufferfd * bf, size_t max, uint8_t * res)
 {
@@ -500,11 +525,10 @@ kara_read_tags(struct bufferfd *bf, struct kara_metadata *dst)
 }
 
 static int
-kara_read_segment_info(struct bufferfd *bf, size_t *len)
+kara_read_segment_info(struct bufferfd *bf, double *len)
 {
-    /* TODO: Read correct elements, Duration and TimestampScale,
-       the result will be `*len = Duration * TimestampScale`. */
     uint64_t data_len;
+    uint64_t scale = 1;
 
     if (mkv_read_element_length(bf, &data_len) < 0)
         return -1;
@@ -512,34 +536,34 @@ kara_read_segment_info(struct bufferfd *bf, size_t *len)
     while (data_len > 0) {
         ssize_t n;
         uint32_t eid;
-        uint64_t elen;
 
-        if ((n = mkv_read_element_id(bf, &eid)) < 0) {
+        if ((n = mkv_read_element_id(bf, &eid)) < 0)
             return -1;
-        }
 
         data_len -= n;
 
-        if ((n = mkv_read_element_length(bf, &elen)) < 0)
-            return -1;
-
-        data_len -= (n + elen);
-
-        /* Find what we need */
-
         if (eid == EBML_MKV_SEG_DURATION) {
-            /* HANDLE (TODO) */
-            *len = 1;
+            if ((n = mkv_read_float(bf, len)) < 0)
+                return -1;
+        }
+
+        else if (eid == EBML_MKV_SEG_TS_SCALE) {
+            if ((n = mkv_read_uint(bf, &scale)) < 0)
+                return -1;
         }
 
-        bufferfd_skip(bf, elen);
+        else if ((n = mkv_skip_element(bf)) < 0)
+                return -1;
+
+        data_len -= n;
     }
 
+    *len *= scale;
     return 0;
 }
 
 int
-kara_read_length(size_t *len, const char *filename)
+kara_read_length(double *len, const char *filename)
 {
     errno = 0;
     int status_code = -1;
@@ -562,7 +586,7 @@ kara_read_length(size_t *len, const char *filename)
     if (header_len < 0)
         goto error;
 
-    *len = 0;
+    *len = 0.;
 
     for (;;) {
         if (mkv_read_element_id(&file, &eid) < 0)
-- 
GitLab