forked from NetworkAndSoftware/gopro2gpx
-
Notifications
You must be signed in to change notification settings - Fork 0
/
goprofilenames.c
192 lines (169 loc) · 5.15 KB
/
goprofilenames.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
// Sun Jul 21 09:34:39 DST 2019
// Copyright Michiel van Wessem
#include "goprofilenames.h"
#include "utils.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "mystring.h"
#include "platform.h"
#include <ctype.h>
// see https://gopro.com/help/articles/question_answer/GoPro-Camera-File-Naming-Convention
char* make_gopro_mp4_name(int chapter, int file_number, file_name_scheme scheme)
{
char* name = malloc(12 + 1);
switch (scheme)
{
default:
case hero_6_7_avc:
sprintf(name, "GH%02d%04d.MP4", chapter + 1, file_number);
break;
case hero_6_7_hevc:
sprintf(name, "GX%02d%04d.MP4", chapter + 1, file_number);
break;
case hero_fusion_front:
if (chapter == 0)
sprintf(name, "GPFR%04d.MP4", file_number);
else
sprintf(name, "GF%02d%04d.MP4", chapter, file_number);
break;
case hero_fusion_back:
if (chapter == 0)
sprintf(name, "GPBK%04d.MP4", file_number);
else
sprintf(name, "GB%02d%04d.MP4", chapter, file_number);
break;
case pre_hero_6:
if (chapter == 0)
sprintf(name, "GOPR%04d.MP4", file_number);
else
sprintf(name, "GP%2d%4d.MP4", chapter, file_number);
break;
}
return name;
}
node* make_node_if_exists(int file_number, node** filenames, const char* directory, int chapter, file_name_scheme scheme)
{
char* gopro_mp4_name = make_gopro_mp4_name(chapter, file_number, scheme);
char* fullname;
if (directory == NULL)
fullname = gopro_mp4_name;
else
{
fullname = malloc(strlen(directory) + 1 + 12 + 1);
sprintf(fullname, "%s%s%s", directory, preferred_path_separator, gopro_mp4_name);
free(gopro_mp4_name);
}
if (!file_exists(fullname))
{
free(fullname);
return NULL;
}
return list_node(fullname);
}
// see https://gopro.com/help/articles/question_answer/GoPro-Camera-File-Naming-Convention
// ReSharper disable CppLocalVariableMightNotBeInitialized
node* get_related_filenames(const char* given_filename, int is_singlefile, int *index_of_provided_file_name)
{
*index_of_provided_file_name = 0;
const char* basename = strrpbrk(given_filename, path_separators);
if (basename == NULL)
basename = given_filename;
else
++basename;
if (is_singlefile || strlen(basename) != 12 || 0 != strcasecmp(basename + 8, ".MP4"))
return list_node(given_filename);
char level_1[3];
char level_2[3];
int file_number;
if (3 != sscanf(basename, "%2s%2s%4d", level_1, level_2, &file_number) || file_number == 0) // NOLINT(cert-err34-c)
return list_node(given_filename);
const int level_2_is_number = isdigit(level_2[0]) && isdigit(level_2[1]);
int level_2_as_number; // meaningless if !level_2_is_number
if (level_2_is_number)
{
level_2_as_number = 10 * (level_2[0] - '0') + level_2[1] - '0';
if (level_2_as_number == 0)
return list_node(given_filename);
}
// Now find adjacent chapters
enum file_name_scheme scheme;
int zero_based_chapter;
if (!strcasecmp(level_1, "GH"))
{
if (!level_2_is_number)
return list_node(given_filename);
scheme = hero_6_7_avc;
zero_based_chapter = level_2_as_number - 1;
}
else if (!strcasecmp(level_1, "GX"))
{
if (!level_2_is_number)
return list_node(given_filename);
scheme = hero_6_7_hevc;
zero_based_chapter = level_2_as_number - 1;
}
else if (!strcasecmp(level_1, "GP"))
{
if (level_2_is_number)
{
zero_based_chapter = level_2_as_number;
scheme = pre_hero_6;
}
else if (!strcasecmp(level_2, "FR"))
{
scheme = hero_fusion_front;
zero_based_chapter = 0;
}
else if (!strcasecmp(level_2, "BK"))
{
scheme = hero_fusion_back;
zero_based_chapter = 0;
}
else
return list_node(given_filename);
}
else if (!strcasecmp(level_1, "GO") && !strcasecmp(level_2, "PR"))
{ // Pre-Hero6, first chapter
zero_based_chapter = 0;
scheme = pre_hero_6;
}
else if (!strcasecmp(level_1, "GF") && level_2_is_number)
{
scheme = hero_fusion_front;
zero_based_chapter = level_2_as_number;
}
else if (!strcasecmp(level_1, "GB") && level_2_is_number)
{
scheme = hero_fusion_back;
zero_based_chapter = level_2_as_number;
}
else
return list_node(given_filename);
// look for lower and higher chapters
node* filenames = list_node(given_filename);
int l = 1;
char* buffer = strdup(given_filename);
char* token = strrtok(buffer, path_separators);
// this is a reverse search; if the first token found is the entire string, then there were no path separators at all and there is no directory,
char* directory = token == buffer ? NULL : buffer;
// TODO: look for lower and higher chapters
for (int i = zero_based_chapter - 1; i >= 0; i--) {
node* n = make_node_if_exists(file_number, &filenames, directory, i, scheme);
if (!n)
break;
list_insert(n, &filenames);
(*index_of_provided_file_name)++;
l++;
}
for (int i = zero_based_chapter + 1; i < 100; i++) {
node* n = make_node_if_exists(file_number, &filenames, directory, i, scheme);
if (!n)
break;
list_append(n, filenames);
l++;
}
free(buffer);
return filenames;
}
// ReSharper enable CppLocalVariableMightNotBeInitialized