author | Michael Krelin <hacker@klever.net> | 2011-03-19 20:14:26 (UTC) |
---|---|---|
committer | Michael Krelin <hacker@klever.net> | 2011-03-19 20:14:26 (UTC) |
commit | b6859c0f505b79a246955ab06763392871459e22 (patch) (unidiff) | |
tree | fd85af38d44c7ff5af1eb687d6446d8c49a19bc8 | |
parent | 5ca0d6a85c438ea75dc2795aca5176e3b31e89f0 (diff) | |
download | iii-b6859c0f505b79a246955ab06763392871459e22.zip iii-b6859c0f505b79a246955ab06763392871459e22.tar.gz iii-b6859c0f505b79a246955ab06763392871459e22.tar.bz2 |
iii-extract-riff-chunk manpage and more date bumps
Signed-off-by: Michael Krelin <hacker@klever.net>
-rw-r--r-- | doc/Makefile.am | 2 | ||||
-rw-r--r-- | doc/iii-extract-riff-chunk.1 | 79 | ||||
-rw-r--r-- | doc/iiid.8.in | 2 | ||||
-rw-r--r-- | src/iii-extract-riff-chunk.cc | 2 |
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 @@ | |||
1 | man_MANS=iiid.8 | 1 | man_MANS=iiid.8 iii-extract-riff-chunk.1 |
2 | doc_DATA = 000000000000.conf | 2 | doc_DATA = 000000000000.conf |
3 | pkglib_SCRIPTS = on-upload-photo.bash tag-photo.bash | 3 | pkglib_SCRIPTS = on-upload-photo.bash tag-photo.bash |
4 | 4 | ||
5 | clean-local: | 5 | clean-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 | |||
6 | iii-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 | |||
19 | The 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 | ||
21 | by date. | ||
22 | |||
23 | .SH OPTIONS | ||
24 | |||
25 | .TP | ||
26 | \fB-1\fR, \fB--first\fR | ||
27 | Stop after extracting the first matching chunk. | ||
28 | .TP | ||
29 | \fB-h\fR, \fB--help\fR, \fB--usage\fR | ||
30 | Display short usage instructions and exit. | ||
31 | .TP | ||
32 | \fB-V\fR, \fB--version\fR | ||
33 | Report version and exit. | ||
34 | .TP | ||
35 | \fB-L\fR, \fB--license\fR | ||
36 | Show licensing terms. | ||
37 | |||
38 | .SH EXAMPLE | ||
39 | |||
40 | The 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 | |||
45 | produces output | ||
46 | |||
47 | YYYY:MM:DD HH:MM:SS | ||
48 | |||
49 | at least for my Nikon D90 recorded AVI files. | ||
50 | |||
51 | .SH AUTHOR | ||
52 | |||
53 | Written by Michael Krelin <hacker@klever.net> | ||
54 | |||
55 | .SH COPYRIGHT | ||
56 | |||
57 | Copyright (c) 2009-2011 Klever Group (http://www.klever.net/) | ||
58 | |||
59 | Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
60 | this software and associated documentation files (the "Software"), to deal in | ||
61 | the Software without restriction, including without limitation the rights to | ||
62 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | ||
63 | of the Software, and to permit persons to whom the Software is furnished to do | ||
64 | so, subject to the following conditions: | ||
65 | |||
66 | The above copyright notice and this permission notice shall be included in all | ||
67 | copies or substantial portions of the Software. | ||
68 | |||
69 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
70 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
71 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
72 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
73 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
74 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
75 | SOFTWARE. | ||
76 | |||
77 | .SH BUGS | ||
78 | |||
79 | You 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 | ||
6 | iiid \- An eye-fi card management daemon | 6 | iiid \- 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 | ||
18 | iiid daemon is a minimalistic open source eye-fi management daemon | 18 | iiid daemon is a minimalistic open source eye-fi management daemon |
19 | implementation. It is listening for incoming connections and accepts files from | 19 | implementation. It is listening for incoming connections and accepts files from |
20 | eye-fi card, optionally invoking scripts to sort out files or send out | 20 | eye-fi card, optionally invoking scripts to sort out files or send out |
21 | notifications. | 21 | notifications. |
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 |
27 | Set the port to listen to. You're not likely to ever need to change this, | 27 | Set the port to listen to. You're not likely to ever need to change this, |
28 | perhaps for debugging purpose or if you want to proxy connections. | 28 | perhaps 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 |
31 | Display short usage instructions and exit. | 31 | Display short usage instructions and exit. |
32 | .TP | 32 | .TP |
33 | \fB-V\fR, \fB--version\fR | 33 | \fB-V\fR, \fB--version\fR |
34 | Report version and exit. | 34 | Report version and exit. |
35 | .TP | 35 | .TP |
36 | \fB-L\fR, \fB--license\fR | 36 | \fB-L\fR, \fB--license\fR |
37 | Show licensing terms. | 37 | Show licensing terms. |
38 | 38 | ||
39 | .SH EXIT STATUS | 39 | .SH EXIT STATUS |
40 | 40 | ||
41 | The daemon isn't supposed to exit at this point, but, like most executables, it returns zero in case of success, non-zero otherwise. | 41 | The 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 |
47 | Upon successfull connection, the daemon reads the configuration from this file, | 47 | Upon successfull connection, the daemon reads the configuration from this file, |
48 | where XXXXXXXXXXXX is the macaddress of your eyefi card. You can lookup the mac | 48 | where XXXXXXXXXXXX is the macaddress of your eyefi card. You can lookup the mac |
49 | address of your card in your Mac/Windows Settings.xml file. Be sure to remove | 49 | address of your card in your Mac/Windows Settings.xml file. Be sure to remove |
50 | dashes from it. | 50 | dashes 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" |
56 | Sets the target directory for uploaded files. If the \fI%s\fR placeholder is | 56 | Sets the target directory for uploaded files. If the \fI%s\fR placeholder is |
57 | present in the string, it is replaced with card mac address. | 57 | present in the string, it is replaced with card mac address. |
58 | .TP | 58 | .TP |
59 | \fBuploadkey\fR = "\fIxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\fR" | 59 | \fBuploadkey\fR = "\fIxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\fR" |
60 | The upload key as seen in Mac/Windows Settings.xml file. | 60 | The 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" |
63 | The command to execute on \fBStartSession\fR request. The command receives some | 63 | The command to execute on \fBStartSession\fR request. The command receives some |
64 | information via environment variables. | 64 | information 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" |
67 | The command to execute after successfull photo upload. The information about | 67 | The command to execute after successfull photo upload. The information about |
68 | the card mac address and uploaded file name is passed via environment | 68 | the card mac address and uploaded file name is passed via environment |
69 | variables. | 69 | variables. |
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" |
72 | The command to execute on \fBMarkLastPhotoInRoll\fR request. The information | 72 | The command to execute on \fBMarkLastPhotoInRoll\fR request. The information |
73 | about request is passed via environment variables. | 73 | about request is passed via environment variables. |
74 | .TP | 74 | .TP |
75 | \fBumask\fR = \fI002\fR | 75 | \fBumask\fR = \fI002\fR |
76 | The file mode creation mask. | 76 | The file mode creation mask. |
77 | 77 | ||
78 | .SH AUTHOR | 78 | .SH AUTHOR |
79 | 79 | ||
80 | Written by Michael Krelin <hacker@klever.net> | 80 | Written by Michael Krelin <hacker@klever.net> |
81 | 81 | ||
82 | .SH COPYRIGHT | 82 | .SH COPYRIGHT |
83 | 83 | ||
84 | Copyright (c) 2009-2011 Klever Group (http://www.klever.net/) | 84 | Copyright (c) 2009-2011 Klever Group (http://www.klever.net/) |
85 | 85 | ||
86 | Permission is hereby granted, free of charge, to any person obtaining a copy of | 86 | Permission is hereby granted, free of charge, to any person obtaining a copy of |
87 | this software and associated documentation files (the "Software"), to deal in | 87 | this software and associated documentation files (the "Software"), to deal in |
88 | the Software without restriction, including without limitation the rights to | 88 | the Software without restriction, including without limitation the rights to |
89 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | 89 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
90 | of the Software, and to permit persons to whom the Software is furnished to do | 90 | of the Software, and to permit persons to whom the Software is furnished to do |
91 | so, subject to the following conditions: | 91 | so, subject to the following conditions: |
92 | 92 | ||
93 | The above copyright notice and this permission notice shall be included in all | 93 | The above copyright notice and this permission notice shall be included in all |
94 | copies or substantial portions of the Software. | 94 | copies or substantial portions of the Software. |
95 | 95 | ||
96 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 96 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
97 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 97 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
98 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | 98 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
99 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 99 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
100 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 100 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
101 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | 101 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
102 | SOFTWARE. | 102 | SOFTWARE. |
103 | 103 | ||
104 | .SH BUGS | 104 | .SH BUGS |
105 | 105 | ||
106 | You tell me. Send reports to <iii-bugs@klever.net> | 106 | You 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,210 +1,210 @@ | |||
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 | ||
20 | typedef uint32_t fourcc_type; | 20 | typedef uint32_t fourcc_type; |
21 | enum fourcc_value { | 21 | enum 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 | ||
27 | fourcc_type str2fourcc(const char *str) { | 27 | fourcc_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 | } |
31 | const std::string fourcc2str(fourcc_type fcc) { | 31 | const 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) |
39 | struct riff_sized_head { | 39 | struct 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 | ||
45 | class exceptional_success : public std::exception { }; | 45 | class exceptional_success : public std::exception { }; |
46 | 46 | ||
47 | struct riff { | 47 | struct 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 | ||
98 | struct scoped_chunk { | 98 | struct 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 | ||
117 | struct chunk_path_type : public std::list<std::string> { | 117 | struct 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 | ||
128 | struct chunk_walker { | 128 | struct 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 | ||
179 | void usage(char **argv) { | 179 | void 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 | ||
195 | int main(int argc,char **argv) try { | 195 | int 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) { |