GCC Code Coverage Report


Directory: ./
File: fseq/FSEQUtils.cpp
Date: 2026-10-29 08:11:58
Exec Total Coverage
Lines: 260 284 91.5%
Functions: 7 8 87.5%
Branches: 187 297 63.0%

Line Branch Exec Source
1
2 #include <getopt.h>
3 #include <inttypes.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include <algorithm>
9 #include <list>
10 #include <string>
11 #include <vector>
12
13 #include "fppversion.h"
14 #include "log.h"
15
16 #include "FSEQFile.h"
17
18 void HexDump(const char* title, const void* data, int len, FPPLoggerInstance& facility, int perLine = 16);
19
20 3 void usage(char* appname) {
21 3 printf("Usage: %s [OPTIONS] FileName.fseq\n", appname);
22 3 printf("\n");
23 3 printf(" Options:\n");
24 3 printf(" -V - Print version information\n");
25 3 printf(" -v - verbose\n");
26 3 printf(" -o OUTPUTFILE - Filename for Output FSEQ\n");
27 3 printf(" -m FSEQFILE - FSEQ to merge onto the input, ignoring 0\n");
28 3 printf(" -M[ FSEQFILE - FSEQ to merge onto the input, copy 0\n");
29 3 printf(" -f # - FSEQ Version\n");
30 3 printf(" -c (none|zstd|zlib) - Compession type\n");
31 3 printf(" -l # - Compression level (-99 for default)\n");
32 3 printf(" -r (#-# | #+#) - Channel Range. Use - to separate start/end channel\n");
33 3 printf(" Use + to separate start channel + num channels\n");
34 3 printf(" If used before first -m/-M argument, sets a sparse range of output\n");
35 3 printf(" If used after -m/-M argument, sets a range to read from last merged sequence.\n");
36 3 printf(" If used before -d argument, sets the range to dump.\n");
37 3 printf(" -n - No Sparse. -r will only read the range, but the resulting fseq is not sparse.\n");
38 3 printf(" -j - Output the fseq file metadata to json\n");
39 3 printf(" -d - Dump the fseq data to stdout in human-readable format\n");
40 3 printf(" -h - This help output\n");
41 3 }
42 const char* outputFilename = nullptr;
43
44 class MergeFSEQ {
45 public:
46 6 MergeFSEQ(const std::string& f, bool cz) :
47 6 filename(f),
48 6 copyZero(cz) {}
49
50 std::string filename;
51 std::vector<std::pair<uint32_t, uint32_t>> ranges;
52 bool copyZero = false;
53 FSEQFile* srcFile = nullptr;
54 };
55
56 static std::list<MergeFSEQ> mergeFseqs;
57 static int fseqMajVersion = 2;
58 static int fseqMinVersion = 0;
59 static int compressionLevel = -99;
60 static bool verbose = false;
61 static std::vector<std::pair<uint32_t, uint32_t>> ranges;
62 static bool sparse = true;
63 static bool json = false;
64 static bool dump = false;
65 static V2FSEQFile::CompressionType compressionType = V2FSEQFile::CompressionType::zstd;
66
67 // Channel buffers here are sized to the channel space the FSEQ library writes
68 // (MAX_CHANNEL_SPACE in FSEQFile.cpp, == FPPD_MAX_CHANNELS). Channels past it
69 // are dropped on read and on write, so say so rather than silently producing a
70 // shorter file or dump.
71 static constexpr uint32_t CHANNEL_SPACE = 8192 * 1024;
72
73 32 static void warnIfBeyondChannelSpace(const std::vector<std::pair<uint32_t, uint32_t>>& rngs, uint32_t maxChannel) {
74 32 uint64_t wanted = 0;
75
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 32 times.
66 for (auto& r : rngs) {
76 34 wanted = std::max(wanted, (uint64_t)r.first + r.second);
77 }
78 32 wanted = std::min(wanted, (uint64_t)maxChannel);
79
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 31 times.
32 if (wanted > CHANNEL_SPACE) {
80
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 printf("Warning: only the first %u channels are used; channels %u-%" PRIu64 " are dropped.\n",
81 CHANNEL_SPACE, CHANNEL_SPACE + 1, wanted);
82 }
83 32 }
84
85 12 static void parseRanges(std::vector<std::pair<uint32_t, uint32_t>>& ranges, char* rng) {
86 12 char* end = rng;
87 12 int startc = strtol(rng, &end, 10);
88 12 int r = *end == '-';
89 12 end++;
90 12 int endc = strtol(end, &end, 10);
91
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 if (r) {
92
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 ranges.push_back(std::pair<uint32_t, uint32_t>(startc - 1, endc - startc + 1));
93 } else {
94
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 ranges.push_back(std::pair<uint32_t, uint32_t>(startc - 1, endc));
95 }
96 12 }
97
98 59 int parseArguments(int argc, char** argv) {
99 59 char* s = NULL;
100 int c;
101
102 59 int this_option_optind = optind;
103 while (1) {
104
1/2
✓ Branch 0 taken 173 times.
✗ Branch 1 not taken.
173 this_option_optind = optind ? optind : 1;
105 173 int option_index = 0;
106 static struct option long_options[] = {
107 { "help", no_argument, 0, 'h' },
108 { "output", required_argument, 0, 'o' },
109 { 0, 0, 0, 0 }
110 };
111
112 173 c = getopt_long(argc, argv, "c:l:o:f:r:m:M:hdjVvn", long_options, &option_index);
113
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 118 times.
173 if (c == -1) {
114 55 break;
115 }
116
117
14/14
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 29 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 10 times.
✓ Branch 7 taken 31 times.
✓ Branch 8 taken 3 times.
✓ Branch 9 taken 3 times.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 1 times.
118 switch (c) {
118 12 case 'r':
119
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 3 times.
12 if (mergeFseqs.empty()) {
120
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 parseRanges(ranges, optarg);
121 } else {
122
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 parseRanges(mergeFseqs.back().ranges, optarg);
123 }
124 12 break;
125 18 case 'j':
126 18 json = true;
127 18 break;
128 4 case 'd':
129 4 dump = true;
130 4 break;
131 1 case 'v':
132 1 verbose = true;
133 1 break;
134 29 case 'c':
135
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 12 times.
29 if (strcmp(optarg, "none") == 0) {
136 17 compressionType = V2FSEQFile::CompressionType::none;
137
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 9 times.
12 } else if (strcmp(optarg, "zlib") == 0) {
138 3 compressionType = V2FSEQFile::CompressionType::zlib;
139
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 } else if (strcmp(optarg, "zstd") == 0) {
140 8 compressionType = V2FSEQFile::CompressionType::zstd;
141 } else {
142
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 printf("Unknown compression type: %s\n", optarg);
143 1 exit(EXIT_FAILURE);
144 }
145 28 break;
146 2 case 'l':
147 2 compressionLevel = strtol(optarg, NULL, 10);
148 2 break;
149 10 case 'f': {
150 10 char* next = nullptr;
151 10 fseqMajVersion = strtol(optarg, &next, 10);
152
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8 times.
10 if (*next == '.') {
153 2 next++;
154 2 fseqMinVersion = strtol(next, &next, 10);
155 }
156 10 } break;
157 31 case 'o':
158 31 outputFilename = optarg;
159 31 break;
160 3 case 'm':
161
3/6
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
3 mergeFseqs.push_back(MergeFSEQ(optarg, false));
162 3 break;
163 3 case 'M':
164
3/6
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
3 mergeFseqs.push_back(MergeFSEQ(optarg, true));
165 3 break;
166 2 case 'n':
167 2 sparse = false;
168 2 break;
169 1 case 'V':
170
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 printVersionInfo();
171 1 exit(0);
172 1 case 'h':
173
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 usage(argv[0]);
174 1 exit(EXIT_SUCCESS);
175 1 default:
176
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 usage(argv[0]);
177 1 exit(EXIT_FAILURE);
178 }
179 114 }
180 55 return this_option_optind;
181 }
182
183 32 static std::string escape(const std::string& data) {
184 32 std::string out;
185
1/2
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
32 out.reserve(data.size() + 16);
186
2/2
✓ Branch 0 taken 375 times.
✓ Branch 1 taken 32 times.
407 for (char c : data) {
187 // Keep the existing \" and \\ escaping byte-identical; additionally
188 // escape C0 controls so filenames with newline etc. stay valid JSON.
189 // Header values with controls never reach here (binary placeholder),
190 // but baseName has no such gate.
191
4/7
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 370 times.
375 switch (c) {
192 3 case '"':
193 case '\\':
194
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 out.push_back('\\');
195
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 out.push_back(c);
196 3 break;
197 ✗ case '\b':
198 ✗ out.append("\\b");
199 ✗ break;
200 ✗ case '\f':
201 ✗ out.append("\\f");
202 ✗ break;
203 1 case '\n':
204
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 out.append("\\n");
205 1 break;
206 ✗ case '\r':
207 ✗ out.append("\\r");
208 ✗ break;
209 1 case '\t':
210
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 out.append("\\t");
211 1 break;
212 370 default:
213
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 370 times.
370 if ((unsigned char)c < 32) {
214 char u[7];
215 ✗ snprintf(u, sizeof(u), "\\u%04x", (unsigned char)c);
216 ✗ out.append(u);
217 } else {
218
1/2
✓ Branch 0 taken 370 times.
✗ Branch 1 not taken.
370 out.push_back(c);
219 }
220 370 break;
221 }
222 }
223 32 return out;
224 ✗ }
225 ✗ std::string getFPPDDir(const std::string& path) {
226 ✗ return "/tmp";
227 }
228 59 int main(int argc, char* argv[]) {
229 59 int idx = parseArguments(argc, argv);
230
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 54 times.
55 if (idx >= argc) {
231 1 usage(argv[0]);
232 1 return 1;
233 }
234
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 53 times.
54 if (verbose) {
235 1 SetLogLevel("debug");
236 } else {
237 53 SetLogFile("stderr", false);
238 }
239
2/4
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 54 times.
✗ Branch 3 not taken.
54 FSEQFile* src = FSEQFile::openFSEQFile(argv[idx]);
240
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 1 times.
54 if (src) {
241
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 35 times.
53 if (json) {
242 /*
243 getNumFrames() const { return m_seqNumFrames; }
244 int getStepTime() const { return m_seqStepTime; }
245 uint32_t getChannelCount() const { return m_seqChannelCount; }
246 uint64_t getUniqueId() const { return m_uniqueId; }
247 const std::string& getFilename() const { return m_filename; }
248 */
249
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 std::string fullName = src->getFilename();
250 18 size_t slash = fullName.find_last_of('/');
251
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
18 std::string baseName = (slash == std::string::npos) ? fullName : fullName.substr(slash + 1);
252
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
54 printf("{\"Name\": \"%s\", \"Version\": \"%d.%d\", \"ID\": \"%" PRIu64 "\", \"StepTime\": %d, \"NumFrames\": %d, \"MaxChannel\": %d, \"ChannelCount\": %d",
253
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
36 escape(baseName).c_str(),
254 src->getVersionMajor(), src->getVersionMinor(),
255 src->getUniqueId(),
256 src->getStepTime(),
257 src->getNumFrames(),
258
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 src->getMaxChannel(),
259 src->getChannelCount());
260
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 4 times.
18 if (!src->getVariableHeaders().empty()) {
261
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 printf(", \"variableHeaders\": {");
262 14 bool first = true;
263
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
28 for (auto& head : src->getVariableHeaders()) {
264
4/8
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 14 times.
✗ Branch 7 not taken.
14 if (head.code[0] > 32 && head.code[0] <= 127 && head.code[1] > 32 && head.code[1] <= 127) {
265
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 const auto& vd = head.getData();
266
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (vd.empty()) {
267 ✗ continue;
268 }
269 14 const char* raw = (const char*)vd.data();
270 14 size_t vlen = strnlen(raw, vd.size());
271
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 std::string vs(raw, vlen);
272 // Gate on the truncated view that is actually emitted:
273 // bytes past the first NUL are never printed, so they
274 // must not flip a truncated-ASCII value to binary.
275 14 bool allAscii = true;
276
2/2
✓ Branch 0 taken 113 times.
✓ Branch 1 taken 14 times.
127 for (unsigned char b : vs) {
277
2/4
✓ Branch 0 taken 113 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 113 times.
113 if (b < 32 || b > 127) {
278 ✗ allAscii = false;
279 ✗ break;
280 }
281 }
282
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 if (allAscii) {
283
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (!first) {
284 ✗ printf(", ");
285 } else {
286 14 first = false;
287 }
288
2/4
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
14 printf("\"%c%c\": \"%s\"", head.code[0], head.code[1], escape(vs).c_str());
289 } else {
290 ✗ if (!first) {
291 ✗ printf(", ");
292 } else {
293 ✗ first = false;
294 }
295 ✗ printf("\"%c%c\": \"<binary data of length %d>\"", head.code[0], head.code[1], (int)head.getDataLength());
296 }
297 14 }
298 }
299
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 printf("}");
300 }
301
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 1 times.
18 if (src->getVersionMajor() >= 2) {
302 17 V2FSEQFile* f = (V2FSEQFile*)src;
303
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 12 times.
17 if (!f->m_sparseRanges.empty()) {
304
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 printf(", \"Ranges\": [");
305 5 int first = true;
306
2/2
✓ Branch 0 taken 859 times.
✓ Branch 1 taken 5 times.
864 for (auto& a : f->m_sparseRanges) {
307
2/2
✓ Branch 0 taken 854 times.
✓ Branch 1 taken 5 times.
859 if (!first) {
308
1/2
✓ Branch 0 taken 854 times.
✗ Branch 1 not taken.
854 printf(",");
309 }
310 859 first = false;
311
1/2
✓ Branch 0 taken 859 times.
✗ Branch 1 not taken.
859 printf("{\"Start\": %d, \"Length\": %d}", a.first, a.second);
312 }
313
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 printf("]");
314 }
315
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 printf(", \"CompressionType\": %d", (int)f->m_compressionType);
316
2/4
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
17 printf(", \"CompressionTypeString\": \"%s\"", f->CompressionTypeString().c_str());
317 }
318
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 printf("}\n");
319
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 31 times.
53 } else if (dump) {
320
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (ranges.empty()) {
321
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 printf("No channel range specified\n");
322
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 delete src;
323 1 return 1;
324 }
325
326
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 src->setReadPattern(FSEQFile::ReadPattern::Bulk);
327
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 src->prepareRead(ranges);
328
329
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 warnIfBeyondChannelSpace(ranges, src->getMaxChannel());
330
331 char title[50];
332 3 uint8_t* data = (uint8_t*)malloc(CHANNEL_SPACE);
333
2/2
✓ Branch 0 taken 3041 times.
✓ Branch 1 taken 3 times.
3044 for (int x = 0; x < src->getNumFrames(); x++) {
334
1/2
✓ Branch 0 taken 3041 times.
✗ Branch 1 not taken.
3041 FSEQFile::FrameData* fdata = src->getFrame(x);
335
1/2
✓ Branch 0 taken 3041 times.
✗ Branch 1 not taken.
3041 fdata->readFrame(data, CHANNEL_SPACE);
336
1/2
✓ Branch 0 taken 3041 times.
✗ Branch 1 not taken.
3041 delete fdata;
337
338
2/2
✓ Branch 0 taken 3041 times.
✓ Branch 1 taken 3041 times.
6082 for (auto& r : ranges) {
339
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3041 times.
3041 if ((uint64_t)r.first >= CHANNEL_SPACE) {
340 ✗ continue;
341 }
342 3041 uint64_t len = r.second;
343
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 3021 times.
3041 if ((uint64_t)r.first + len > CHANNEL_SPACE) {
344 20 len = CHANNEL_SPACE - r.first;
345 }
346
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3041 times.
3041 uint64_t end = len == 0 ? r.first : (uint64_t)r.first + len - 1;
347 3041 snprintf(title, 50, "Frame: %d, Range: %d-%d", x, r.first, (int)end);
348
1/2
✓ Branch 0 taken 3041 times.
✗ Branch 1 not taken.
3041 HexDump(title, data + r.first, (int)len, VB_SEQUENCE, 16);
349 }
350 }
351 3 free(data);
352 } else {
353
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 31 times.
37 for (auto& f : mergeFseqs) {
354
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 FSEQFile* src = FSEQFile::openFSEQFile(f.filename);
355
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (src) {
356
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 src->setReadPattern(FSEQFile::ReadPattern::Bulk);
357 6 f.srcFile = src;
358
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (f.ranges.empty()) {
359
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 f.ranges.push_back(std::pair<uint32_t, uint32_t>(0, CHANNEL_SPACE));
360 }
361 }
362 }
363
364
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 30 times.
31 if (outputFilename == nullptr) {
365
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!verbose) {
366 1 printf("No output file defined!\n");
367 1 printf("Use -v to enable verbose output printing for file information.\n");
368 }
369
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 delete src;
370 1 return 0;
371 }
372
373
2/4
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
60 FSEQFile* dest = FSEQFile::createFSEQFile(outputFilename,
374 fseqMajVersion,
375 compressionType,
376 compressionLevel);
377
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 29 times.
30 if (dest == nullptr) {
378 1 printf("Failed to create FSEQ file (returned nullptr)!\n");
379
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 delete src;
380 1 return 1;
381 }
382 29 dest->enableMinorVersionFeatures(fseqMinVersion);
383
384
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 4 times.
29 if (ranges.empty()) {
385
1/2
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
25 ranges.push_back(std::pair<uint32_t, uint32_t>(0, 999999999));
386
3/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
4 } else if (fseqMajVersion == 2 && sparse) {
387 2 V2FSEQFile* f = (V2FSEQFile*)dest;
388 2 f->m_sparseRanges = ranges;
389 }
390 29 warnIfBeyondChannelSpace(ranges, src->getMaxChannel());
391 29 src->setReadPattern(FSEQFile::ReadPattern::Bulk);
392 29 src->prepareRead(ranges);
393
394 29 dest->initializeFromFSEQ(*src);
395 29 dest->writeHeader();
396
397 29 uint8_t* data = (uint8_t*)calloc(1, CHANNEL_SPACE);
398 29 uint8_t* mergedata = (uint8_t*)malloc(CHANNEL_SPACE);
399 29 memset(mergedata, 0, CHANNEL_SPACE);
400
2/2
✓ Branch 0 taken 36316 times.
✓ Branch 1 taken 29 times.
36345 for (int x = 0; x < src->getNumFrames(); x++) {
401 36316 FSEQFile::FrameData* fdata = src->getFrame(x);
402 36316 fdata->readFrame(data, CHANNEL_SPACE);
403
1/2
✓ Branch 0 taken 36316 times.
✗ Branch 1 not taken.
36316 delete fdata;
404
405
2/2
✓ Branch 0 taken 3101 times.
✓ Branch 1 taken 36316 times.
39417 for (auto& m : mergeFseqs) {
406
1/2
✓ Branch 0 taken 3101 times.
✗ Branch 1 not taken.
3101 if (m.srcFile) {
407
1/2
✓ Branch 0 taken 3101 times.
✗ Branch 1 not taken.
3101 FSEQFile::FrameData* fdata = m.srcFile->getFrame(x);
408
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 3091 times.
3101 if (!fdata) {
409 10 continue; // past the end of a shorter merge file
410 }
411
1/2
✓ Branch 0 taken 3091 times.
✗ Branch 1 not taken.
3091 fdata->readFrame(mergedata, CHANNEL_SPACE);
412
1/2
✓ Branch 0 taken 3091 times.
✗ Branch 1 not taken.
3091 delete fdata;
413
2/2
✓ Branch 0 taken 3091 times.
✓ Branch 1 taken 3091 times.
6182 for (auto& r : m.ranges) {
414 // Merge ranges come from the CLI, but never trust an
415 // index past the buffer: stop instead of corrupting heap.
416
4/4
✓ Branch 0 taken 422503704 times.
✓ Branch 1 taken 3071 times.
✓ Branch 2 taken 422503684 times.
✓ Branch 3 taken 20 times.
422506775 for (uint64_t y = 0, idx = r.first; y < r.second && idx < CHANNEL_SPACE; ++y, ++idx) {
417
4/4
✓ Branch 0 taken 419430180 times.
✓ Branch 1 taken 3073504 times.
✓ Branch 2 taken 167772180 times.
✓ Branch 3 taken 251658000 times.
422503684 if (mergedata[idx] || m.copyZero) {
418 170845684 data[idx] = mergedata[idx];
419 170845684 mergedata[idx] = 0;
420 }
421 }
422 }
423 }
424 }
425 36316 dest->addFrame(x, data);
426 }
427 29 free(data);
428 29 free(mergedata);
429 29 dest->finalize();
430
431
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 if (!strcmp(outputFilename, "-memory-")) {
432 ✗ printf("size: %d\n", (int)dest->getMemoryBuffer().size());
433 }
434
435
1/2
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
29 delete dest;
436
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 29 times.
35 for (auto& a : mergeFseqs) {
437
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (a.srcFile) {
438
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 delete a.srcFile;
439 }
440 }
441 }
442
1/2
✓ Branch 0 taken 50 times.
✗ Branch 1 not taken.
50 delete src;
443 }
444
445 51 return 0;
446 }
447