2 Copyright (c) 2005-2013, John Hurst
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 using namespace ASDCP;
37 using Kumu::DefaultLogSink;
40 //------------------------------------------------------------------------------------------
42 // command line option parser class
44 static const char* PROGRAM_NAME = "klvsplit"; // program name for messages
45 typedef std::list<std::string> FileList_t;
47 // Increment the iterator, test for an additional non-option command line argument.
48 // Causes the caller to return if there are no remaining arguments or if the next
49 // argument begins with '-'.
50 #define TEST_EXTRA_ARG(i,c) if ( ++i >= argc || argv[(i)][0] == '-' ) \
52 fprintf(stderr, "Argument not found for option -%c.\n", (c)); \
58 banner(FILE* stream = stdout)
62 Copyright (c) 2005-2013 John Hurst\n\
63 %s is part of the asdcplib DCP tools package.\n\
64 asdcplib may be copied only under the terms of the license found at\n\
65 the top of every file in the asdcplib distribution kit.\n\n\
66 Specify the -h (help) option for further information about %s\n\n",
67 PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME, PROGRAM_NAME);
72 usage(FILE* stream = stdout)
75 USAGE: %s [-l <limit>] [-p <prefix>] [-s <suffix>] [-u|-U] [-v] \n\
76 (<type-name>|<type-ul>) <mxf-filename>+\n\
82 -d - List the valid packet type names\n\
83 -h | -help - Show help\n\
84 -l <limit> - Stop processing after <limit> matching packets\n\
85 -p <prefix> - Use <prefix> to start output filenames (default\n\
86 uses the input filename minus any extension\n\
87 -s <suffix> - Append <suffix> to output filenames\n\
88 -u - Unwrap the packet value (i.e., do not output KL)\n\
89 -U - Do not unwrap (default)\n\
90 -v - Verbose. Prints informative messages to stderr\n\
91 -V - Show version information\n\
93 NOTES: o There is no option grouping, all options must be distinct arguments.\n\
94 o All option arguments must be separated from the option by whitespace.\n\
95 \n", PROGRAM_NAME, PROGRAM_NAME, PROGRAM_NAME);
105 bool error_flag; // true if the given options are in error or not complete
106 bool version_flag; // true if the version display option was selected
107 bool help_flag; // true if the help display option was selected
108 bool verbose_flag; // true if the informative messages option was selected
109 bool unwrap_mode; // true if we are to strip the K and L before writing
111 ASDCP::UL target_ul; // a UL value identifying the packets to be extracted
112 ui64_t extract_limit; // limit extraction to the given number of packets
113 std::string prefix; // output filename prefix
114 std::string suffix; // output filename suffix
115 FileList_t inFileList; // File to operate on
117 CommandOptions(int argc, const char** argv, const ASDCP::Dictionary& dict) :
118 error_flag(true), version_flag(false), help_flag(false),
119 verbose_flag(false), unwrap_mode(false), list_mode(false), extract_limit(ui64_C(-1))
121 for ( int i = 1; i < argc; ++i )
124 if ( (strcmp( argv[i], "-help") == 0) )
130 if ( argv[i][0] == '-' && isalpha(argv[i][1]) && argv[i][2] == 0 )
132 switch ( argv[i][1] )
134 case 'd': list_mode = true; break;
135 case 'h': help_flag = true; break;
138 TEST_EXTRA_ARG(i, 'l');
139 extract_limit = Kumu::xabs(strtoll(argv[i], 0, 10));
143 TEST_EXTRA_ARG(i, 'p');
148 TEST_EXTRA_ARG(i, 's');
152 case 'u': unwrap_mode = true; break;
153 case 'U': unwrap_mode = false; break;
154 case 'V': version_flag = true; break;
155 case 'v': verbose_flag = true; break;
158 fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
162 else if ( argv[i][0] != '-' )
164 if ( ! target_ul.HasValue() )
166 if ( ! target_ul.DecodeHex(argv[i]) )
168 const ASDCP::MDDEntry *e = dict.FindSymbol(argv[i]);
174 if ( ! target_ul.HasValue() )
176 fprintf(stderr, "Value is not a UL or valid object name: %s\n", argv[i]);
182 inFileList.push_back(argv[i]);
187 fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
192 if ( help_flag || version_flag )
197 if ( inFileList.empty() )
199 fputs("Input filename(s) required.\n", stderr);
203 if ( ! target_ul.HasValue() )
205 fputs("Packet UL not set. Use %s -u <ul> or keyword.\n", stderr);
215 //---------------------------------------------------------------------------------------------------
219 main(int argc, const char** argv)
221 const Dictionary *dict = &DefaultCompositeDict();
222 CommandOptions Options(argc, argv, *dict);
224 if ( Options.version_flag )
227 if ( Options.help_flag )
230 if ( Options.version_flag || Options.help_flag )
233 if ( Options.error_flag )
235 fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME);
239 if ( Options.list_mode )
241 DefaultLogSink().UnsetFilterFlag(Kumu::LOG_ALLOW_WARN);
245 while ( di < MDD_Max )
247 const MDDEntry& e = dict->Type(di);
249 if ( e.name != 0 && ( e.ul[4] == 1 || e.ul[4] == 2 ) )
251 if ( Options.verbose_flag )
254 printf("%s %s\n", tmp_ul.EncodeString(buf, 64), e.name);
258 printf("%s\n", e.name);
262 di = (MDD_t)(di + 1);
268 Result_t result = RESULT_OK;
269 FileList_t::iterator fi;
271 for ( fi = Options.inFileList.begin(); KM_SUCCESS(result) && fi != Options.inFileList.end(); ++fi )
273 if ( Options.verbose_flag )
274 fprintf(stderr, "Opening file %s\n", (fi->c_str()));
276 std::string this_prefix = Options.prefix.empty() ? Kumu::PathSetExtension(*fi, "") + "_" : Options.prefix;
277 Kumu::FileReader reader;
278 KLVFilePacket packet;
279 char filename_buf[1024];
280 ui64_t item_counter = 0;
282 result = reader.OpenRead(fi->c_str());
284 if ( KM_SUCCESS(result) )
285 result = packet.InitFromFile(reader);
287 while ( KM_SUCCESS(result) && item_counter < Options.extract_limit )
289 if ( packet.GetUL() == Options.target_ul
290 || packet.GetUL().MatchIgnoreStream(Options.target_ul) )
292 snprintf(filename_buf, 1024, "%s%010qu%s", this_prefix.c_str(), item_counter, Options.suffix.c_str());
294 if ( Options.verbose_flag )
295 fprintf(stderr, "%s (%llu bytes)\n", filename_buf, packet.ValueLength());
297 Kumu::FileWriter writer;
298 writer.OpenWrite(filename_buf);
300 if ( KM_SUCCESS(result) )
302 if ( Options.unwrap_mode )
304 result = writer.Write(packet.m_Buffer.RoData() + packet.KLLength(), packet.ValueLength());
308 result = writer.Write(packet.m_Buffer.RoData(), packet.m_Buffer.Size());
315 if ( KM_SUCCESS(result) )
316 result = packet.InitFromFile(reader);
319 if ( result == RESULT_ENDOFFILE )
323 if ( KM_FAILURE(result) )
325 fputs("Program stopped on error.\n", stderr);
327 if ( result != RESULT_FAIL )
329 fputs(result, stderr);