1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "gtest/gtest.h"
7 #include "mp4parse.h"
8 
9 #include <stdint.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <algorithm>
13 #include <vector>
14 
15 static intptr_t
error_reader(uint8_t * buffer,uintptr_t size,void * userdata)16 error_reader(uint8_t* buffer, uintptr_t size, void* userdata)
17 {
18   return -1;
19 }
20 
21 struct read_vector {
22   explicit read_vector(FILE* file, size_t length);
23   explicit read_vector(size_t length);
24 
25   size_t location;
26   std::vector<uint8_t> buffer;
27 };
28 
read_vector(FILE * file,size_t length)29 read_vector::read_vector(FILE* file, size_t length)
30  : location(0)
31 {
32   buffer.resize(length);
33   size_t read = fread(buffer.data(), sizeof(decltype(buffer)::value_type),
34       buffer.size(), file);
35   buffer.resize(read);
36 }
37 
read_vector(size_t length)38 read_vector::read_vector(size_t length)
39   : location(0)
40 {
41   buffer.resize(length, 0);
42 }
43 
44 static intptr_t
vector_reader(uint8_t * buffer,uintptr_t size,void * userdata)45 vector_reader(uint8_t* buffer, uintptr_t size, void* userdata)
46 {
47   if (!buffer || !userdata) {
48     return -1;
49   }
50 
51   auto source = reinterpret_cast<read_vector*>(userdata);
52   if (source->location > source->buffer.size()) {
53     return -1;
54   }
55   uintptr_t available = source->buffer.size() - source->location;
56   uintptr_t length = std::min(available, size);
57   memcpy(buffer, source->buffer.data() + source->location, length);
58   source->location += length;
59   return length;
60 }
61 
TEST(rust,MP4MetadataEmpty)62 TEST(rust, MP4MetadataEmpty)
63 {
64   Mp4parseStatus rv;
65   Mp4parseIo io;
66 
67   // Shouldn't be able to read with no context.
68   rv = mp4parse_read(nullptr);
69   EXPECT_EQ(rv, MP4PARSE_STATUS_BAD_ARG);
70 
71   // Shouldn't be able to wrap an Mp4parseIo with null members.
72   io = { nullptr, nullptr };
73   Mp4parseParser* context = mp4parse_new(&io);
74   EXPECT_EQ(context, nullptr);
75 
76   io = { nullptr, &io };
77   context = mp4parse_new(&io);
78   EXPECT_EQ(context, nullptr);
79 
80   // FIXME: this should probably be accepted.
81   io = { error_reader, nullptr };
82   context = mp4parse_new(&io);
83   EXPECT_EQ(context, nullptr);
84 
85   // Read method errors should propagate.
86   io = { error_reader, &io };
87   context = mp4parse_new(&io);
88   ASSERT_NE(context, nullptr);
89   rv = mp4parse_read(context);
90   EXPECT_EQ(rv, MP4PARSE_STATUS_IO);
91   mp4parse_free(context);
92 
93   // Short buffers should fail.
94   read_vector buf(0);
95   io = { vector_reader, &buf };
96   context = mp4parse_new(&io);
97   ASSERT_NE(context, nullptr);
98   rv = mp4parse_read(context);
99   EXPECT_EQ(rv, MP4PARSE_STATUS_INVALID);
100   mp4parse_free(context);
101 
102   buf.buffer.reserve(4097);
103   context = mp4parse_new(&io);
104   ASSERT_NE(context, nullptr);
105   rv = mp4parse_read(context);
106   EXPECT_EQ(rv, MP4PARSE_STATUS_INVALID);
107   mp4parse_free(context);
108 
109   // Empty buffers should fail.
110   buf.buffer.resize(4097, 0);
111   context = mp4parse_new(&io);
112   rv = mp4parse_read(context);
113   EXPECT_EQ(rv, MP4PARSE_STATUS_UNSUPPORTED);
114   mp4parse_free(context);
115 }
116 
TEST(rust,MP4Metadata)117 TEST(rust, MP4Metadata)
118 {
119   FILE* f = fopen("street.mp4", "rb");
120   ASSERT_TRUE(f != nullptr);
121   // Read just the moov header to work around the parser
122   // treating mid-box eof as an error.
123   //read_vector reader = read_vector(f, 1061);
124   struct stat s;
125   ASSERT_EQ(0, fstat(fileno(f), &s));
126   read_vector reader = read_vector(f, s.st_size);
127   fclose(f);
128 
129   Mp4parseIo io = { vector_reader, &reader };
130   Mp4parseParser* context = mp4parse_new(&io);
131   ASSERT_NE(nullptr, context);
132 
133   Mp4parseStatus rv = mp4parse_read(context);
134   EXPECT_EQ(MP4PARSE_STATUS_OK, rv);
135 
136   uint32_t tracks = 0;
137   rv = mp4parse_get_track_count(context, &tracks);
138   EXPECT_EQ(MP4PARSE_STATUS_OK, rv);
139   EXPECT_EQ(2U, tracks);
140 
141   mp4parse_free(context);
142 }
143