summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--doc/Makefile.am2
-rw-r--r--doc/iii-extract-riff-chunk.179
-rw-r--r--doc/iiid.8.in2
-rw-r--r--src/iii-extract-riff-chunk.cc2
4 files changed, 82 insertions, 3 deletions
diff --git a/doc/Makefile.am b/doc/Makefile.am
index e171b0b..63079ee 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -1,6 +1,6 @@
1man_MANS=iiid.8 1man_MANS=iiid.8 iii-extract-riff-chunk.1
2doc_DATA = 000000000000.conf 2doc_DATA = 000000000000.conf
3pkglib_SCRIPTS = on-upload-photo.bash tag-photo.bash 3pkglib_SCRIPTS = on-upload-photo.bash tag-photo.bash
4 4
5clean-local: 5clean-local:
6 rm -f iiid.8 6 rm -f iiid.8
diff --git a/doc/iii-extract-riff-chunk.1 b/doc/iii-extract-riff-chunk.1
new file mode 100644
index 0000000..5a9afeb
--- a/dev/null
+++ b/doc/iii-extract-riff-chunk.1
@@ -0,0 +1,79 @@
1.TH iii-extract-riff-chunk 1 "March 19th, 2011" "iii" "Klever Group (http://www.klever.net/)"
2.hla en
3
4.SH NAME
5
6iii-extract-riff-chunk \- utility to extract chunks from RIFF files
7
8.SH SYNOPSYS
9
10\fBiii-extract-riff-chunk\fR
11[\fB-h\fR] [\fB--help\fR] [\fB--usage\fR]
12[\fB-V\fR] [\fB--version\fR]
13[\fB-L\fR] [\fB--license\fR]
14[\fB-1\fR] [\fB--first\fR]
15<avi-file> <chunk-path>
16
17.SH DESCRIPTION
18
19The utility is designed to assist in extracting chunk from RIFF files. The main
20(and only) reason why it was developed is to sort video files created by camera
21by date.
22
23.SH OPTIONS
24
25.TP
26\fB-1\fR, \fB--first\fR
27Stop after extracting the first matching chunk.
28.TP
29\fB-h\fR, \fB--help\fR, \fB--usage\fR
30Display short usage instructions and exit.
31.TP
32\fB-V\fR, \fB--version\fR
33Report version and exit.
34.TP
35\fB-L\fR, \fB--license\fR
36Show licensing terms.
37
38.SH EXAMPLE
39
40The command line invokation
41
42\fBiii-extract-riff-chunk DSC_0001.AVI '/RIFF.AVI /LIST.ncdt/nctg'\fR
43| dd bs=1 skip=82 count=19 2>/dev/null
44
45produces output
46
47YYYY:MM:DD HH:MM:SS
48
49at least for my Nikon D90 recorded AVI files.
50
51.SH AUTHOR
52
53Written by Michael Krelin <hacker@klever.net>
54
55.SH COPYRIGHT
56
57Copyright (c) 2009-2011 Klever Group (http://www.klever.net/)
58
59Permission is hereby granted, free of charge, to any person obtaining a copy of
60this software and associated documentation files (the "Software"), to deal in
61the Software without restriction, including without limitation the rights to
62use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
63of the Software, and to permit persons to whom the Software is furnished to do
64so, subject to the following conditions:
65
66The above copyright notice and this permission notice shall be included in all
67copies or substantial portions of the Software.
68
69THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
70IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
71FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
72AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
73LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
74OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
75SOFTWARE.
76
77.SH BUGS
78
79You tell me. Send reports to <iii-bugs@klever.net>
diff --git a/doc/iiid.8.in b/doc/iiid.8.in
index 533ed18..30476f7 100644
--- a/doc/iiid.8.in
+++ b/doc/iiid.8.in
@@ -1,106 +1,106 @@
1.TH iiid 8 "March 8th, 2009" "iiid(8)" "Klever Group (http://www.klever.net/)" 1.TH iiid 8 "March 8th, 2009" "iii" "Klever Group (http://www.klever.net/)"
2.hla en 2.hla en
3 3
4.SH NAME 4.SH NAME
5 5
6iiid \- An eye-fi card management daemon 6iiid \- An eye-fi card management daemon
7 7
8.SH SYNOPSYS 8.SH SYNOPSYS
9 9
10\fBiiid\fR 10\fBiiid\fR
11[\fB-h\fR] [\fB--help\fR] [\fB--usage\fR] 11[\fB-h\fR] [\fB--help\fR] [\fB--usage\fR]
12[\fB-V\fR] [\fB--version\fR] 12[\fB-V\fR] [\fB--version\fR]
13[\fB-L\fR] [\fB--license\fR] 13[\fB-L\fR] [\fB--license\fR]
14[\fB-p\fR \fIport\fR] [\fB--port=\fR\fIport\fR] 14[\fB-p\fR \fIport\fR] [\fB--port=\fR\fIport\fR]
15 15
16.SH DESCRIPTION 16.SH DESCRIPTION
17 17
18iiid daemon is a minimalistic open source eye-fi management daemon 18iiid daemon is a minimalistic open source eye-fi management daemon
19implementation. It is listening for incoming connections and accepts files from 19implementation. It is listening for incoming connections and accepts files from
20eye-fi card, optionally invoking scripts to sort out files or send out 20eye-fi card, optionally invoking scripts to sort out files or send out
21notifications. 21notifications.
22 22
23.SH OPTIONS 23.SH OPTIONS
24 24
25.TP 25.TP
26\fB-p\fR \fIport\fR, \fB--port=\fR\fIport\fR 26\fB-p\fR \fIport\fR, \fB--port=\fR\fIport\fR
27Set the port to listen to. You're not likely to ever need to change this, 27Set the port to listen to. You're not likely to ever need to change this,
28perhaps for debugging purpose or if you want to proxy connections. 28perhaps for debugging purpose or if you want to proxy connections.
29.TP 29.TP
30\fB-h\fR, \fB--help\fR, \fB--usage\fR 30\fB-h\fR, \fB--help\fR, \fB--usage\fR
31Display short usage instructions and exit. 31Display short usage instructions and exit.
32.TP 32.TP
33\fB-V\fR, \fB--version\fR 33\fB-V\fR, \fB--version\fR
34Report version and exit. 34Report version and exit.
35.TP 35.TP
36\fB-L\fR, \fB--license\fR 36\fB-L\fR, \fB--license\fR
37Show licensing terms. 37Show licensing terms.
38 38
39.SH EXIT STATUS 39.SH EXIT STATUS
40 40
41The daemon isn't supposed to exit at this point, but, like most executables, it returns zero in case of success, non-zero otherwise. 41The daemon isn't supposed to exit at this point, but, like most executables, it returns zero in case of success, non-zero otherwise.
42 42
43.SH FILES 43.SH FILES
44 44
45.TP 45.TP
46@sysconfdir@/iii/\fBXXXXXXXXXXXX.conf/fR 46@sysconfdir@/iii/\fBXXXXXXXXXXXX.conf/fR
47Upon successfull connection, the daemon reads the configuration from this file, 47Upon successfull connection, the daemon reads the configuration from this file,
48where XXXXXXXXXXXX is the macaddress of your eyefi card. You can lookup the mac 48where XXXXXXXXXXXX is the macaddress of your eyefi card. You can lookup the mac
49address of your card in your Mac/Windows Settings.xml file. Be sure to remove 49address of your card in your Mac/Windows Settings.xml file. Be sure to remove
50dashes from it. 50dashes from it.
51 51
52.SH CONFIGURATION OPTIONS 52.SH CONFIGURATION OPTIONS
53 53
54.TP 54.TP
55\fBtargetdir\fR = "\fI/var/lib/iii/%s/\fR" 55\fBtargetdir\fR = "\fI/var/lib/iii/%s/\fR"
56Sets the target directory for uploaded files. If the \fI%s\fR placeholder is 56Sets the target directory for uploaded files. If the \fI%s\fR placeholder is
57present in the string, it is replaced with card mac address. 57present in the string, it is replaced with card mac address.
58.TP 58.TP
59\fBuploadkey\fR = "\fIxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\fR" 59\fBuploadkey\fR = "\fIxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\fR"
60The upload key as seen in Mac/Windows Settings.xml file. 60The upload key as seen in Mac/Windows Settings.xml file.
61.TP 61.TP
62\fBon-start-session\fR = "\fIlogger iii-StartSession ${EYEFI_MACADDRESS} ${EYEFI_TRANSFER_MODE} ${EYEFI_TRANSFERMODETIMESTAMP}\fR" 62\fBon-start-session\fR = "\fIlogger iii-StartSession ${EYEFI_MACADDRESS} ${EYEFI_TRANSFER_MODE} ${EYEFI_TRANSFERMODETIMESTAMP}\fR"
63The command to execute on \fBStartSession\fR request. The command receives some 63The command to execute on \fBStartSession\fR request. The command receives some
64information via environment variables. 64information via environment variables.
65.TP 65.TP
66\fBon-upload-photo\fR = "\fIlogger iii-UploadPhoto ${EYEFI_MACADDRESS} ${EYEFI_UPLOADED}\fR" 66\fBon-upload-photo\fR = "\fIlogger iii-UploadPhoto ${EYEFI_MACADDRESS} ${EYEFI_UPLOADED}\fR"
67The command to execute after successfull photo upload. The information about 67The command to execute after successfull photo upload. The information about
68the card mac address and uploaded file name is passed via environment 68the card mac address and uploaded file name is passed via environment
69variables. 69variables.
70.TP 70.TP
71\fBon-mark-last-photo-in-roll\fR = "\fIlogger iii-MarkLastPhotoInRoll ${EYEFI_MACADDRESS} ${EYEFI_MERGEDELTA}\fR" 71\fBon-mark-last-photo-in-roll\fR = "\fIlogger iii-MarkLastPhotoInRoll ${EYEFI_MACADDRESS} ${EYEFI_MERGEDELTA}\fR"
72The command to execute on \fBMarkLastPhotoInRoll\fR request. The information 72The command to execute on \fBMarkLastPhotoInRoll\fR request. The information
73about request is passed via environment variables. 73about request is passed via environment variables.
74.TP 74.TP
75\fBumask\fR = \fI002\fR 75\fBumask\fR = \fI002\fR
76The file mode creation mask. 76The file mode creation mask.
77 77
78.SH AUTHOR 78.SH AUTHOR
79 79
80Written by Michael Krelin <hacker@klever.net> 80Written by Michael Krelin <hacker@klever.net>
81 81
82.SH COPYRIGHT 82.SH COPYRIGHT
83 83
84Copyright (c) 2009-2011 Klever Group (http://www.klever.net/) 84Copyright (c) 2009-2011 Klever Group (http://www.klever.net/)
85 85
86Permission is hereby granted, free of charge, to any person obtaining a copy of 86Permission is hereby granted, free of charge, to any person obtaining a copy of
87this software and associated documentation files (the "Software"), to deal in 87this software and associated documentation files (the "Software"), to deal in
88the Software without restriction, including without limitation the rights to 88the Software without restriction, including without limitation the rights to
89use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 89use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
90of the Software, and to permit persons to whom the Software is furnished to do 90of the Software, and to permit persons to whom the Software is furnished to do
91so, subject to the following conditions: 91so, subject to the following conditions:
92 92
93The above copyright notice and this permission notice shall be included in all 93The above copyright notice and this permission notice shall be included in all
94copies or substantial portions of the Software. 94copies or substantial portions of the Software.
95 95
96THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 96THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
97IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 97IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
98FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 98FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
99AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 99AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
100LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 100LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
101OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 101OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
102SOFTWARE. 102SOFTWARE.
103 103
104.SH BUGS 104.SH BUGS
105 105
106You tell me. Send reports to <iii-bugs@klever.net> 106You tell me. Send reports to <iii-bugs@klever.net>
diff --git a/src/iii-extract-riff-chunk.cc b/src/iii-extract-riff-chunk.cc
index 3a06db2..d53170d 100644
--- a/src/iii-extract-riff-chunk.cc
+++ b/src/iii-extract-riff-chunk.cc
@@ -1,246 +1,246 @@
1/* vim:set sw=8 nosi noai cin cino=:0,l1,g0: */ 1/* vim:set sw=8 nosi noai cin cino=:0,l1,g0: */
2#include <stdint.h> 2#include <stdint.h>
3#include <stdlib.h> 3#include <stdlib.h>
4#include <getopt.h> 4#include <getopt.h>
5#include <cstring> 5#include <cstring>
6#include <iostream> 6#include <iostream>
7#include <fstream> 7#include <fstream>
8#include <stdexcept> 8#include <stdexcept>
9#include <cassert> 9#include <cassert>
10#include <list> 10#include <list>
11#include <string> 11#include <string>
12#include <iterator> 12#include <iterator>
13 13
14#include "config.h" 14#include "config.h"
15 15
16#define PHEADER \ 16#define PHEADER \
17 PACKAGE " Version " VERSION "\n" \ 17 PACKAGE " Version " VERSION "\n" \
18 "Copyright (c) 2009-2010 Klever Group" 18 "Copyright (c) 2009-2011 Klever Group"
19 19
20typedef uint32_t fourcc_type; 20typedef uint32_t fourcc_type;
21enum fourcc_value { 21enum fourcc_value {
22 fourcc_RIFF = 0x46464952, fourcc_AVI = 0x20495641, fourcc_LIST = 0x5453494c, 22 fourcc_RIFF = 0x46464952, fourcc_AVI = 0x20495641, fourcc_LIST = 0x5453494c,
23 fourcc_hdrl = 0x6c726468, fourcc_strl = 0x6c727473, 23 fourcc_hdrl = 0x6c726468, fourcc_strl = 0x6c727473,
24 fourcc_ncdt = 0x7464636e, fourcc_ncvr = 0x7276636e, fourcc_nctg = 0x6774636e, fourcc_ncth = 0x6874636e 24 fourcc_ncdt = 0x7464636e, fourcc_ncvr = 0x7276636e, fourcc_nctg = 0x6774636e, fourcc_ncth = 0x6874636e
25}; 25};
26 26
27fourcc_type str2fourcc(const char *str) { 27fourcc_type str2fourcc(const char *str) {
28 fourcc_type rv = 0; 28 fourcc_type rv = 0;
29 return *(fourcc_type*)strncpy((char*)&rv,str,sizeof(rv)); 29 return *(fourcc_type*)strncpy((char*)&rv,str,sizeof(rv));
30} 30}
31const std::string fourcc2str(fourcc_type fcc) { 31const std::string fourcc2str(fourcc_type fcc) {
32 char rv[sizeof(fcc)+1]; 32 char rv[sizeof(fcc)+1];
33 *(fourcc_type*)rv = fcc; 33 *(fourcc_type*)rv = fcc;
34 rv[sizeof(fcc)]=0; 34 rv[sizeof(fcc)]=0;
35 return rv; 35 return rv;
36} 36}
37 37
38#pragma pack(1) 38#pragma pack(1)
39struct riff_sized_head { 39struct riff_sized_head {
40 fourcc_type fourcc; 40 fourcc_type fourcc;
41 uint32_t size; 41 uint32_t size;
42}; 42};
43#pragma pack() 43#pragma pack()
44 44
45class exceptional_success : public std::exception { }; 45class exceptional_success : public std::exception { };
46 46
47struct riff { 47struct riff {
48 struct chunk_type { 48 struct chunk_type {
49 riff_sized_head head; 49 riff_sized_head head;
50 uint32_t left; 50 uint32_t left;
51 51
52 chunk_type(riff& r) { 52 chunk_type(riff& r) {
53 r.read(&head); 53 r.read(&head);
54 left = head.size; 54 left = head.size;
55 } 55 }
56 }; 56 };
57 57
58 std::istream *in; 58 std::istream *in;
59 typedef std::list<chunk_type> chunks_type; 59 typedef std::list<chunk_type> chunks_type;
60 chunks_type chunks; 60 chunks_type chunks;
61 61
62 riff(std::istream& i) : in(&i) { } 62 riff(std::istream& i) : in(&i) { }
63 63
64 protected: 64 protected:
65 65
66 int begin_chunk() { 66 int begin_chunk() {
67 chunks.push_back( chunk_type(*this) ); 67 chunks.push_back( chunk_type(*this) );
68 return chunks.size(); 68 return chunks.size();
69 } 69 }
70 void end_chunk(int level) { 70 void end_chunk(int level) {
71 assert(in); assert(chunks.size()==level); 71 assert(in); assert(chunks.size()==level);
72 std::streamsize o = chunks.back().left; 72 std::streamsize o = chunks.back().left;
73 chunks.pop_back(); 73 chunks.pop_back();
74 if(!o) return; 74 if(!o) return;
75 in->seekg(o,std::ios::cur); 75 in->seekg(o,std::ios::cur);
76 for(chunks_type::iterator i=chunks.begin(),ie=chunks.end() ;i!=ie; (i++)->left -= o) ; 76 for(chunks_type::iterator i=chunks.begin(),ie=chunks.end() ;i!=ie; (i++)->left -= o) ;
77 } 77 }
78 78
79 void read(void *p,size_t n) { 79 void read(void *p,size_t n) {
80 assert(in); 80 assert(in);
81 if( (!chunks.empty()) && chunks.back().left < n) 81 if( (!chunks.empty()) && chunks.back().left < n)
82 throw std::runtime_error("attempt to read beyond the end of chunk"); 82 throw std::runtime_error("attempt to read beyond the end of chunk");
83 if(!in->read((char*)p,n)) 83 if(!in->read((char*)p,n))
84 throw std::runtime_error("failed to read()"); 84 throw std::runtime_error("failed to read()");
85 std::streamsize gc = in->gcount(); 85 std::streamsize gc = in->gcount();
86 for(chunks_type::iterator i=chunks.begin(),ie=chunks.end();i!=ie;++i) { 86 for(chunks_type::iterator i=chunks.begin(),ie=chunks.end();i!=ie;++i) {
87 i->left -= gc; assert(i->left >= 0); 87 i->left -= gc; assert(i->left >= 0);
88 } 88 }
89 if(gc!=n) throw std::runtime_error("incomplete read()"); 89 if(gc!=n) throw std::runtime_error("incomplete read()");
90 } 90 }
91 91
92 template<typename T> void read(T* v) { read(v,sizeof(*v)); } 92 template<typename T> void read(T* v) { read(v,sizeof(*v)); }
93 93
94 friend class scoped_chunk; 94 friend class scoped_chunk;
95 95
96}; 96};
97 97
98struct scoped_chunk { 98struct scoped_chunk {
99 riff& rs; 99 riff& rs;
100 int level; 100 int level;
101 riff::chunks_type::reverse_iterator chunk_iterator; 101 riff::chunks_type::reverse_iterator chunk_iterator;
102 102
103 scoped_chunk(riff& rs_) : rs(rs_), level(rs.begin_chunk()), chunk_iterator(rs.chunks.rbegin()) { } 103 scoped_chunk(riff& rs_) : rs(rs_), level(rs.begin_chunk()), chunk_iterator(rs.chunks.rbegin()) { }
104 ~scoped_chunk() { rs.end_chunk(level); } 104 ~scoped_chunk() { rs.end_chunk(level); }
105 105
106 riff::chunk_type& chunk() { return *chunk_iterator; } 106 riff::chunk_type& chunk() { return *chunk_iterator; }
107 107
108 fourcc_type get_chunk_id() { return chunk().head.fourcc; } 108 fourcc_type get_chunk_id() { return chunk().head.fourcc; }
109 bool has(uint32_t bytes=1) { return chunk().left >= bytes; } 109 bool has(uint32_t bytes=1) { return chunk().left >= bytes; }
110 110
111 template<typename T> T read() { T rv; rs.read(&rv); return rv; } 111 template<typename T> T read() { T rv; rs.read(&rv); return rv; }
112 template<typename T> void read(T& t) { rs.read(&t); } 112 template<typename T> void read(T& t) { rs.read(&t); }
113 void read(void *p,size_t n) { rs.read(p,n); } 113 void read(void *p,size_t n) { rs.read(p,n); }
114 114
115}; 115};
116 116
117struct chunk_path_type : public std::list<std::string> { 117struct chunk_path_type : public std::list<std::string> {
118 118
119 chunk_path_type() { } 119 chunk_path_type() { }
120 chunk_path_type(const char *str) { 120 chunk_path_type(const char *str) {
121 for(const char *p0=str,*p1=strchr(p0,'/');p0;p1=p1?strchr(p0=++p1,'/'):(p0=0)) 121 for(const char *p0=str,*p1=strchr(p0,'/');p0;p1=p1?strchr(p0=++p1,'/'):(p0=0))
122 if(p0!=p1) 122 if(p0!=p1)
123 push_back( p1? std::string(p0,p1-p0) : std::string(p0) ); 123 push_back( p1? std::string(p0,p1-p0) : std::string(p0) );
124 } 124 }
125 125
126}; 126};
127 127
128struct chunk_walker { 128struct chunk_walker {
129 riff& r; 129 riff& r;
130 chunk_path_type path; 130 chunk_path_type path;
131 131
132 chunk_walker(riff& r_) : r(r_) { } 132 chunk_walker(riff& r_) : r(r_) { }
133 133
134 void shoot(scoped_chunk& chunk) { 134 void shoot(scoped_chunk& chunk) {
135 riff::chunk_type& c = chunk.chunk(); 135 riff::chunk_type& c = chunk.chunk();
136 while(c.left) { 136 while(c.left) {
137 static char tmp[512]; 137 static char tmp[512];
138 int r = (c.left<sizeof(tmp)) ? c.left : sizeof(tmp) ; 138 int r = (c.left<sizeof(tmp)) ? c.left : sizeof(tmp) ;
139 chunk.read(tmp,r); std::cout.write(tmp,r); 139 chunk.read(tmp,r); std::cout.write(tmp,r);
140 } 140 }
141 if(first) throw exceptional_success(); 141 if(first) throw exceptional_success();
142 } 142 }
143 143
144 void walk_chunks() { 144 void walk_chunks() {
145 scoped_chunk chunk(r); 145 scoped_chunk chunk(r);
146 std::string pc = fourcc2str(chunk.get_chunk_id()); 146 std::string pc = fourcc2str(chunk.get_chunk_id());
147 bool list = false; 147 bool list = false;
148 switch(chunk.get_chunk_id()) { 148 switch(chunk.get_chunk_id()) {
149 case fourcc_RIFF: case fourcc_LIST: 149 case fourcc_RIFF: case fourcc_LIST:
150 list = true; 150 list = true;
151 pc += '.'; pc += fourcc2str(chunk.read<fourcc_type>()); 151 pc += '.'; pc += fourcc2str(chunk.read<fourcc_type>());
152 break; 152 break;
153 } 153 }
154 path.push_back(pc); 154 path.push_back(pc);
155 std::pair<chunk_path_type::const_iterator,chunk_path_type::const_iterator> 155 std::pair<chunk_path_type::const_iterator,chunk_path_type::const_iterator>
156 mm = std::mismatch(path.begin(),path.end(),target.begin()); 156 mm = std::mismatch(path.begin(),path.end(),target.begin());
157 bool dive = list; 157 bool dive = list;
158 if(mm.first==path.end()) { 158 if(mm.first==path.end()) {
159 if(mm.second==target.end()) { 159 if(mm.second==target.end()) {
160 shoot(chunk); 160 shoot(chunk);
161 dive = false; 161 dive = false;
162 } 162 }
163 }else{ 163 }else{
164 assert(mm.second!=target.end()); 164 assert(mm.second!=target.end());
165 dive = false; 165 dive = false;
166 } 166 }
167 167
168 if(dive) while(chunk.has()) walk_chunks(); 168 if(dive) while(chunk.has()) walk_chunks();
169 path.pop_back(); 169 path.pop_back();
170 } 170 }
171 171
172 172
173 chunk_path_type target; 173 chunk_path_type target;
174 chunk_walker& set_target(chunk_path_type t) { target = t; return *this; } 174 chunk_walker& set_target(chunk_path_type t) { target = t; return *this; }
175 bool first; 175 bool first;
176 chunk_walker& set_oneshot(bool os) { first = true; return *this; } 176 chunk_walker& set_oneshot(bool os) { first = true; return *this; }
177}; 177};
178 178
179void usage(char **argv) { 179void usage(char **argv) {
180 std::cerr << PHEADER << std::endl << std::endl 180 std::cerr << PHEADER << std::endl << std::endl
181 << ' ' << argv[0] << " [options] <avi-file> <chunk-path>" << std::endl 181 << ' ' << argv[0] << " [options] <avi-file> <chunk-path>" << std::endl
182 << std::endl << 182 << std::endl <<
183 " -h, --help,\n" 183 " -h, --help,\n"
184 " --usage display this text\n" 184 " --usage display this text\n"
185 " -V, --version display version information\n" 185 " -V, --version display version information\n"
186 " -L, --license show license\n" 186 " -L, --license show license\n"
187 "\n" 187 "\n"
188 "Example: " << argv[0] << " DSC_0001.AVI '/RIFF.AVI /LIST.ncdt/nctg' \\\n" 188 "Example: " << argv[0] << " DSC_0001.AVI '/RIFF.AVI /LIST.ncdt/nctg' \\\n"
189 "\t\t| dd bs=1 skip=82 count=19 2>/dev/null\n" 189 "\t\t| dd bs=1 skip=82 count=19 2>/dev/null\n"
190 "Output: YYYY:MM:DD HH:MM:SS (for Nikon-recorded AVI)" 190 "Output: YYYY:MM:DD HH:MM:SS (for Nikon-recorded AVI)"
191 << std::endl << std::endl; 191 << std::endl << std::endl;
192 exit(0); 192 exit(0);
193} 193}
194 194
195int main(int argc,char **argv) try { 195int main(int argc,char **argv) try {
196 196
197 bool first = false; 197 bool first = false;
198 198
199 for(;;) { 199 for(;;) {
200 static struct option opts[] = { 200 static struct option opts[] = {
201 { "first", no_argument, 0, '1' }, 201 { "first", no_argument, 0, '1' },
202 { "help", no_argument, 0, 'h' }, 202 { "help", no_argument, 0, 'h' },
203 { "usage", no_argument, 0, 'h' }, 203 { "usage", no_argument, 0, 'h' },
204 { "version", no_argument, 0, 'V' }, 204 { "version", no_argument, 0, 'V' },
205 { "license", no_argument, 0, 'L' }, 205 { "license", no_argument, 0, 'L' },
206 { NULL, 0, 0, 0 } 206 { NULL, 0, 0, 0 }
207 }; 207 };
208 int c = getopt_long(argc,argv,"1hVL",opts,NULL); 208 int c = getopt_long(argc,argv,"1hVL",opts,NULL);
209 if(c==-1) break; 209 if(c==-1) break;
210 switch(c) { 210 switch(c) {
211 case 'h': 211 case 'h':
212 usage(argv); break; 212 usage(argv); break;
213 case 'V': 213 case 'V':
214 std::cerr << VERSION << std::endl; 214 std::cerr << VERSION << std::endl;
215 exit(0); break; 215 exit(0); break;
216 case 'L': 216 case 'L':
217 extern const char *COPYING; 217 extern const char *COPYING;
218 std::cerr << COPYING << std::endl; 218 std::cerr << COPYING << std::endl;
219 exit(0); break; 219 exit(0); break;
220 case '1': 220 case '1':
221 first = true; break; 221 first = true; break;
222 default: 222 default:
223 std::cerr << "Huh?" << std::endl; 223 std::cerr << "Huh?" << std::endl;
224 exit(1); break; 224 exit(1); break;
225 } 225 }
226 } 226 }
227 227
228 if(optind!=(argc-2)) usage(argv); 228 if(optind!=(argc-2)) usage(argv);
229 229
230 std::ifstream i(argv[optind],std::ios::in); 230 std::ifstream i(argv[optind],std::ios::in);
231 if(!i) { 231 if(!i) {
232 std::cerr << "Failed to open file '" << argv[optind] << "'" << std::endl; 232 std::cerr << "Failed to open file '" << argv[optind] << "'" << std::endl;
233 exit(1); 233 exit(1);
234 } 234 }
235 riff rs(i); 235 riff rs(i);
236 chunk_walker(rs) 236 chunk_walker(rs)
237 .set_target(chunk_path_type(argv[++optind])) 237 .set_target(chunk_path_type(argv[++optind]))
238 .set_oneshot(first) 238 .set_oneshot(first)
239 .walk_chunks(); 239 .walk_chunks();
240 return 0; 240 return 0;
241}catch(exceptional_success&) { 241}catch(exceptional_success&) {
242 return 0; 242 return 0;
243}catch(std::exception &e) { 243}catch(std::exception &e) {
244 std::cerr << "oops: " << e.what() << std::endl; 244 std::cerr << "oops: " << e.what() << std::endl;
245 return 1; 245 return 1;
246} 246}