summaryrefslogtreecommitdiffabout
path: root/src
Unidiff
Diffstat (limited to 'src') (more/less context) (ignore whitespace changes)
-rw-r--r--src/iii-extract-riff-chunk.cc2
1 files changed, 1 insertions, 1 deletions
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}