| 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 |