├── Anchor.h ├── COPYING.txt ├── File.cpp ├── File.h ├── List.cpp ├── List.h ├── Mediatype.cpp ├── Mediatype.h ├── OutputPin.cpp ├── OutputPin.h ├── RAR.cpp ├── RAR.h ├── RARFileSource.sln ├── RARFileSource.vcxproj ├── RARFileSource.vcxproj.filters ├── RAR_defines.h ├── README.txt ├── RFS.cpp ├── RFS.def ├── RFS.h ├── RFS.nsi ├── RFS.rc ├── Utils.cpp ├── Utils.h └── resource.h /Anchor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008-2012, OctaneSnail 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef ANCHOR_H 19 | #define ANCHOR_H 20 | 21 | #include 22 | 23 | template class Anchor 24 | { 25 | public: 26 | Anchor (T **value) : value (value) { } 27 | Anchor (void) : value (NULL) { } 28 | ~Anchor (void) { if (value) { delete *value; *value = NULL; } } 29 | 30 | void Set (T **value) { this->value = value; } 31 | void Release (void) { value = NULL; } 32 | 33 | private: 34 | T **value; 35 | }; 36 | 37 | template class ArrayAnchor 38 | { 39 | public: 40 | ArrayAnchor (T **value) : value (value) { } 41 | ArrayAnchor (void) : value (NULL) { } 42 | ~ArrayAnchor (void) { if (value) { delete [] *value; *value = NULL; } } 43 | 44 | void Set (T **value) { this->value = value; } 45 | void Release (void) { value = NULL; } 46 | 47 | private: 48 | T **value; 49 | }; 50 | 51 | template <> class Anchor 52 | { 53 | public: 54 | Anchor (HANDLE *value) : value (value) { } 55 | Anchor (void) : value (NULL) { } 56 | ~Anchor (void) { Close (); } 57 | 58 | void Set (HANDLE *val) { value = val; } 59 | void Release (void) { value = NULL; } 60 | void Close (void) 61 | { 62 | if (value && *value != INVALID_HANDLE_VALUE) 63 | { 64 | CloseHandle (*value); 65 | *value = INVALID_HANDLE_VALUE; 66 | } 67 | } 68 | 69 | private: 70 | HANDLE *value; 71 | }; 72 | 73 | #endif // ANCHOR_H 74 | -------------------------------------------------------------------------------- /COPYING.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /File.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008-2012, OctaneSnail 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | 21 | #include "File.h" 22 | #include "Utils.h" 23 | 24 | static int compare (const void *pos, const void *part) 25 | { 26 | if (*((LONGLONG *) pos) < ((FilePart *) part)->in_file_offset) 27 | return -1; 28 | 29 | if (*((LONGLONG *) pos) >= ((FilePart *) part)->in_file_offset + ((FilePart *) part)->size) 30 | return 1; 31 | 32 | return 0; 33 | } 34 | 35 | int File::FindStartPart (LONGLONG position) 36 | { 37 | if (position > size) 38 | return -1; 39 | 40 | // Check if the previous lookup up still matches. 41 | if (m_prev_part && !compare (&position, m_prev_part)) 42 | return (int) (m_prev_part - array); 43 | 44 | m_prev_part = (FilePart *) bsearch (&position, array, parts, sizeof (FilePart), compare); 45 | 46 | if (!m_prev_part) 47 | return -1; 48 | 49 | return (int) (m_prev_part - array); 50 | } 51 | 52 | HRESULT File::SyncRead (LONGLONG llPosition, DWORD lLength, BYTE* pBuffer, LONG *cbActual) 53 | { 54 | OVERLAPPED o; 55 | LARGE_INTEGER offset; 56 | DWORD to_read, read, acc = 0; 57 | LONGLONG offset2; 58 | int pos; 59 | #ifdef _DEBUG 60 | static int last_pos = -1; 61 | #endif 62 | 63 | if (!pBuffer) 64 | return E_POINTER; 65 | 66 | pos = FindStartPart (llPosition); 67 | if (pos == -1) 68 | { 69 | DbgLog((LOG_TRACE, 2, L"FindStartPart bailed length = %lu, pos = %lld", lLength, llPosition)); 70 | return S_FALSE; 71 | } 72 | 73 | #ifdef _DEBUG 74 | if (pos != last_pos) 75 | { 76 | DbgLog((LOG_TRACE, 2, L"Now reading volume %d.", pos)); 77 | last_pos = pos; 78 | } 79 | #endif 80 | FilePart *part = array + pos; 81 | 82 | offset2 = llPosition - part->in_file_offset; 83 | offset.QuadPart = part->in_rar_offset + offset2; 84 | 85 | memset (&o, 0, sizeof (o)); 86 | 87 | if (!(o.hEvent = CreateEvent (NULL, FALSE, FALSE, NULL))) 88 | { 89 | ErrorMsg (GetLastError (), L"CRFSOutputPin::SyncRead - CreateEvent"); 90 | return S_FALSE; 91 | } 92 | 93 | while (true) 94 | { 95 | read = 0; 96 | to_read = min (lLength, (DWORD) (part->size - offset2)); 97 | 98 | o.Offset = offset.LowPart; 99 | o.OffsetHigh = offset.HighPart; 100 | 101 | if (!ReadFile (part->file, pBuffer + acc, to_read, NULL, &o)) 102 | { 103 | DWORD err = GetLastError (); 104 | 105 | if (err != ERROR_IO_PENDING) 106 | { 107 | ErrorMsg (err, L"CRFSOutputPin::SyncRead - ReadFile"); 108 | break; 109 | } 110 | } 111 | if (!GetOverlappedResult (part->file, &o, &read, TRUE)) 112 | { 113 | ErrorMsg (GetLastError (), L"CRFSOutputPin::SyncRead - GetOverlappedResult"); 114 | break; 115 | } 116 | lLength -= read; 117 | acc += read; 118 | 119 | if (lLength == 0) 120 | { 121 | CloseHandle (o.hEvent); 122 | if (cbActual) 123 | *cbActual = acc; 124 | return S_OK; 125 | } 126 | 127 | pos ++; 128 | 129 | if (pos >= parts) 130 | break; 131 | 132 | part ++; 133 | offset2 = 0; 134 | offset.QuadPart = part->in_rar_offset; 135 | } 136 | 137 | CloseHandle (o.hEvent); 138 | if (cbActual) 139 | *cbActual = acc; 140 | return S_FALSE; 141 | } 142 | -------------------------------------------------------------------------------- /File.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008-2012, OctaneSnail 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef FILE_H 19 | #define FILE_H 20 | 21 | #include "List.h" 22 | 23 | class FilePart 24 | { 25 | public: 26 | FilePart (void) : next (NULL), file (INVALID_HANDLE_VALUE), 27 | in_rar_offset (0), in_file_offset (0), size (0) { } 28 | ~FilePart (void) { if (file != INVALID_HANDLE_VALUE) CloseHandle (file); } 29 | 30 | FilePart *next; 31 | 32 | HANDLE file; 33 | 34 | LONGLONG in_rar_offset; 35 | LONGLONG in_file_offset; 36 | LONGLONG size; 37 | }; 38 | 39 | class File : public Node 40 | { 41 | public: 42 | File (void) : size (0), parts (0), list (NULL), array (NULL), m_prev_part (NULL), filename (NULL), 43 | type_known (false), unsupported (false) { } 44 | 45 | ~File (void) 46 | { 47 | FilePart *fp = list; 48 | while (fp) 49 | { 50 | FilePart *tmp = fp; 51 | fp = fp->next; 52 | delete tmp; 53 | } 54 | delete [] array; 55 | delete [] filename; 56 | } 57 | 58 | int FindStartPart (LONGLONG position); 59 | HRESULT SyncRead (LONGLONG llPosition, DWORD lLength, BYTE* pBuffer, LONG *cbActual); 60 | 61 | CMediaType media_type; 62 | LONGLONG size; 63 | int parts; 64 | 65 | FilePart *list; 66 | FilePart *array; 67 | FilePart *m_prev_part; 68 | 69 | char *filename; 70 | bool type_known; 71 | bool unsupported; 72 | }; 73 | 74 | #endif // FILE_H 75 | -------------------------------------------------------------------------------- /List.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008-2012, OctaneSnail 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | template void List::InsertFirst (Node *n) 19 | { 20 | n->next = anchor.next; 21 | n->prev = &anchor; 22 | 23 | anchor.next->prev = n; 24 | anchor.next = n; 25 | } 26 | 27 | template void List::InsertLast (Node *n) 28 | { 29 | n->next = &anchor; 30 | n->prev = anchor.prev; 31 | 32 | anchor.prev->next = n; 33 | anchor.prev = n; 34 | } 35 | 36 | template T *List::UnlinkFirst (void) 37 | { 38 | Node *n = First (); 39 | if (!n) 40 | return NULL; 41 | n->Unlink (); 42 | return (T *) n; 43 | } 44 | 45 | template T *List::UnlinkLast (void) 46 | { 47 | Node *n = Last (); 48 | if (!n) 49 | return NULL; 50 | n->Unlink (); 51 | return (T *) n; 52 | } 53 | 54 | template T *List::Next (Node *n) 55 | { 56 | if (n->next == &anchor) 57 | return NULL; 58 | return (T *) n->next; 59 | } 60 | 61 | template T *List::Prev (Node *n) 62 | { 63 | if (n->prev == &anchor) 64 | return NULL; 65 | return (T *) n->prev; 66 | } 67 | 68 | template void List::Clear () 69 | { 70 | T *node; 71 | 72 | while (node = UnlinkFirst ()) 73 | delete node; 74 | } 75 | -------------------------------------------------------------------------------- /List.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008-2012, OctaneSnail 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef LIST_H 19 | #define LIST_H 20 | 21 | template class List; 22 | 23 | template class Node 24 | { 25 | friend class List; 26 | 27 | public: 28 | Node (void) : next (NULL), prev (NULL) { } 29 | 30 | void Unlink (void) 31 | { 32 | next->prev = prev; 33 | prev->next = next; 34 | } 35 | 36 | private: 37 | Node (Node *next, Node *prev) : next (next), prev (prev) { } 38 | 39 | Node *next; 40 | Node *prev; 41 | }; 42 | 43 | template class List 44 | { 45 | public: 46 | List (bool auto_clear = false) : anchor (&anchor, &anchor), clear (auto_clear) { } 47 | ~List () { if (clear) Clear (); } 48 | 49 | bool IsEmpty (void) { return anchor.next == &anchor; } 50 | 51 | T *First (void) { return Next (&anchor); } 52 | T *Last (void) { return Prev (&anchor); } 53 | 54 | void InsertFirst (Node *n); 55 | void InsertLast (Node *n); 56 | 57 | T *UnlinkFirst (void); 58 | T *UnlinkLast (void); 59 | 60 | T *Next (Node *n); 61 | T *Prev (Node *n); 62 | 63 | void Clear (void); 64 | 65 | private: 66 | Node anchor; 67 | bool clear; 68 | }; 69 | 70 | #include "List.cpp" 71 | 72 | #endif // LIST_H 73 | -------------------------------------------------------------------------------- /Mediatype.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008, OV2 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | most of the information used in this file comes from 20 | http://msdn.microsoft.com/en-us/library/ms787558(VS.85).aspx 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "Anchor.h" 29 | #include "Utils.h" 30 | #include "RFS.h" 31 | #include "Mediatype.h" 32 | #include "File.h" 33 | 34 | 35 | /* getNextToken extracts the current token from the string and 36 | and sets the starting point of the next token */ 37 | static void getNextToken (wchar_t **strTok, wchar_t **nextTokenStart) 38 | { 39 | while (**strTok == TEXT(' ')) 40 | (*strTok) ++; 41 | 42 | for (int i = 0; i < lstrlen (*strTok); i ++) 43 | { 44 | if ((*strTok) [i] == TEXT(',')) 45 | { 46 | (*strTok) [i] = TEXT('\0'); 47 | *nextTokenStart = *strTok + i + 1; 48 | return; 49 | } 50 | } 51 | *nextTokenStart = NULL; 52 | } 53 | 54 | /* parseCheckBytes splits valueData and places the parsed values in the 55 | checkBytes array (allocated here) */ 56 | static int parseCheckBytes (wchar_t *valueData, CheckByteDetails **checkBytes) 57 | { 58 | int tokenCount = 0, byteDetailsCount = 0, value; 59 | wchar_t *token, *nextTokenStart; 60 | 61 | for (int i = 0; i < lstrlen (valueData); i ++) 62 | if (valueData [i] == TEXT(',')) 63 | tokenCount ++; 64 | 65 | if ((++ tokenCount) % 4) 66 | return 0; 67 | 68 | byteDetailsCount = tokenCount / 4; 69 | *checkBytes = new CheckByteDetails [byteDetailsCount]; 70 | 71 | if (!*checkBytes) 72 | { 73 | ErrorMsg (0, L"Out of memory."); 74 | return -1; 75 | } 76 | 77 | nextTokenStart = valueData; 78 | 79 | for (int i = 0; i < byteDetailsCount; i ++) 80 | { 81 | token = nextTokenStart; 82 | getNextToken (&token, &nextTokenStart); 83 | swscanf_s (token, TEXT(" %lld"), &(*checkBytes) [i].offset); // offset in file 84 | token = nextTokenStart; 85 | getNextToken (&token, &nextTokenStart); 86 | swscanf_s (token, TEXT(" %u"), &(*checkBytes) [i].byteCount); // byte count of mask and value 87 | (*checkBytes) [i].mask = new BYTE [(*checkBytes) [i].byteCount]; 88 | (*checkBytes) [i].value = new BYTE [(*checkBytes) [i].byteCount]; 89 | 90 | if (!(*checkBytes) [i].mask || !(*checkBytes) [i].value) 91 | { 92 | ErrorMsg (0, L"Out of memory."); 93 | return -1; 94 | } 95 | 96 | //TODO: if the next token is smaller than byteCount and not empty we could pad with zeroes 97 | token = nextTokenStart; 98 | getNextToken (&token, &nextTokenStart); 99 | 100 | if (*token == TEXT('\0')) // no mask means all ones 101 | for (unsigned int j = 0; j < (*checkBytes) [i].byteCount; j ++) 102 | (*checkBytes) [i].mask [j] = 0xFF; 103 | else // otherwise parse mask 104 | { 105 | for (unsigned int j = 0; j < (*checkBytes) [i].byteCount && j * 2 < lstrlen (token); j ++) 106 | { 107 | swscanf_s (token + j * 2, TEXT(" %2x"), &value); 108 | (*checkBytes) [i].mask [j] = value; 109 | } 110 | } 111 | 112 | token = nextTokenStart; 113 | getNextToken (&token, &nextTokenStart); 114 | 115 | for (unsigned int j = 0; j < (*checkBytes) [i].byteCount && j * 2 < lstrlen (token); j ++) 116 | { 117 | swscanf_s (token + j * 2, TEXT(" %2x"), &value); // parse value 118 | (*checkBytes) [i].value [j] = value; 119 | } 120 | } 121 | return byteDetailsCount; 122 | } 123 | 124 | /* parses the HKEY_CLASSES_ROOT\Media Type registry key and 125 | fills the mediaTypeList with all valid byte marks and their 126 | corresponding major/subtypes */ 127 | int getMediaTypeList (List *mediaTypeList) 128 | { 129 | //these values come from http://msdn.microsoft.com/en-us/library/ms724872(VS.85).aspx 130 | #define MAX_VALUE_SIZE 16384 131 | #define MAX_KEYNAME_SIZE 256 132 | 133 | wchar_t keyName [MAX_KEYNAME_SIZE]; 134 | wchar_t subKeyName [MAX_KEYNAME_SIZE]; 135 | wchar_t valueName [MAX_VALUE_SIZE]; 136 | LONG ret, retSub, retVal; 137 | 138 | HKEY mTypeKey, majorTypeKey, subTypeKey; 139 | DWORD valueType, valueSize, valueNameSize; 140 | wchar_t *valueData; 141 | int mediaTypeCount = 0; 142 | MediaType *newType; 143 | CheckByteGroup *newGroup; 144 | 145 | ret = RegOpenKey (HKEY_CLASSES_ROOT, TEXT("Media Type"), &mTypeKey); 146 | if (ret != ERROR_SUCCESS) 147 | return -1; 148 | 149 | for (int i = 0; ret != ERROR_NO_MORE_ITEMS; i ++) 150 | { 151 | ret = RegEnumKey (mTypeKey, i, keyName, MAX_KEYNAME_SIZE); 152 | 153 | if (ret != ERROR_SUCCESS || !lstrcmp (keyName, TEXT("Extensions"))) // we don't want the Extensions subkey 154 | continue; 155 | 156 | retSub = RegOpenKey (mTypeKey, keyName, &majorTypeKey); 157 | 158 | if (retSub != ERROR_SUCCESS) 159 | continue; 160 | 161 | for (int j = 0; retSub != ERROR_NO_MORE_ITEMS; j ++) 162 | { 163 | retSub = RegEnumKey (majorTypeKey, j, subKeyName, MAX_KEYNAME_SIZE); 164 | if (retSub != ERROR_SUCCESS) 165 | continue; 166 | 167 | retVal = RegOpenKey (majorTypeKey, subKeyName, &subTypeKey); 168 | 169 | newType = new MediaType; 170 | if (!newType) 171 | { 172 | ErrorMsg (0, L"Out of memory."); 173 | return -1; 174 | } 175 | 176 | CLSIDFromString (keyName, &newType->majorType); 177 | CLSIDFromString (subKeyName, &newType->subType); 178 | 179 | for (int k = 0; retVal != ERROR_NO_MORE_ITEMS; k ++) 180 | { 181 | valueNameSize = MAX_VALUE_SIZE; 182 | retVal = RegEnumValue (subTypeKey, k, valueName, &valueNameSize, NULL, &valueType, NULL, &valueSize); 183 | 184 | if (retVal != ERROR_SUCCESS || valueType != REG_SZ || !lstrcmp (valueName, TEXT("Source Filter"))) // we don't need the source filter value 185 | continue; 186 | 187 | valueData = (wchar_t *) new BYTE [valueSize]; 188 | 189 | valueNameSize = MAX_VALUE_SIZE; 190 | retVal = RegEnumValue (subTypeKey, k, valueName, &valueNameSize, NULL, &valueType, 191 | (LPBYTE) valueData, &valueSize); 192 | 193 | if (retVal != ERROR_SUCCESS) 194 | { 195 | delete [] valueData; 196 | continue; 197 | } 198 | 199 | newGroup = new CheckByteGroup; // each value is one group 200 | 201 | if (!newGroup) 202 | { 203 | delete [] valueData; 204 | ErrorMsg (0, L"Out of memory."); 205 | return -1; 206 | } 207 | 208 | newGroup->checkByteCount = parseCheckBytes (valueData, &newGroup->checkBytes); 209 | 210 | if (newGroup->checkByteCount == -1) 211 | { 212 | delete [] valueData; 213 | delete newGroup; 214 | 215 | return -1; // this means out of memory 216 | } 217 | 218 | if (!newGroup->checkByteCount) 219 | { 220 | // if we get here there was a parse error or an invalid value in the registry 221 | delete newGroup; 222 | } 223 | else 224 | { 225 | newType->checkByteGroups.InsertLast (newGroup); 226 | newType->checkByteGroupCount ++; 227 | } 228 | 229 | delete [] valueData; 230 | } 231 | 232 | if (!newType->checkByteGroupCount) 233 | { 234 | // if we get here we were unable to parse any of the values in the current subkey 235 | delete newType; 236 | } 237 | else 238 | { 239 | mediaTypeList->InsertLast (newType); 240 | mediaTypeCount ++; 241 | } 242 | } 243 | } 244 | return mediaTypeCount; 245 | } 246 | 247 | int checkFileForMediaType (File *file, List *mediaTypeList, MediaType **foundMediaType) 248 | { 249 | MediaType *mt; 250 | CheckByteGroup *cbg; 251 | bool matches; 252 | BOOL ret; 253 | LONG lBytesRead; 254 | LONGLONG actOffset; 255 | BYTE *necessaryBytes; 256 | 257 | mt = mediaTypeList->First (); 258 | 259 | while (mt != NULL) 260 | { // loop over all filetypes 261 | cbg = mt->checkByteGroups.First (); 262 | 263 | while (cbg != NULL) 264 | { // loop over all groups of checkbytes 265 | matches = true; 266 | 267 | for (unsigned int i = 0; i < cbg->checkByteCount; i ++) 268 | { // we need to match all fields in one group 269 | if (cbg->checkBytes [i].offset < 0) 270 | actOffset = file->size + cbg->checkBytes [i].offset; 271 | else 272 | actOffset = cbg->checkBytes [i].offset; 273 | 274 | if (actOffset > file->size || actOffset < 0) 275 | { 276 | matches = false; 277 | break; 278 | } 279 | 280 | necessaryBytes = new BYTE [cbg->checkBytes [i].byteCount]; 281 | 282 | if (!necessaryBytes) 283 | { 284 | ErrorMsg (0, L"Out of memory."); 285 | return 0; 286 | } 287 | 288 | // read the necessary amount of bytes to compare to value (after masking) 289 | ret = file->SyncRead (actOffset, cbg->checkBytes [i].byteCount, necessaryBytes, &lBytesRead); 290 | 291 | if (ret != S_OK) 292 | { 293 | matches = false; 294 | delete [] necessaryBytes; 295 | break; 296 | } 297 | 298 | // mask and compare all bytes in this entry 299 | for (unsigned int j = 0; j < cbg->checkBytes [i].byteCount; j ++) 300 | { 301 | if ((necessaryBytes [j] & cbg->checkBytes [i].mask [j]) != cbg->checkBytes [i].value [j]) 302 | { 303 | matches = false; 304 | break; 305 | } 306 | } 307 | delete [] necessaryBytes; 308 | 309 | if (!matches) 310 | break; 311 | } 312 | 313 | if (matches) // one group is enought to match the filetype 314 | { 315 | *foundMediaType = mt; 316 | return 1; 317 | } 318 | cbg = mt->checkByteGroups.Next (cbg); 319 | } 320 | mt = mediaTypeList->Next (mt); 321 | } 322 | 323 | *foundMediaType = NULL; 324 | return 1; 325 | } 326 | -------------------------------------------------------------------------------- /Mediatype.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008, OV2 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef MEDIATYPE_H 19 | #define MEDIATYPE_H 20 | 21 | #include "List.h" 22 | 23 | class CheckByteDetails 24 | { 25 | public: 26 | CheckByteDetails () : offset (0), byteCount (0), mask (NULL), value (NULL) { } 27 | 28 | ~CheckByteDetails () 29 | { 30 | if (mask) 31 | delete [] mask; 32 | if (value) 33 | delete [] value; 34 | } 35 | 36 | LONGLONG offset; 37 | unsigned int byteCount; 38 | BYTE *mask; 39 | BYTE *value; 40 | }; 41 | 42 | class CheckByteGroup : public Node 43 | { 44 | public: 45 | CheckByteGroup () : checkBytes (NULL), checkByteCount (0) { } 46 | 47 | ~CheckByteGroup () 48 | { 49 | if (checkBytes) 50 | delete [] checkBytes; 51 | } 52 | 53 | CheckByteDetails *checkBytes; 54 | unsigned int checkByteCount; 55 | }; 56 | 57 | class MediaType : public Node 58 | { 59 | public: 60 | MediaType () : majorType (GUID_NULL), subType (GUID_NULL), checkByteGroupCount (0) { } 61 | 62 | ~MediaType () 63 | { 64 | checkByteGroups.Clear (); 65 | } 66 | 67 | GUID majorType; 68 | GUID subType; 69 | List checkByteGroups; 70 | unsigned int checkByteGroupCount; 71 | }; 72 | 73 | int getMediaTypeList (List *mediaTypeList); 74 | int checkFileForMediaType (File *file, List *mediaTypeList, MediaType **foundMediaType); 75 | 76 | #endif // MEDIATYPE_H 77 | -------------------------------------------------------------------------------- /OutputPin.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008-2012, OctaneSnail 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | 21 | #include "OutputPin.h" 22 | #include "RFS.h" 23 | #include "Utils.h" 24 | #include "Anchor.h" 25 | #include "File.h" 26 | 27 | 28 | CRFSOutputPin::CRFSOutputPin (CRARFileSource *pFilter, CCritSec *pLock, HRESULT *phr) : 29 | CBasePin (L"RAR File Source Output Pin", pFilter, pLock, phr, L"Output", PINDIR_OUTPUT) 30 | { 31 | m_align = 1; 32 | m_asked_for_reader = FALSE; 33 | m_file = NULL; 34 | m_flush = FALSE; 35 | 36 | if (!(m_event = CreateEvent (NULL, FALSE, FALSE, NULL))) 37 | { 38 | ErrorMsg (GetLastError (), L"CRFSOutputPin::CRFSOutputPin - CreateEvent"); 39 | 40 | m_event = INVALID_HANDLE_VALUE; 41 | 42 | if (phr) 43 | *phr = S_FALSE; 44 | } 45 | } 46 | 47 | CRFSOutputPin::~CRFSOutputPin () 48 | { 49 | CloseHandle (m_event); 50 | } 51 | 52 | STDMETHODIMP CRFSOutputPin::NonDelegatingQueryInterface (REFIID riid, void **ppv) 53 | { 54 | if (riid == IID_IAsyncReader) 55 | { 56 | m_asked_for_reader = TRUE; 57 | return GetInterface ((IAsyncReader*) this, ppv); 58 | } 59 | else 60 | return CBasePin::NonDelegatingQueryInterface (riid, ppv); 61 | } 62 | 63 | STDMETHODIMP CRFSOutputPin::Connect (IPin * pReceivePin, const AM_MEDIA_TYPE *pmt) 64 | { 65 | return CBasePin::Connect (pReceivePin, pmt); 66 | } 67 | 68 | HRESULT CRFSOutputPin::GetMediaType (int iPosition, CMediaType *pMediaType) 69 | { 70 | if (!pMediaType) 71 | return E_POINTER; 72 | 73 | if (!m_file) 74 | return E_UNEXPECTED; 75 | 76 | if (iPosition < 0) 77 | return E_INVALIDARG; 78 | 79 | if (iPosition > 1) 80 | return VFW_S_NO_MORE_ITEMS; 81 | 82 | if (iPosition == 0) 83 | *pMediaType = m_file->media_type; 84 | else 85 | *pMediaType = &MEDIASUBTYPE_NULL; 86 | 87 | return S_OK; 88 | } 89 | 90 | 91 | HRESULT CRFSOutputPin::CheckMediaType (const CMediaType* pType) 92 | { 93 | if (!m_file) 94 | return E_UNEXPECTED; 95 | 96 | // Treat MEDIASUBTYPE_NULL subtype as a wild card. 97 | if ((m_file->media_type.majortype == pType->majortype) && 98 | (m_file->media_type.subtype == MEDIASUBTYPE_NULL || m_file->media_type.subtype == pType->subtype)) 99 | { 100 | return S_OK; 101 | } 102 | 103 | return S_FALSE; 104 | } 105 | 106 | HRESULT CRFSOutputPin::CheckConnect (IPin *pPin) 107 | { 108 | m_asked_for_reader = FALSE; 109 | return CBasePin::CheckConnect (pPin); 110 | } 111 | 112 | HRESULT CRFSOutputPin::CompleteConnect (IPin *pReceivePin) 113 | { 114 | if (m_asked_for_reader) 115 | return CBasePin::CompleteConnect (pReceivePin); 116 | 117 | return VFW_E_NO_TRANSPORT; 118 | } 119 | 120 | HRESULT CRFSOutputPin::BreakConnect () 121 | { 122 | m_asked_for_reader = FALSE; 123 | return CBasePin::BreakConnect (); 124 | } 125 | 126 | STDMETHODIMP CRFSOutputPin::RequestAllocator (IMemAllocator *pPreferred, ALLOCATOR_PROPERTIES *pProps, IMemAllocator **ppActual) 127 | { 128 | if (!(pPreferred && pProps && ppActual)) 129 | return E_POINTER; 130 | 131 | ALLOCATOR_PROPERTIES actual; 132 | HRESULT hr; 133 | 134 | DbgLog((LOG_TRACE, 2, L"Requested alignment = %ld", pProps->cbAlign)); 135 | if (pProps->cbAlign) 136 | m_align = pProps->cbAlign; 137 | else 138 | pProps->cbAlign = m_align; 139 | 140 | if (pPreferred) 141 | { 142 | hr = pPreferred->SetProperties (pProps, &actual); 143 | 144 | if (SUCCEEDED (hr) && IsAligned (actual.cbAlign)) 145 | { 146 | DbgLog((LOG_TRACE, 2, L"Using preferred allocator.")); 147 | pPreferred->AddRef (); 148 | *ppActual = pPreferred; 149 | return S_OK; 150 | } 151 | } 152 | 153 | CMemAllocator *pMemObject = new CMemAllocator (L"RFS memory allocator", NULL, &hr); 154 | 155 | if (!pMemObject) 156 | return E_OUTOFMEMORY; 157 | 158 | if (FAILED (hr)) 159 | { 160 | delete pMemObject; 161 | return hr; 162 | } 163 | 164 | IMemAllocator* pAlloc; 165 | 166 | hr = pMemObject->QueryInterface (IID_IMemAllocator, (void **) &pAlloc); 167 | 168 | if (FAILED (hr)) 169 | { 170 | delete pMemObject; 171 | return E_NOINTERFACE; 172 | } 173 | 174 | hr = pAlloc->SetProperties (pProps, &actual); 175 | 176 | if (SUCCEEDED (hr) && IsAligned (actual.cbAlign)) 177 | { 178 | DbgLog((LOG_TRACE, 2, L"Using our allocator.")); 179 | *ppActual = pAlloc; 180 | return S_OK; 181 | } 182 | 183 | pAlloc->Release (); 184 | 185 | if (SUCCEEDED (hr)) 186 | hr = VFW_E_BADALIGN; 187 | 188 | DbgLog((LOG_TRACE, 2, L"RequestAllocator failed.")); 189 | return hr; 190 | } 191 | 192 | HRESULT CRFSOutputPin::ConvertSample (IMediaSample* sample, LONGLONG *pos, DWORD *length, BYTE **buffer) 193 | { 194 | if (!(sample && pos && length && buffer)) 195 | return E_POINTER; 196 | 197 | REFERENCE_TIME start, stop; 198 | 199 | HRESULT hr = sample->GetTime (&start, &stop); 200 | if (FAILED (hr)) 201 | return hr; 202 | 203 | if (start < 0) 204 | return E_UNEXPECTED; 205 | 206 | LONGLONG llPos = start / UNITS; 207 | LONGLONG llLength = (stop - start) / UNITS; 208 | 209 | if (llLength < 0 || llLength > LONG_MAX) 210 | return E_UNEXPECTED; 211 | 212 | DWORD lLength = (LONG) llLength; 213 | LONGLONG llTotal = m_file->size; 214 | 215 | if (llPos > llTotal) 216 | { 217 | DbgLog((LOG_TRACE, 2, L"ConvertSample EOF pos = %lld total = %lld", llPos, llTotal)); 218 | return ERROR_HANDLE_EOF; 219 | } 220 | 221 | if (llPos + lLength > llTotal) 222 | { 223 | llTotal = (llTotal + m_align - 1) & ~((LONGLONG) (m_align - 1)); 224 | 225 | if (llPos + lLength > llTotal) 226 | { 227 | lLength = (LONG) (llTotal - llPos); 228 | 229 | stop = llTotal * UNITS; 230 | sample->SetTime (&start, &stop); 231 | } 232 | } 233 | 234 | BYTE* b; 235 | hr = sample->GetPointer (&b); 236 | if (FAILED (hr)) 237 | { 238 | DbgLog((LOG_TRACE, 2, L"ConvertSample pSample->GetPointer failed")); 239 | return hr; 240 | } 241 | 242 | *pos = llPos; 243 | *length = lLength; 244 | *buffer = b; 245 | 246 | return S_OK; 247 | } 248 | 249 | STDMETHODIMP CRFSOutputPin::Request (IMediaSample* pSample, DWORD_PTR dwUser) 250 | { 251 | LONGLONG llPosition; 252 | DWORD lLength; 253 | BYTE* pBuffer; 254 | 255 | if (m_flush) 256 | { 257 | DbgLog((LOG_TRACE, 2, L"Request called during flush.")); 258 | return VFW_E_WRONG_STATE; 259 | } 260 | 261 | if (!m_file) 262 | { 263 | DbgLog((LOG_TRACE, 2, L"Request called with no file loaded.")); 264 | return E_UNEXPECTED; 265 | } 266 | 267 | HRESULT hr = ConvertSample (pSample, &llPosition, &lLength, &pBuffer); 268 | 269 | if (FAILED (hr)) 270 | return hr; 271 | 272 | if (!(IsAligned ((INT_PTR) llPosition) && IsAligned ((INT_PTR) lLength) && IsAligned ((INT_PTR) pBuffer))) 273 | { 274 | DbgLog((LOG_TRACE, 2, L"SyncReadAligned bad alignment. align = %lu, pos = %lld, len = %lu, buf = %p", 275 | m_align, llPosition, lLength, pBuffer)); 276 | return VFW_E_BADALIGN; 277 | } 278 | 279 | LARGE_INTEGER offset; 280 | DWORD to_read, acc = 0; 281 | LONGLONG offset2; 282 | int pos = m_file->FindStartPart (llPosition); 283 | 284 | if (pos == -1) 285 | return S_FALSE; 286 | 287 | ReadRequest *request = new ReadRequest (); 288 | 289 | if (!request) 290 | return E_OUTOFMEMORY; 291 | 292 | Anchor arr (&request); 293 | 294 | request->dwUser = dwUser; 295 | request->pSample = pSample; 296 | request->count = 0; 297 | 298 | FilePart *part = m_file->array + pos; 299 | 300 | offset2 = llPosition - part->in_file_offset; 301 | offset.QuadPart = part->in_rar_offset + offset2; 302 | 303 | while (true) 304 | { 305 | SubRequest *sr = new SubRequest (); 306 | 307 | if (!sr) 308 | { 309 | ErrorMsg (0, L"Out of memory."); 310 | return E_OUTOFMEMORY; 311 | } 312 | 313 | request->subreqs.InsertLast (sr); 314 | request->count ++; 315 | 316 | to_read = min (lLength, (DWORD) (part->size - offset2)); 317 | 318 | sr->file = part->file; 319 | sr->expected = to_read; 320 | sr->o.hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); 321 | 322 | if (!sr->o.hEvent) 323 | { 324 | sr->o.hEvent = INVALID_HANDLE_VALUE; 325 | return S_FALSE; 326 | } 327 | 328 | sr->o.Offset = offset.LowPart; 329 | sr->o.OffsetHigh = offset.HighPart; 330 | 331 | if (!ReadFile (part->file, pBuffer + acc, to_read, NULL, &sr->o)) 332 | { 333 | DWORD err = GetLastError (); 334 | 335 | // FIXME: Do something smart in response to EOF. 336 | if (err != ERROR_IO_PENDING && err != ERROR_HANDLE_EOF) 337 | { 338 | ErrorMsg (err, L"CRFSOutputPin::Request - ReadFile"); 339 | return S_FALSE; 340 | } 341 | } 342 | lLength -= to_read; 343 | acc += to_read; 344 | 345 | if (lLength <= 0) 346 | break; 347 | 348 | pos ++; 349 | 350 | if (pos >= m_file->parts) 351 | return S_FALSE; 352 | 353 | part ++; 354 | offset2 = 0; 355 | offset.QuadPart = part->in_rar_offset; 356 | } 357 | 358 | m_lock.Lock (); 359 | 360 | arr.Release (); 361 | m_requests.InsertFirst (request); 362 | 363 | if (!SetEvent (m_event)) 364 | ErrorMsg (GetLastError (), L"CRFSOutputPin::Request - SetEvent"); 365 | 366 | m_lock.Unlock (); 367 | 368 | return S_OK; 369 | } 370 | 371 | HRESULT CRFSOutputPin::DoFlush (IMediaSample **ppSample, DWORD_PTR *pdwUser) 372 | { 373 | ReadRequest *rr; 374 | SubRequest *sr; 375 | 376 | DbgLog((LOG_TRACE, 2, L"WaitForNext is flushing...")); 377 | 378 | m_lock.Lock (); 379 | rr = m_requests.UnlinkLast (); 380 | m_lock.Unlock (); 381 | 382 | if (!rr) 383 | { 384 | *ppSample = NULL; 385 | return VFW_E_TIMEOUT; 386 | } 387 | 388 | while (sr = rr->subreqs.UnlinkLast ()) 389 | { 390 | CancelIo (sr->file); 391 | delete sr; 392 | } 393 | 394 | *pdwUser = rr->dwUser; 395 | *ppSample = rr->pSample; 396 | 397 | delete rr; 398 | 399 | return VFW_E_TIMEOUT; 400 | } 401 | 402 | STDMETHODIMP CRFSOutputPin::WaitForNext (DWORD dwTimeout, IMediaSample **ppSample, DWORD_PTR *pdwUser) 403 | { 404 | HRESULT ret = S_OK; 405 | DWORD r; 406 | ReadRequest *rr; 407 | 408 | if (!(ppSample && pdwUser)) 409 | return E_POINTER; 410 | 411 | if (m_flush) 412 | return DoFlush (ppSample, pdwUser); 413 | 414 | m_lock.Lock (); 415 | rr = m_requests.UnlinkLast (); 416 | m_lock.Unlock (); 417 | 418 | Anchor arr (&rr); 419 | 420 | while (!rr) 421 | { 422 | r = WaitForSingleObject (m_event, dwTimeout); 423 | 424 | if (m_flush) 425 | return DoFlush (ppSample, pdwUser); 426 | 427 | if (r == WAIT_TIMEOUT) 428 | return VFW_E_TIMEOUT; 429 | 430 | if (r == WAIT_FAILED) 431 | { 432 | ErrorMsg (GetLastError (), L"CRFSOutputPin::WaitForNext - WaitForSingleObject"); 433 | return E_FAIL; 434 | } 435 | 436 | m_lock.Lock (); 437 | rr = m_requests.UnlinkLast (); 438 | m_lock.Unlock (); 439 | 440 | if (!rr) 441 | DbgLog((LOG_TRACE, 2, L"Got nothing?!?!")); 442 | } 443 | 444 | DWORD count, read, acc = 0; 445 | SubRequest *sr = rr->subreqs.First (); 446 | 447 | count = rr->count; 448 | 449 | HANDLE *hArray = new HANDLE [count]; 450 | 451 | for (DWORD i = 0; i < count; i ++) 452 | { 453 | hArray [i] = sr->o.hEvent; 454 | sr = rr->subreqs.Next (sr); 455 | } 456 | 457 | // FIXME: Any time spent waiting in WaitForSingleObject above should be subtracted from dwTimeout 458 | r = WaitForMultipleObjects (count, hArray, TRUE, dwTimeout); 459 | 460 | delete [] hArray; 461 | 462 | if (r == WAIT_TIMEOUT) 463 | { 464 | // Put it back into the list. 465 | m_lock.Lock (); 466 | arr.Release (); 467 | m_requests.InsertLast (rr); 468 | m_lock.Unlock (); 469 | return VFW_E_TIMEOUT; 470 | } 471 | 472 | *pdwUser = rr->dwUser; 473 | *ppSample = rr->pSample; 474 | 475 | if (r == WAIT_FAILED) 476 | { 477 | ErrorMsg (GetLastError (), L"CRFSOutputPin::WaitForNext - WaitForMultipleObjects"); 478 | return E_FAIL; 479 | } 480 | 481 | while (sr = rr->subreqs.UnlinkFirst ()) 482 | { 483 | read = 0; 484 | 485 | if (!GetOverlappedResult (sr->file, &sr->o, &read, TRUE)) 486 | { 487 | ErrorMsg (GetLastError (), L"CRFSOutputPin::WaitForNext - GetOverlappedResult"); 488 | acc += read; 489 | delete sr; 490 | ret = S_FALSE; // FIXME: Should probably return EOF if that's what happened. 491 | break; 492 | } 493 | 494 | acc += read; 495 | 496 | // TODO: Try to recover if read != sr->expected. 497 | if (read != sr->expected) 498 | { 499 | DbgLog((LOG_TRACE, 2, L"CRFSOutputPin::WaitForNext Got %lu expected %lu!", read, sr->expected)); 500 | delete sr; 501 | ret = S_FALSE; 502 | break; 503 | } 504 | delete sr; 505 | } 506 | 507 | rr->pSample->SetActualDataLength (acc); 508 | 509 | return ret; 510 | } 511 | 512 | 513 | STDMETHODIMP CRFSOutputPin::SyncReadAligned (IMediaSample* pSample) 514 | { 515 | LONGLONG llPosition; 516 | DWORD lLength; 517 | BYTE* pBuffer; 518 | 519 | if (!m_file) 520 | { 521 | DbgLog((LOG_TRACE, 2, L"SyncReadAligned called with no file loaded.")); 522 | return E_UNEXPECTED; 523 | } 524 | 525 | HRESULT hr = ConvertSample (pSample, &llPosition, &lLength, &pBuffer); 526 | 527 | if (FAILED (hr)) 528 | return hr; 529 | 530 | if (!(IsAligned ((INT_PTR) llPosition) && IsAligned ((INT_PTR) lLength) && IsAligned ((INT_PTR) pBuffer))) 531 | { 532 | DbgLog((LOG_TRACE, 2, L"SyncReadAligned bad alignment. align = %lu, pos = %lld, len = %lu, buf = %p", 533 | m_align, llPosition, lLength, pBuffer)); 534 | return VFW_E_BADALIGN; 535 | } 536 | 537 | LONG cbActual = 0; 538 | 539 | hr = m_file->SyncRead (llPosition, lLength, pBuffer, &cbActual); 540 | 541 | pSample->SetActualDataLength (cbActual); 542 | 543 | return hr; 544 | } 545 | 546 | STDMETHODIMP CRFSOutputPin::SyncRead (LONGLONG llPosition, LONG lLength, BYTE* pBuffer) 547 | { 548 | if (!m_file) 549 | { 550 | DbgLog((LOG_TRACE, 2, L"SyncRead called with no file loaded.")); 551 | return E_UNEXPECTED; 552 | } 553 | 554 | if (lLength < 0) 555 | return E_UNEXPECTED; 556 | 557 | return m_file->SyncRead (llPosition, lLength, pBuffer, NULL); 558 | } 559 | 560 | STDMETHODIMP CRFSOutputPin::Length (LONGLONG *pTotal, LONGLONG *pAvailable) 561 | { 562 | if (!m_file) 563 | return E_UNEXPECTED; 564 | 565 | if (pTotal) 566 | *pTotal = m_file->size; 567 | 568 | if (pAvailable) 569 | *pAvailable = m_file->size; 570 | 571 | return S_OK; 572 | } 573 | 574 | STDMETHODIMP CRFSOutputPin::BeginFlush (void) 575 | { 576 | DbgLog((LOG_TRACE, 2, L"CRFSOutputPin::BeginFlush")); 577 | m_flush = TRUE; 578 | SetEvent (m_event); 579 | return S_OK; 580 | } 581 | 582 | STDMETHODIMP CRFSOutputPin::EndFlush (void) 583 | { 584 | DbgLog((LOG_TRACE, 2, L"CRFSOutputPin::EndFlush")); 585 | m_flush = FALSE; 586 | return S_OK; 587 | } 588 | -------------------------------------------------------------------------------- /OutputPin.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008-2012, OctaneSnail 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef OUTPUT_PIN_H 19 | #define OUTPUT_PIN_H 20 | 21 | #include "List.h" 22 | 23 | class CRARFileSource; 24 | class File; 25 | class FilePart; 26 | 27 | class SubRequest : public Node 28 | { 29 | public: 30 | SubRequest (void) : file (INVALID_HANDLE_VALUE), expected (0) 31 | { memset (&o, 0, sizeof (OVERLAPPED)); o.hEvent = INVALID_HANDLE_VALUE; } 32 | ~SubRequest (void) { if (o.hEvent != INVALID_HANDLE_VALUE) CloseHandle (o.hEvent); } 33 | 34 | HANDLE file; 35 | DWORD expected; 36 | OVERLAPPED o; 37 | }; 38 | 39 | class ReadRequest : public Node 40 | { 41 | public: 42 | ~ReadRequest (void) { subreqs.Clear (); } 43 | 44 | DWORD_PTR dwUser; 45 | IMediaSample *pSample; 46 | 47 | DWORD count; 48 | List subreqs; 49 | }; 50 | 51 | class CRFSOutputPin : 52 | public CBasePin, 53 | public IAsyncReader 54 | { 55 | public: 56 | CRFSOutputPin (CRARFileSource *pFilter, CCritSec *pLock, HRESULT *phr); 57 | ~CRFSOutputPin (void); 58 | 59 | DECLARE_IUNKNOWN; 60 | 61 | // Reveals IAsyncReader 62 | STDMETHODIMP NonDelegatingQueryInterface (REFIID riid, void **ppv); 63 | 64 | // IPin interface 65 | STDMETHODIMP Connect (IPin *pReceivePin, const AM_MEDIA_TYPE *pmt); 66 | 67 | // CBasePin 68 | HRESULT GetMediaType (int iPosition, CMediaType *pMediaType); 69 | HRESULT CheckMediaType (const CMediaType* pType); 70 | HRESULT CheckConnect (IPin *pPin); 71 | HRESULT CompleteConnect (IPin *pReceivePin); 72 | HRESULT BreakConnect (); 73 | 74 | // IAsyncReader interface 75 | STDMETHODIMP RequestAllocator (IMemAllocator *pPreferred, ALLOCATOR_PROPERTIES *pProps, IMemAllocator **ppActual); 76 | 77 | STDMETHODIMP Request (IMediaSample* pSample, DWORD_PTR dwUser); 78 | STDMETHODIMP WaitForNext (DWORD dwTimeout, IMediaSample **ppSample, DWORD_PTR *pdwUser); 79 | 80 | STDMETHODIMP SyncReadAligned (IMediaSample *pSample); 81 | STDMETHODIMP SyncRead (LONGLONG llPosition, LONG lLength, BYTE *pBuffer); 82 | 83 | STDMETHODIMP Length (LONGLONG *pTotal, LONGLONG *pAvailable); 84 | 85 | STDMETHODIMP BeginFlush (void); 86 | STDMETHODIMP EndFlush (void); 87 | 88 | void SetFile (File *file) { m_file = file; } 89 | 90 | private: 91 | DWORD m_align; 92 | BOOL m_asked_for_reader; 93 | File *m_file; 94 | BOOL m_flush; 95 | HANDLE m_event; 96 | 97 | List m_requests; 98 | CCritSec m_lock; 99 | 100 | HRESULT ConvertSample (IMediaSample *sample, LONGLONG *pos, DWORD *length, BYTE **buffer); 101 | HRESULT DoFlush (IMediaSample **ppSample, DWORD_PTR *pdwUser); 102 | 103 | BOOL IsAligned (INT_PTR l) { return !(l & (m_align - 1)); } 104 | }; 105 | 106 | #endif // OUTPUT_PIN_H 107 | -------------------------------------------------------------------------------- /RAR.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008-2012, OctaneSnail 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | 21 | #include "rar.h" 22 | #include "utils.h" 23 | 24 | #define READ_ITEM(item) READ_ITEM2(&item, sizeof(item)) 25 | 26 | #define READ_ITEM2(item, size) { \ 27 | if (!ReadFile (file, item, size, &read, NULL)) \ 28 | { \ 29 | ErrorMsg (GetLastError (), L"Could not read RAR header"); \ 30 | return S_FALSE; \ 31 | } \ 32 | if (read < size) return ERROR_HANDLE_EOF; \ 33 | acc += read; } 34 | 35 | DWORD ReadHeader (HANDLE file, rar_header_t *dest) 36 | { 37 | fixed_header_t fh; 38 | fixed_file_header_t ffh; 39 | DWORD read, dword; 40 | LONGLONG acc = 0; 41 | 42 | // Read fixed archive header. 43 | READ_ITEM(fh); 44 | 45 | dest->ch.crc = fh.crc; 46 | dest->ch.flags = fh.flags; 47 | dest->ch.type = fh.type; 48 | 49 | switch (fh.type) 50 | { 51 | case HEADER_TYPE_FILE: 52 | READ_ITEM(ffh); 53 | 54 | dest->ch.size.QuadPart = (LONGLONG) ffh.packedSize + fh.size; 55 | dest->fh.size.LowPart = ffh.size; 56 | dest->fh.os = ffh.os; 57 | dest->fh.crc = ffh.crc; 58 | dest->fh.timestamp = ffh.timestamp; 59 | dest->fh.version = ffh.version; 60 | dest->fh.method = ffh.method; 61 | dest->fh.name_len = ffh.name_len; 62 | dest->fh.attributes = ffh.attributes; 63 | 64 | if (fh.flags & LHD_LARGE) 65 | { 66 | READ_ITEM(dword); // Packed size high dword 67 | dest->ch.size.HighPart += dword; 68 | READ_ITEM(dword); // Unpacked size high dword 69 | dest->fh.size.HighPart = dword; 70 | } 71 | else 72 | dest->fh.size.HighPart = 0; 73 | 74 | dest->fh.filename = new char [dest->fh.name_len + 1]; 75 | if (!dest->fh.filename) 76 | { 77 | ErrorMsg (0, L"Out of memory while reading RAR header."); 78 | return ERROR_OUTOFMEMORY; 79 | } 80 | READ_ITEM2 (dest->fh.filename, dest->fh.name_len); 81 | dest->fh.filename [dest->fh.name_len] = 0; 82 | 83 | if (acc < fh.size) 84 | { 85 | SetFilePointer (file, (LONG) (fh.size - acc), NULL, FILE_CURRENT); 86 | acc = fh.size; 87 | } 88 | break; 89 | 90 | default: 91 | if (fh.flags & LONG_BLOCK) 92 | { 93 | READ_ITEM (dword); 94 | dest->ch.size.QuadPart = (LONGLONG) dword + fh.size; 95 | } 96 | else 97 | { 98 | dest->ch.size.HighPart = 0; 99 | dest->ch.size.LowPart = fh.size; 100 | } 101 | } 102 | 103 | if (acc > dest->ch.size.QuadPart) 104 | { 105 | ErrorMsg (0, L"Overrun while reading RAR header."); 106 | return S_FALSE; 107 | } 108 | 109 | if (fh.type != HEADER_TYPE_FILE && acc < dest->ch.size.QuadPart) 110 | { 111 | LARGE_INTEGER li; 112 | li.QuadPart = dest->ch.size.QuadPart - acc; 113 | SetFilePointerEx (file, li, NULL, FILE_CURRENT); 114 | dest->bytesRemaining.QuadPart = 0; 115 | } 116 | else 117 | dest->bytesRemaining.QuadPart = dest->ch.size.QuadPart - acc; 118 | 119 | return ERROR_SUCCESS; 120 | } 121 | -------------------------------------------------------------------------------- /RAR.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008-2012, OctaneSnail 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef RAR_H 19 | #define RAR_H 20 | 21 | #include "RAR_defines.h" 22 | 23 | #define HEADER_TYPE_MARKER 0x72 24 | #define HEADER_TYPE_ARCHIVE 0x73 25 | #define HEADER_TYPE_FILE 0x74 26 | #define HEADER_TYPE_SUBBLOCK 0x77 27 | #define HEADER_TYPE_RECOVERY 0x78 28 | #define HEADER_TYPE_NEWSUBLOCK 0x7a 29 | #define HEADER_TYPE_END 0x7b 30 | 31 | #pragma pack (push, 1) 32 | 33 | // Fixed size parts of the in file headers. 34 | 35 | typedef struct 36 | { 37 | WORD crc; 38 | BYTE type; 39 | WORD flags; 40 | WORD size; 41 | } fixed_header_t; 42 | 43 | typedef struct 44 | { 45 | DWORD packedSize; 46 | DWORD size; 47 | BYTE os; 48 | DWORD crc; 49 | DWORD timestamp; 50 | BYTE version; 51 | BYTE method; 52 | WORD name_len; 53 | DWORD attributes; 54 | } fixed_file_header_t; 55 | 56 | #pragma pack (pop) 57 | 58 | // In memory representation 59 | 60 | typedef struct 61 | { 62 | WORD crc; 63 | BYTE type; 64 | WORD flags; 65 | LARGE_INTEGER size; 66 | } common_header_t; 67 | 68 | typedef struct 69 | { 70 | WORD reserved1; 71 | DWORD reserved2; 72 | } archive_header_t; 73 | 74 | typedef struct 75 | { 76 | LARGE_INTEGER size; 77 | 78 | DWORD crc; 79 | DWORD timestamp; 80 | DWORD timestamp_ext; 81 | DWORD attributes; 82 | DWORD name_len; 83 | 84 | char *filename; 85 | 86 | BYTE os; 87 | BYTE version; 88 | BYTE method; 89 | 90 | } file_header_t; 91 | 92 | typedef struct 93 | { 94 | DWORD crc; 95 | WORD volume_number; 96 | } end_header_t; 97 | 98 | typedef struct 99 | { 100 | common_header_t ch; 101 | 102 | union 103 | { 104 | archive_header_t ah; 105 | file_header_t fh; 106 | end_header_t eh; 107 | }; 108 | 109 | LARGE_INTEGER bytesRemaining; 110 | } rar_header_t; 111 | 112 | DWORD ReadHeader (HANDLE file, rar_header_t *dest); 113 | 114 | #endif // RAR_H 115 | -------------------------------------------------------------------------------- /RARFileSource.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RARFileSource", "RARFileSource.vcxproj", "{2B7F22D7-1750-47C5-8709-1A3688B62499}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Debug|x64 = Debug|x64 10 | Release|Win32 = Release|Win32 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {2B7F22D7-1750-47C5-8709-1A3688B62499}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {2B7F22D7-1750-47C5-8709-1A3688B62499}.Debug|Win32.Build.0 = Debug|Win32 16 | {2B7F22D7-1750-47C5-8709-1A3688B62499}.Debug|x64.ActiveCfg = Debug|x64 17 | {2B7F22D7-1750-47C5-8709-1A3688B62499}.Debug|x64.Build.0 = Debug|x64 18 | {2B7F22D7-1750-47C5-8709-1A3688B62499}.Release|Win32.ActiveCfg = Release|Win32 19 | {2B7F22D7-1750-47C5-8709-1A3688B62499}.Release|Win32.Build.0 = Release|Win32 20 | {2B7F22D7-1750-47C5-8709-1A3688B62499}.Release|x64.ActiveCfg = Release|x64 21 | {2B7F22D7-1750-47C5-8709-1A3688B62499}.Release|x64.Build.0 = Release|x64 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | -------------------------------------------------------------------------------- /RARFileSource.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {2B7F22D7-1750-47C5-8709-1A3688B62499} 23 | RARFileSource 24 | Win32Proj 25 | 26 | 27 | 28 | DynamicLibrary 29 | Unicode 30 | true 31 | 32 | 33 | DynamicLibrary 34 | Unicode 35 | true 36 | 37 | 38 | DynamicLibrary 39 | false 40 | Unicode 41 | 42 | 43 | DynamicLibrary 44 | false 45 | Unicode 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | <_ProjectFileVersion>10.0.30319.1 65 | $(SolutionDir)$(Configuration)\ 66 | $(Configuration)\ 67 | $(Platform)\$(Configuration)\ 68 | true 69 | true 70 | $(SolutionDir)$(Configuration)\ 71 | $(SolutionDir)$(Platform)\$(Configuration)\ 72 | $(Configuration)\ 73 | $(Platform)\$(Configuration)\ 74 | false 75 | false 76 | .ax 77 | .ax 78 | .ax 79 | .ax 80 | 81 | 82 | 83 | Disabled 84 | %(AdditionalIncludeDirectories) 85 | WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) 86 | true 87 | EnableFastChecks 88 | MultiThreadedDebugDLL 89 | 90 | 91 | true 92 | Level3 93 | EditAndContinue 94 | 95 | 96 | strmbasd.lib;winmm.lib;%(AdditionalDependencies) 97 | $(OutDir)$(TargetName)$(TargetExt) 98 | 99 | 100 | RFS.def 101 | true 102 | true 103 | Windows 104 | false 105 | 106 | 107 | MachineX86 108 | 109 | 110 | 111 | 112 | Disabled 113 | %(AdditionalIncludeDirectories) 114 | WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) 115 | EnableFastChecks 116 | MultiThreadedDebugDLL 117 | 118 | 119 | true 120 | Level3 121 | ProgramDatabase 122 | 123 | 124 | strmbasd.lib;winmm.lib;%(AdditionalDependencies) 125 | $(OutDir)$(TargetName)$(TargetExt) 126 | 127 | 128 | RFS.def 129 | true 130 | true 131 | Windows 132 | false 133 | 134 | 135 | 136 | 137 | 138 | 139 | Full 140 | AnySuitable 141 | true 142 | Speed 143 | true 144 | %(AdditionalIncludeDirectories) 145 | WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) 146 | MultiThreadedDLL 147 | false 148 | StreamingSIMDExtensions 149 | 150 | 151 | Level3 152 | ProgramDatabase 153 | true 154 | 155 | 156 | strmbase.lib;winmm.lib;%(AdditionalDependencies) 157 | $(OutDir)$(TargetName)$(TargetExt) 158 | 159 | 160 | RFS.def 161 | true 162 | Windows 163 | true 164 | true 165 | false 166 | 167 | 168 | MachineX86 169 | 170 | 171 | 172 | 173 | Full 174 | AnySuitable 175 | true 176 | Speed 177 | true 178 | %(AdditionalIncludeDirectories) 179 | WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) 180 | MultiThreadedDLL 181 | false 182 | StreamingSIMDExtensions 183 | 184 | 185 | Level3 186 | ProgramDatabase 187 | true 188 | 189 | 190 | strmbase.lib;winmm.lib;%(AdditionalDependencies) 191 | $(OutDir)$(TargetName)$(TargetExt) 192 | 193 | 194 | RFS.def 195 | true 196 | Windows 197 | true 198 | true 199 | false 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | true 208 | true 209 | true 210 | true 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | -------------------------------------------------------------------------------- /RARFileSource.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | 41 | 42 | Header Files 43 | 44 | 45 | Header Files 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | Header Files 58 | 59 | 60 | Header Files 61 | 62 | 63 | Header Files 64 | 65 | 66 | Header Files 67 | 68 | 69 | Header Files 70 | 71 | 72 | 73 | 74 | Resource Files 75 | 76 | 77 | Resource Files 78 | 79 | 80 | Resource Files 81 | 82 | 83 | Resource Files 84 | 85 | 86 | 87 | 88 | Resource Files 89 | 90 | 91 | -------------------------------------------------------------------------------- /RAR_defines.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef RAR_DEFINES_H 3 | #define RAR_DEFINES_H 4 | 5 | /* 6 | The defines below where taken from the UnRAR source distribution 7 | which came with the following license: 8 | 9 | The source code of UnRAR utility is freeware. This means: 10 | 11 | 1. All copyrights to RAR and the utility UnRAR are exclusively 12 | owned by the author - Alexander Roshal. 13 | 14 | 2. The UnRAR sources may be used in any software to handle RAR 15 | archives without limitations free of charge, but cannot be used 16 | to re-create the RAR compression algorithm, which is proprietary. 17 | Distribution of modified UnRAR sources in separate form or as a 18 | part of other software is permitted, provided that it is clearly 19 | stated in the documentation and source comments that the code may 20 | not be used to develop a RAR (WinRAR) compatible archiver. 21 | 22 | 3. The UnRAR utility may be freely distributed. It is allowed 23 | to distribute UnRAR inside of other software packages. 24 | 25 | 4. THE RAR ARCHIVER AND THE UnRAR UTILITY ARE DISTRIBUTED "AS IS". 26 | NO WARRANTY OF ANY KIND IS EXPRESSED OR IMPLIED. YOU USE AT 27 | YOUR OWN RISK. THE AUTHOR WILL NOT BE LIABLE FOR DATA LOSS, 28 | DAMAGES, LOSS OF PROFITS OR ANY OTHER KIND OF LOSS WHILE USING 29 | OR MISUSING THIS SOFTWARE. 30 | 31 | 5. Installing and using the UnRAR utility signifies acceptance of 32 | these terms and conditions of the license. 33 | 34 | 6. If you don't agree with terms of the license you must remove 35 | UnRAR files from your storage devices and cease to use the 36 | utility. 37 | 38 | Thank you for your interest in RAR and UnRAR. 39 | 40 | 41 | Alexander L. Roshal 42 | */ 43 | 44 | #define MHD_VOLUME 0x0001 45 | #define MHD_COMMENT 0x0002 46 | #define MHD_LOCK 0x0004 47 | #define MHD_SOLID 0x0008 48 | #define MHD_PACK_COMMENT 0x0010 49 | #define MHD_NEWNUMBERING 0x0010 50 | #define MHD_AV 0x0020 51 | #define MHD_PROTECT 0x0040 52 | #define MHD_PASSWORD 0x0080 53 | #define MHD_FIRSTVOLUME 0x0100 54 | #define MHD_ENCRYPTVER 0x0200 55 | 56 | #define LHD_SPLIT_BEFORE 0x0001 57 | #define LHD_SPLIT_AFTER 0x0002 58 | #define LHD_PASSWORD 0x0004 59 | #define LHD_COMMENT 0x0008 60 | #define LHD_SOLID 0x0010 61 | 62 | #define LHD_WINDOWMASK 0x00e0 63 | #define LHD_WINDOW64 0x0000 64 | #define LHD_WINDOW128 0x0020 65 | #define LHD_WINDOW256 0x0040 66 | #define LHD_WINDOW512 0x0060 67 | #define LHD_WINDOW1024 0x0080 68 | #define LHD_WINDOW2048 0x00a0 69 | #define LHD_WINDOW4096 0x00c0 70 | #define LHD_DIRECTORY 0x00e0 71 | 72 | #define LHD_LARGE 0x0100 73 | #define LHD_UNICODE 0x0200 74 | #define LHD_SALT 0x0400 75 | #define LHD_VERSION 0x0800 76 | #define LHD_EXTTIME 0x1000 77 | #define LHD_EXTFLAGS 0x2000 78 | 79 | #define SKIP_IF_UNKNOWN 0x4000 80 | #define LONG_BLOCK 0x8000 81 | 82 | #define EARC_NEXT_VOLUME 0x0001 83 | #define EARC_DATACRC 0x0002 84 | #define EARC_REVSPACE 0x0004 85 | #define EARC_VOLNUMBER 0x0008 86 | 87 | #endif RAR_DEFINES_H 88 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | 2 | Building from source 3 | -------------------- 4 | 5 | Building RARFileSource requires Visual Studio 2010, the DirectShow SDK and the 6 | DirectShow Base Classes. 7 | 8 | The DirectShow SDK and Base Classes are part of the Windows SDK, which can be 9 | found here: http://msdn.microsoft.com/en-us/windows/bb980924.aspx 10 | 11 | Instructions on how to build and use the Base Classes can be found here: 12 | http://msdn.microsoft.com/en-us/library/ms783325(VS.85).aspx 13 | 14 | 15 | With the prerequisites in place just load and build the RARFileSource.sln 16 | solution. 17 | 18 | Happy hacking! Don't forget to submit patches! :) 19 | 20 | /OctaneSnail 21 | 22 | 23 | P.S. 24 | 25 | No. I don't have time to answer questions about how to get the SDK and Base 26 | Classes installed and working. 27 | -------------------------------------------------------------------------------- /RFS.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008-2012, OctaneSnail 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "RFS.h" 24 | #include "Utils.h" 25 | #include "RAR.h" 26 | #include "Anchor.h" 27 | #include "resource.h" 28 | #include "Mediatype.h" 29 | #include "File.h" 30 | 31 | 32 | // {9FFE11D2-29F2-463f-AD5F-C04A5EE2E58D} 33 | DEFINE_GUID(CLSID_RARFileSource, 34 | 0x9ffe11d2, 0x29f2, 0x463f, 0xad, 0x5f, 0xc0, 0x4a, 0x5e, 0xe2, 0xe5, 0x8d); 35 | 36 | #define RFS_GUID_STRING "{9FFE11D2-29F2-463f-AD5F-C04A5EE2E58D}" 37 | 38 | 39 | //{1AC0BEBD-4D2B-45AD-BCEB-F2C41C5E3788} 40 | DEFINE_GUID(MEDIASUBTYPE_Matroska, 41 | 0x1AC0BEBD, 0x4D2B, 0x45AD, 0xBC, 0xEB, 0xF2, 0xC4, 0x1C, 0x5E, 0x37, 0x88); 42 | 43 | // Setup information 44 | const AMOVIESETUP_MEDIATYPE sudPinTypes = 45 | { 46 | &MEDIATYPE_Stream, // Major type 47 | &MEDIASUBTYPE_NULL // Minor type 48 | }; 49 | 50 | const AMOVIESETUP_PIN sudpPin = 51 | { 52 | L"Output", // Pin name 53 | FALSE, // Is it rendered 54 | TRUE, // Is it an output 55 | FALSE, // Zero instances allowed 56 | FALSE, // Multiple instances allowed 57 | &CLSID_NULL, // Connects to filter 58 | NULL, // Connects to pin 59 | 1, // Number of types 60 | &sudPinTypes // Pin types 61 | }; 62 | 63 | const AMOVIESETUP_FILTER sudRARFileSource = 64 | { 65 | &CLSID_RARFileSource, // Filter CLSID 66 | L"RAR File Source", // Filter name 67 | MERIT_UNLIKELY, // Filter merit 68 | 1, // Number of pins 69 | &sudpPin // Pin information 70 | }; 71 | 72 | // List of class IDs and creator functions for the class factory. 73 | 74 | CFactoryTemplate g_Templates [] = 75 | { 76 | { 77 | L"RAR File Source", 78 | &CLSID_RARFileSource, 79 | CRARFileSource::CreateInstance, 80 | NULL, 81 | &sudRARFileSource 82 | } 83 | }; 84 | 85 | int g_cTemplates = sizeof (g_Templates) / sizeof (g_Templates [0]); 86 | 87 | 88 | /* static */ 89 | file_type_t CRARFileSource::s_file_types [] = 90 | { 91 | { "avi", &MEDIASUBTYPE_Avi }, 92 | { "mpg", &MEDIASUBTYPE_MPEG1System }, 93 | { "vob", &MEDIASUBTYPE_MPEG2_PROGRAM }, 94 | { "mkv", &MEDIASUBTYPE_Matroska }, 95 | { "mka", &MEDIASUBTYPE_Matroska }, 96 | { "mks", &MEDIASUBTYPE_Matroska }, 97 | { "mov", &MEDIASUBTYPE_QTMovie }, 98 | { "wav", &MEDIASUBTYPE_WAVE }, 99 | { "mp3", &MEDIASUBTYPE_MPEG1Audio }, 100 | { "mpa", &MEDIASUBTYPE_MPEG1Audio }, 101 | { "mpv", &MEDIASUBTYPE_MPEG1Video }, 102 | { "dat", &MEDIASUBTYPE_MPEG1VideoCD }, 103 | { NULL, NULL } 104 | }; 105 | 106 | 107 | extern "C" BOOL WINAPI DllEntryPoint (HINSTANCE, ULONG, LPVOID); 108 | 109 | BOOL WINAPI DllMain (HINSTANCE hDllHandle, DWORD dwReason, LPVOID lpReserved) 110 | { 111 | return DllEntryPoint (hDllHandle, dwReason, lpReserved); 112 | } 113 | 114 | STDAPI DllRegisterServer () 115 | { 116 | HKEY key; 117 | LONG ret; 118 | int i; 119 | wchar_t key_name [] = L"Media Type\\Extensions\\.rar"; 120 | 121 | ret = RegCreateKey (HKEY_CLASSES_ROOT, key_name, &key); 122 | 123 | if (ret != ERROR_SUCCESS) 124 | { 125 | ret = RegOpenKey (HKEY_CLASSES_ROOT, key_name, &key); 126 | 127 | if (ret != ERROR_SUCCESS) 128 | return ret; 129 | } 130 | 131 | ret = RegSetValueExA (key, "Source Filter", 0, REG_SZ, (BYTE *) RFS_GUID_STRING, (DWORD) strlen (RFS_GUID_STRING) + 1); 132 | 133 | if (ret != ERROR_SUCCESS) 134 | { 135 | RegCloseKey (key); 136 | return ret; 137 | } 138 | 139 | RegCloseKey (key); 140 | 141 | for (i = 0; i < 100; i ++) 142 | { 143 | key_name [24] = L'0' + i / 10; 144 | key_name [25] = L'0' + i % 10; 145 | 146 | ret = RegCreateKey (HKEY_CLASSES_ROOT, key_name, &key); 147 | 148 | if (ret != ERROR_SUCCESS) 149 | { 150 | ret = RegOpenKey (HKEY_CLASSES_ROOT, key_name, &key); 151 | 152 | if (ret != ERROR_SUCCESS) 153 | continue; 154 | } 155 | 156 | ret = RegSetValueExA (key, "Source Filter", 0, REG_SZ, (BYTE *) RFS_GUID_STRING, (DWORD) strlen (RFS_GUID_STRING) + 1); 157 | 158 | RegCloseKey (key); 159 | } 160 | 161 | return AMovieDllRegisterServer2 (TRUE); 162 | } 163 | 164 | STDAPI DllUnregisterServer () 165 | { 166 | HKEY key; 167 | LONG ret; 168 | char value [40]; 169 | DWORD len = sizeof (value); 170 | wchar_t key_name [] = L"Media Type\\Extensions\\.rar"; 171 | int i; 172 | 173 | for (i = 0; i < 101; i ++) 174 | { 175 | ret = RegOpenKey (HKEY_CLASSES_ROOT, key_name, &key); 176 | if (ret == ERROR_SUCCESS) 177 | { 178 | ret = RegQueryValueExA (key, "Source Filter", NULL, NULL, (BYTE *) value, &len); 179 | RegCloseKey (key); 180 | 181 | if (ret == ERROR_SUCCESS) 182 | { 183 | if (!_stricmp (value, RFS_GUID_STRING)) 184 | RegDeleteKey (HKEY_CLASSES_ROOT, key_name); 185 | } 186 | } 187 | key_name [24] = L'0' + i / 10; 188 | key_name [25] = L'0' + i % 10; 189 | } 190 | 191 | return AMovieDllRegisterServer2 (FALSE); 192 | } 193 | 194 | CRARFileSource::CRARFileSource (LPUNKNOWN punk, HRESULT *phr) : 195 | CBaseFilter (L"RAR File Source", punk, &m_lock, CLSID_RARFileSource), 196 | m_pin (this, &m_lock, phr), 197 | m_file_name (NULL), 198 | m_file (NULL) 199 | { 200 | if (phr) 201 | *phr = S_OK; 202 | } 203 | 204 | CRARFileSource::~CRARFileSource () 205 | { 206 | delete m_file_name; 207 | delete m_file; 208 | } 209 | 210 | CUnknown *CRARFileSource::CreateInstance (LPUNKNOWN punk, HRESULT *phr) // OK 211 | { 212 | CRARFileSource *pNewObject = new CRARFileSource (punk, phr); 213 | 214 | if (pNewObject == NULL) 215 | *phr = E_OUTOFMEMORY; 216 | 217 | DbgSetModuleLevel (LOG_TRACE, 2); 218 | DbgLog((LOG_TRACE, 2, L"CRARFileSource::CreateInstance () succeded.")); 219 | 220 | return pNewObject; 221 | } 222 | 223 | STDMETHODIMP CRARFileSource::NonDelegatingQueryInterface (REFIID riid, void **ppv) 224 | { 225 | if (riid == IID_IFileSourceFilter) 226 | return GetInterface ((IFileSourceFilter *) this, ppv); 227 | else 228 | return CBaseFilter::NonDelegatingQueryInterface (riid, ppv); 229 | } 230 | 231 | /* static */ 232 | void CRARFileSource::UpdateArchiveName (wchar_t *ext, size_t len, int volume, bool new_numbering) 233 | { 234 | if (new_numbering) 235 | { 236 | StringCchPrintf (ext, len + 1, L"%0*d", len, volume + 1); 237 | ext [len] = L'.'; 238 | } 239 | else 240 | { 241 | ASSERT (len == 2); 242 | 243 | if (volume == 0) 244 | { 245 | ext [0] = L'a'; 246 | ext [1] = L'r'; 247 | } 248 | else 249 | StringCchPrintf (ext - 1, len + 2, L"%c%02d", 114 + (volume - 1) / 100, (volume - 1) % 100); 250 | } 251 | } 252 | 253 | #define HEADER_SKIP_FILE \ 254 | delete [] rh.fh.filename; \ 255 | SetFilePointerEx (hFile, rh.bytesRemaining, NULL, FILE_CURRENT); \ 256 | continue; 257 | 258 | int CRARFileSource::ScanArchive (wchar_t *archive_name, List *file_list, int *ok_files_found) 259 | { 260 | DWORD dwBytesRead; 261 | char *filename = NULL; 262 | wchar_t *current_rar_filename = NULL, *rar_ext; 263 | bool first_archive_file = true, rewind; 264 | bool multi_volume = false, new_numbering = false; 265 | rar_header_t rh; 266 | BYTE marker [7]; 267 | BYTE expected [7] = { 0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00 }; 268 | FilePart *new_part, *prev_part; 269 | LONGLONG collected; 270 | DWORD ret; 271 | DWORD files = 0, volumes = 0; 272 | int volume_digits; 273 | File *file = NULL; 274 | 275 | *ok_files_found = 0; 276 | LARGE_INTEGER zero = {0}; 277 | 278 | MediaType *mType; 279 | List mediaTypeList (true); 280 | 281 | Anchor af (&file); 282 | ArrayAnchor acrf (¤t_rar_filename); 283 | 284 | HANDLE hFile = INVALID_HANDLE_VALUE; 285 | Anchor ha (&hFile); 286 | 287 | int cch = lstrlen (archive_name) + 1; 288 | 289 | current_rar_filename = new wchar_t [cch]; 290 | if (!current_rar_filename) 291 | { 292 | ErrorMsg (0, L"Out of memory."); 293 | return 0; 294 | } 295 | 296 | CopyMemory (current_rar_filename, archive_name, cch * sizeof (wchar_t)); 297 | 298 | rar_ext = wcsrchr (current_rar_filename, '.'); 299 | 300 | if (getMediaTypeList (&mediaTypeList) == -1) 301 | return 0; // this means out of memory 302 | 303 | // Scan through archive volume(s) 304 | while (true) 305 | { 306 | ha.Close (); 307 | DbgLog((LOG_TRACE, 2, L"Loading file \"%s\".", current_rar_filename)); 308 | hFile = CreateFile (current_rar_filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 309 | if (hFile == INVALID_HANDLE_VALUE) 310 | { 311 | if (first_archive_file || rewind) 312 | { 313 | ErrorMsg (GetLastError (), L"Could not open file \"%s\".", current_rar_filename); 314 | return files; 315 | } 316 | else 317 | break; 318 | } 319 | rewind = false; 320 | 321 | // Read marker. 322 | if (!ReadFile (hFile, marker, 7, &dwBytesRead, NULL) || dwBytesRead != 7) 323 | { 324 | ErrorMsg (GetLastError (), L"Could not read RAR header."); 325 | return files; 326 | } 327 | 328 | if (memcmp (marker, expected, 7)) 329 | { 330 | ErrorMsg (0, L"Incorrect RAR marker."); 331 | return files; 332 | } 333 | 334 | // Read archive header. 335 | if (ReadHeader (hFile, &rh)) 336 | return files; 337 | 338 | LOG_HEADER(&rh); 339 | 340 | if (rh.ch.type != HEADER_TYPE_ARCHIVE) 341 | { 342 | ErrorMsg (0, L"Unexpected RAR header type."); 343 | return files; 344 | } 345 | 346 | if (rh.ch.flags & MHD_PASSWORD) 347 | { 348 | ErrorMsg (0, L"Encrypted RAR volumes are not supported."); 349 | return files; 350 | } 351 | 352 | if (first_archive_file) 353 | { 354 | new_numbering = !!(rh.ch.flags & MHD_NEWNUMBERING); 355 | multi_volume = !!(rh.ch.flags & MHD_VOLUME); 356 | 357 | if (multi_volume) 358 | { 359 | if (!rar_ext) 360 | { 361 | ErrorMsg (0, L"Input file does not end with .rar"); 362 | return files; 363 | } 364 | 365 | // Locate volume counter 366 | if (new_numbering) 367 | { 368 | volume_digits = 0; 369 | do 370 | { 371 | rar_ext --; 372 | volume_digits ++; 373 | } while (iswdigit (*(rar_ext - 1))); 374 | } 375 | else 376 | { 377 | rar_ext += 2; 378 | volume_digits = 2; 379 | } 380 | 381 | if (!(rh.ch.flags & MHD_FIRSTVOLUME)) 382 | { 383 | DbgLog((LOG_TRACE, 2, L"Rewinding to the first file in the set.")); 384 | UpdateArchiveName (rar_ext, volume_digits, volumes, new_numbering); 385 | 386 | first_archive_file = false; 387 | rewind = true; 388 | continue; 389 | } 390 | } 391 | } 392 | else 393 | { 394 | ASSERT (new_numbering == !!(rh.ch.flags & MHD_NEWNUMBERING)); 395 | ASSERT (rh.ch.flags & MHD_VOLUME); 396 | } 397 | 398 | // Find file headers 399 | while (true) 400 | { 401 | // Read file header. 402 | if (ret = ReadHeader (hFile, &rh)) 403 | { 404 | if (ret == ERROR_HANDLE_EOF) 405 | break; 406 | else 407 | return files; 408 | } 409 | 410 | LOG_HEADER(&rh); 411 | 412 | if (rh.ch.type == HEADER_TYPE_END) 413 | { 414 | // TODO: Verify that the volume number in the header matches our volume counter. 415 | 416 | // Check for EARC_NEXT_VOLUME removed as this flag is missing on some archives. 417 | 418 | break; 419 | } 420 | if (rh.ch.type != HEADER_TYPE_FILE) 421 | { 422 | SetFilePointerEx (hFile, rh.bytesRemaining, NULL, FILE_CURRENT); 423 | DbgLog((LOG_TRACE, 2, L"Skipping unknown header of type %02x.", rh.ch.type)); 424 | continue; 425 | } 426 | 427 | DbgLog((LOG_TRACE, 2, L"SIZE %08lx %08lx OS %02x CRC %08lx TIMESTAMP %08lx VERSION %d METHOD %02x LEN %04lx ATTRIB %08lx", 428 | rh.fh.size.HighPart, rh.fh.size.LowPart, rh.fh.os, rh.fh.crc, rh.fh.timestamp, rh.fh.version, rh.fh.method, rh.fh.name_len, rh.fh.attributes)); 429 | 430 | DbgLog((LOG_TRACE, 2, L"FILENAME \"%S\"", rh.fh.filename)); 431 | 432 | if ((rh.ch.flags & LHD_WINDOWMASK) == LHD_DIRECTORY) 433 | { 434 | DbgLog((LOG_TRACE, 2, L"Skipping directory.")); 435 | HEADER_SKIP_FILE 436 | } 437 | 438 | if (filename) 439 | { 440 | if (strcmp (filename, rh.fh.filename)) 441 | { 442 | // TODO: We should probably dump the old file start fresh with this one 443 | // since the lazy error handling at other places may cause us to end up here. 444 | DbgLog((LOG_TRACE, 2, L"Incorrect file found.")); 445 | HEADER_SKIP_FILE 446 | } 447 | 448 | if (!(rh.ch.flags & LHD_SPLIT_BEFORE)) 449 | { 450 | // TODO: Decide if it's better to ignore the missing flag. 451 | DbgLog((LOG_TRACE, 2, L"LHD_SPLIT_BEFORE flag was not set as expected.")); 452 | HEADER_SKIP_FILE 453 | } 454 | 455 | delete [] rh.fh.filename; 456 | } 457 | else 458 | { 459 | if (!multi_volume && rh.ch.flags & (LHD_SPLIT_BEFORE | LHD_SPLIT_AFTER)) 460 | { 461 | ErrorMsg (0, L"Split file in a single volume archive."); 462 | delete [] rh.fh.filename; 463 | return files; 464 | } 465 | 466 | if (rh.ch.flags & LHD_SPLIT_BEFORE) 467 | { 468 | if (first_archive_file) 469 | { 470 | // Some archives incorrectly have MHD_FIRSTVOLUME set on all files, attempt rewind. 471 | DbgLog((LOG_TRACE, 2, L"Rewinding to the first file in the set.")); 472 | UpdateArchiveName (rar_ext, volume_digits, volumes, new_numbering); 473 | 474 | rewind = true; 475 | 476 | delete [] rh.fh.filename; 477 | break; 478 | } 479 | else 480 | { 481 | // TODO: Decide if it's better to just abort the entire scanning process here. 482 | DbgLog((LOG_TRACE, 2, L"Not at the beginning of the file.")); 483 | HEADER_SKIP_FILE 484 | } 485 | } 486 | 487 | files ++; 488 | collected = 0; 489 | 490 | ASSERT (!file); 491 | 492 | file = new File (); 493 | 494 | if (!file) 495 | { 496 | ErrorMsg (0, L"Out of memory."); 497 | delete [] rh.fh.filename; 498 | return files; 499 | } 500 | 501 | file->media_type.SetType (&MEDIATYPE_Stream); 502 | file->media_type.SetSubtype (&MEDIASUBTYPE_NULL); 503 | file->filename = rh.fh.filename; 504 | file->size = rh.fh.size.QuadPart; 505 | filename = rh.fh.filename; 506 | 507 | if (rh.ch.flags & LHD_PASSWORD) 508 | { 509 | DbgLog((LOG_TRACE, 2, L"Encrypted files are not supported.")); 510 | file->unsupported = true; 511 | } 512 | 513 | if (rh.fh.method != 0x30) 514 | { 515 | DbgLog((LOG_TRACE, 2, L"Compressed files are not supported.")); 516 | file->unsupported = true; 517 | } 518 | } 519 | 520 | if (!file->unsupported) 521 | { 522 | new_part = new FilePart (); 523 | 524 | if (!new_part) 525 | { 526 | ErrorMsg (0, L"Out of memory."); 527 | return files; 528 | } 529 | 530 | // Is this the 1st part? 531 | if (!file->parts) 532 | { 533 | file->parts = 1; 534 | file->list = new_part; 535 | } 536 | else 537 | { 538 | file->parts ++; 539 | prev_part->next = new_part; 540 | } 541 | prev_part = new_part; 542 | 543 | SetFilePointerEx (hFile, zero, (LARGE_INTEGER*) &new_part->in_rar_offset, FILE_CURRENT); 544 | new_part->in_file_offset = collected; 545 | new_part->size = rh.bytesRemaining.QuadPart; 546 | 547 | new_part->file = CreateFile (current_rar_filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); 548 | if (new_part->file == INVALID_HANDLE_VALUE) 549 | { 550 | ErrorMsg (GetLastError (), L"Could not open file \"%s\".", current_rar_filename); 551 | return files; 552 | } 553 | } 554 | 555 | collected += rh.bytesRemaining.QuadPart; 556 | SetFilePointerEx (hFile, rh.bytesRemaining, NULL, FILE_CURRENT); 557 | 558 | // Is file complete? 559 | if (!(rh.ch.flags & LHD_SPLIT_AFTER)) 560 | { 561 | if (!file->unsupported && file->size != collected) 562 | DbgLog((LOG_TRACE, 2, L"The file is not the sum of it's parts. expected = %lld, actual = %lld", file->size, collected)); 563 | 564 | if (file->parts) 565 | { 566 | file->array = new FilePart [file->parts]; 567 | 568 | if (!file->array) 569 | { 570 | ErrorMsg (0, L"Out of memory."); 571 | return files; 572 | } 573 | 574 | FilePart *fp = file->list; 575 | file->list = NULL; 576 | for (int i = 0; i < file->parts; i ++) 577 | { 578 | FilePart *tmp; 579 | memcpy (file->array + i, fp, sizeof (FilePart)); 580 | tmp = fp; 581 | fp = fp->next; 582 | tmp->file = INVALID_HANDLE_VALUE; 583 | delete tmp; 584 | } 585 | } 586 | 587 | if (!file->unsupported) 588 | { 589 | if (!checkFileForMediaType (file, &mediaTypeList, &mType)) 590 | return files; // this means out of memory 591 | 592 | if (mType) 593 | { 594 | #ifdef _DEBUG 595 | LPOLESTR majorType, subType; 596 | StringFromCLSID (mType->majorType, &majorType); 597 | StringFromCLSID (mType->subType, &subType); 598 | DbgLog((LOG_TRACE, 2, L"Filetype detection determined:")); 599 | DbgLog((LOG_TRACE, 2, L" Major type: %s", majorType)); 600 | DbgLog((LOG_TRACE, 2, L" Subtype: %s", subType)); 601 | CoTaskMemFree (majorType); 602 | CoTaskMemFree (subType); 603 | #endif 604 | file->media_type.SetType (&mType->majorType); 605 | file->media_type.SetSubtype (&mType->subType); 606 | file->type_known = true; 607 | (*ok_files_found) ++; 608 | } 609 | } 610 | 611 | // TODO: Figure out if checking file extensions is necessary anymore. 612 | if (!file->type_known) 613 | { 614 | char *ext = strrchr (file->filename, '.'); 615 | 616 | if (ext) 617 | { 618 | ext ++; 619 | int i; 620 | 621 | for (i = 0; s_file_types [i].extension; i ++) 622 | { 623 | if (!_stricmp (ext, s_file_types [i].extension)) 624 | break; 625 | } 626 | 627 | if (s_file_types [i].extension) 628 | { 629 | file->media_type.SetSubtype (s_file_types [i].guid); 630 | file->type_known = true; 631 | if (!file->unsupported) 632 | (*ok_files_found) ++; 633 | } 634 | else 635 | { 636 | file->unsupported = true; 637 | DbgLog((LOG_TRACE, 2, L"Unknown file extension.")); 638 | } 639 | } 640 | else 641 | { 642 | file->unsupported = true; 643 | DbgLog((LOG_TRACE, 2, L"No file extension.")); 644 | } 645 | } 646 | 647 | if (filename != file->filename) 648 | delete filename; 649 | 650 | filename = NULL; 651 | 652 | file_list->InsertLast (file); 653 | file = NULL; 654 | } 655 | } 656 | 657 | first_archive_file = false; 658 | 659 | if (rewind) 660 | continue; 661 | 662 | if (!multi_volume) 663 | break; 664 | 665 | // Continue to the next volume. 666 | volumes ++; 667 | UpdateArchiveName (rar_ext, volume_digits, volumes, new_numbering); 668 | } 669 | 670 | if (file) 671 | { 672 | // TODO: Decide if we should allow playback of truncated files. 673 | ErrorMsg (0, L"Couldn't find all archive volumes."); 674 | } 675 | 676 | return files; 677 | } 678 | 679 | /* static */ 680 | INT_PTR CALLBACK CRARFileSource::DlgFileList (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) 681 | { 682 | int index; 683 | 684 | switch (uMsg) 685 | { 686 | case WM_INITDIALOG: 687 | { 688 | int len; 689 | List *file_list = (List *) lParam; 690 | File *file = file_list->First (); 691 | wchar_t *tempString; 692 | 693 | while (file) 694 | { 695 | if (!file->unsupported) 696 | { 697 | len = (int) strlen (file->filename) + 1; 698 | tempString = new wchar_t [len]; 699 | MultiByteToWideChar (CP_ACP, 0, file->filename, -1, tempString, len); 700 | index = ListBox_AddString (GetDlgItem (hwndDlg, IDC_FILELIST), tempString); 701 | ListBox_SetItemData (GetDlgItem (hwndDlg, IDC_FILELIST), index, file); 702 | delete [] tempString; 703 | } 704 | 705 | file = file_list->Next (file); 706 | } 707 | ListBox_SetCurSel (GetDlgItem (hwndDlg, IDC_FILELIST), 0); 708 | SetForegroundWindow (hwndDlg); 709 | return TRUE; 710 | } 711 | case WM_COMMAND: 712 | switch (LOWORD(wParam)) 713 | { 714 | case IDOK: 715 | index = ListBox_GetCurSel (GetDlgItem (hwndDlg, IDC_FILELIST)); 716 | EndDialog (hwndDlg, ListBox_GetItemData (GetDlgItem (hwndDlg, IDC_FILELIST), index)); 717 | return TRUE; 718 | 719 | case IDCANCEL: 720 | EndDialog (hwndDlg, NULL); 721 | return TRUE; 722 | 723 | case IDC_FILELIST: 724 | switch (HIWORD (wParam)) 725 | { 726 | case LBN_DBLCLK: 727 | index = ListBox_GetCurSel ((HWND) lParam); 728 | EndDialog (hwndDlg, ListBox_GetItemData ((HWND) lParam, index)); 729 | return TRUE; 730 | } 731 | } 732 | break; 733 | 734 | case WM_CLOSE: 735 | EndDialog (hwndDlg, NULL); 736 | return TRUE; 737 | } 738 | 739 | return FALSE; 740 | } 741 | 742 | // IFileSourceFilter methods 743 | 744 | STDMETHODIMP CRARFileSource::Load (LPCOLESTR lpwszFileName, const AM_MEDIA_TYPE *pmt) 745 | { 746 | List file_list; 747 | int num_files, num_ok_files; 748 | CAutoLock lck (&m_lock); 749 | 750 | if (!lpwszFileName) 751 | return E_POINTER; 752 | 753 | if (m_file) 754 | { 755 | DbgLog((LOG_TRACE, 2, L"CRARFileSource::Load called with file already loaded.")); 756 | return E_UNEXPECTED; 757 | } 758 | 759 | int cch = lstrlen (lpwszFileName) + 1; 760 | 761 | if (m_file_name) 762 | delete m_file_name; 763 | 764 | m_file_name = new WCHAR [cch]; 765 | if (!m_file_name) 766 | { 767 | ErrorMsg (0, L"Out of memory."); 768 | return E_OUTOFMEMORY; 769 | } 770 | 771 | CopyMemory (m_file_name, lpwszFileName, cch * sizeof (WCHAR)); 772 | 773 | num_files = ScanArchive ((wchar_t *) lpwszFileName, &file_list, &num_ok_files); 774 | 775 | DbgLog((LOG_TRACE, 2, L"Found %d files out of which %d are media files.", num_files, num_ok_files)); 776 | 777 | if (!num_ok_files) 778 | { 779 | ErrorMsg (0, L"No media files found in the archive."); 780 | return E_UNEXPECTED; // TODO: Figure out a better error code. 781 | } 782 | 783 | if (num_ok_files == 1) 784 | { 785 | m_file = file_list.First (); 786 | 787 | while (m_file->unsupported) 788 | m_file = file_list.Next (m_file); 789 | } 790 | else 791 | { 792 | m_file = (File *) DialogBoxParam (g_hInst, MAKEINTRESOURCE(IDD_FILELIST), 0, DlgFileList, (LPARAM) &file_list); 793 | 794 | if (!m_file) 795 | return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); 796 | } 797 | 798 | if (pmt) 799 | m_file->media_type = *pmt; 800 | 801 | m_file->Unlink (); 802 | m_pin.SetFile (m_file); 803 | 804 | file_list.Clear (); 805 | 806 | return S_OK; 807 | } 808 | 809 | // Behaves like IPersistFile::Load 810 | STDMETHODIMP CRARFileSource::GetCurFile (LPOLESTR *ppszFileName, AM_MEDIA_TYPE *pmt) 811 | { 812 | if (!ppszFileName) 813 | return E_POINTER; 814 | 815 | if (m_file_name != NULL) 816 | { 817 | DWORD n = sizeof (WCHAR) * (lstrlen (m_file_name) + 1); 818 | 819 | *ppszFileName = (LPOLESTR) CoTaskMemAlloc (n); 820 | 821 | if (*ppszFileName != NULL) 822 | CopyMemory (*ppszFileName, m_file_name, n); 823 | else 824 | return E_OUTOFMEMORY; 825 | } 826 | else 827 | *ppszFileName = NULL; 828 | 829 | if (pmt != NULL) 830 | CopyMediaType (pmt, &m_file->media_type); 831 | 832 | return NOERROR; 833 | } 834 | -------------------------------------------------------------------------------- /RFS.def: -------------------------------------------------------------------------------- 1 | LIBRARY RARFileSource.ax 2 | EXPORTS 3 | DllMain PRIVATE 4 | DllGetClassObject PRIVATE 5 | DllCanUnloadNow PRIVATE 6 | DllRegisterServer PRIVATE 7 | DllUnregisterServer PRIVATE 8 | -------------------------------------------------------------------------------- /RFS.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008-2012, OctaneSnail 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef RFS_H 19 | #define RFS_H 20 | 21 | #include "OutputPin.h" 22 | 23 | typedef struct 24 | { 25 | const char *extension; 26 | const GUID *guid; 27 | } file_type_t; 28 | 29 | class CRARFileSource : 30 | public CBaseFilter, 31 | public IFileSourceFilter 32 | { 33 | public: 34 | DECLARE_IUNKNOWN; 35 | 36 | static CUnknown * WINAPI CreateInstance (LPUNKNOWN punk, HRESULT *phr); 37 | 38 | // Reveals IFileSourceFilter 39 | STDMETHODIMP NonDelegatingQueryInterface (REFIID riid, void **ppv); 40 | 41 | // CBaseFilter 42 | int GetPinCount () { return 1; } 43 | CBasePin *GetPin (int n) { return n == 0 ? &m_pin : NULL; } 44 | 45 | // IFileSourceFilter interface 46 | STDMETHODIMP Load (LPCOLESTR lpwszFileName, const AM_MEDIA_TYPE *pmt); 47 | STDMETHODIMP GetCurFile (LPOLESTR *ppszFileName, AM_MEDIA_TYPE *pmt); 48 | 49 | private: 50 | CRARFileSource (LPUNKNOWN punk, HRESULT *phr); 51 | ~CRARFileSource (); 52 | 53 | static void UpdateArchiveName (wchar_t *ext, size_t len, int volume, bool new_numbering); 54 | int ScanArchive (wchar_t *archive_name, List *file_list, int *known_files_found); 55 | static INT_PTR CALLBACK DlgFileList (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); 56 | 57 | CRFSOutputPin m_pin; 58 | CCritSec m_lock; 59 | LPWSTR m_file_name; 60 | File *m_file; 61 | 62 | static file_type_t s_file_types []; 63 | }; 64 | 65 | #endif // RFS_H 66 | -------------------------------------------------------------------------------- /RFS.nsi: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008-2012, OctaneSnail 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | !include MUI2.nsh 19 | !include Library.nsh 20 | !include x64.nsh 21 | 22 | !define VERSION "0.9.3" 23 | 24 | Name "RAR File Source" 25 | OutFile "RARFileSource-v${VERSION}.exe" 26 | 27 | !define REGKEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\RARFileSource" 28 | 29 | InstallDirRegKey HKLM ${REGKEY} "InstallLocation" 30 | 31 | RequestExecutionLevel admin 32 | 33 | !insertmacro MUI_PAGE_WELCOME 34 | 35 | !define MUI_PAGE_CUSTOMFUNCTION_PRE ComponentsPre 36 | !define MUI_PAGE_CUSTOMFUNCTION_LEAVE ComponentsLeave 37 | !insertmacro MUI_PAGE_COMPONENTS 38 | 39 | !insertmacro MUI_PAGE_DIRECTORY 40 | !insertmacro MUI_PAGE_INSTFILES 41 | !insertmacro MUI_PAGE_FINISH 42 | 43 | !insertmacro MUI_UNPAGE_CONFIRM 44 | !insertmacro MUI_UNPAGE_INSTFILES 45 | !insertmacro MUI_UNPAGE_FINISH 46 | 47 | !insertmacro MUI_LANGUAGE "English" 48 | 49 | !define LIBRARY_IGNORE_VERSION 50 | 51 | !macro checkRedist TARGET 52 | SetRegView 32 53 | checkInstalled: 54 | ReadRegDWORD $0 HKLM "Software\Microsoft\VisualStudio\10.0\VC\VCRedist\${TARGET}" "Installed" 55 | IntCmp $0 1 redistInstalled 56 | ReadRegDWORD $0 HKLM "Software\Microsoft\VisualStudio\10.0\VC\Runtimes\${TARGET}" "Installed" 57 | IntCmp $0 1 redistInstalled 58 | MessageBox MB_ABORTRETRYIGNORE "The Microsoft Visual C++ 2010 Redistributable Package (${TARGET}) is not installed.$\nWithout the necessary runtime DLLs the filter will not work.$\n$\nFind it at http://www.microsoft.com/downloads/ and try again." IDIGNORE redistInstalled IDRETRY checkInstalled 59 | Quit 60 | redistInstalled: 61 | !macroend 62 | 63 | Section "Install 32-bit filter" SEC_X86 64 | !insertmacro checkRedist x86 65 | SetOutPath "$INSTDIR" 66 | !insertmacro InstallLib REGDLL NOTSHARED REBOOT_NOTPROTECTED "Release\RARFileSource.ax" "$INSTDIR\RARFileSource.ax" "$INSTDIR" 67 | SectionEnd 68 | 69 | Section "Install 64-bit filter" SEC_X64 70 | !insertmacro checkRedist x64 71 | SetOutPath "$INSTDIR\x64" 72 | !define LIBRARY_X64 73 | !insertmacro InstallLib REGDLL NOTSHARED REBOOT_NOTPROTECTED "x64\Release\RARFileSource.ax" "$INSTDIR\x64\RARFileSource.ax" "$INSTDIR\x64" 74 | SectionEnd 75 | 76 | Section "-Uninstaller" 77 | SetRegView 32 78 | SetOutPath "$INSTDIR" 79 | WriteUninstaller "$INSTDIR\Uninstall.exe" 80 | WriteRegStr HKLM ${REGKEY} "DisplayName" "RAR File Source" 81 | WriteRegStr HKLM ${REGKEY} "DisplayVersion" "${VERSION}" 82 | WriteRegStr HKLM ${REGKEY} "HelpLink" "http://www.v12pwr.com/RARFileSource/" 83 | WriteRegStr HKLM ${REGKEY} "InstallLocation" "$INSTDIR" 84 | WriteRegStr HKLM ${REGKEY} "Publisher" "OctaneSnail" 85 | WriteRegStr HKLM ${REGKEY} "UninstallString" "$INSTDIR\Uninstall.exe" 86 | WriteRegStr HKLM ${REGKEY} "URLInfoAbout" "http://www.v12pwr.com/RARFileSource/" 87 | WriteRegDWORD HKLM ${REGKEY} "NoModify" 1 88 | WriteRegDWORD HKLM ${REGKEY} "NoRepair" 1 89 | SectionEnd 90 | 91 | Function ComponentsPre 92 | ${IfNot} ${RunningX64} 93 | !insertmacro UnselectSection ${SEC_X64} 94 | StrCpy $INSTDIR "$PROGRAMFILES\RARFileSource" 95 | Abort 96 | ${EndIf} 97 | FunctionEnd 98 | 99 | Function ComponentsLeave 100 | !insertmacro SectionFlagIsSet ${SEC_X86} ${SF_SELECTED} ok_x86 check_x64 101 | 102 | ok_x86: 103 | StrCpy $INSTDIR "$PROGRAMFILES\RARFileSource" 104 | Goto end 105 | 106 | check_x64: 107 | !insertmacro SectionFlagIsSet ${SEC_X64} ${SF_SELECTED} ok_x64 abort 108 | 109 | ok_x64: 110 | StrCpy $INSTDIR "$PROGRAMFILES64\RARFileSource" 111 | Goto end 112 | 113 | abort: 114 | MessageBox MB_OK|MB_ICONEXCLAMATION "You must select at least one component." 115 | Abort 116 | 117 | end: 118 | FunctionEnd 119 | 120 | Section "Uninstall" 121 | !undef LIBRARY_X64 122 | !insertmacro UnInstallLib REGDLL NOTSHARED REBOOT_NOTPROTECTED "$INSTDIR\RARFileSource.ax" 123 | !define LIBRARY_X64 124 | !insertmacro UnInstallLib REGDLL NOTSHARED REBOOT_NOTPROTECTED "$INSTDIR\x64\RARFileSource.ax" 125 | Delete "$INSTDIR\Uninstall.exe" 126 | RMDir "$INSTDIR\x64" 127 | RMDir "$INSTDIR" 128 | SetRegView 32 129 | DeleteRegKey HKLM ${REGKEY} 130 | SectionEnd 131 | -------------------------------------------------------------------------------- /RFS.rc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "resource.h" 4 | 5 | ///////////////////////////////////////////////////////////////////////////// 6 | // 7 | // Version 8 | // 9 | 10 | VS_VERSION_INFO VERSIONINFO 11 | FILEVERSION 0,9,3,0 12 | PRODUCTVERSION 0,9,3,0 13 | FILEFLAGSMASK 0x30003fL 14 | #ifdef _DEBUG 15 | FILEFLAGS VS_FF_DEBUG 16 | #else 17 | FILEFLAGS 0x0L 18 | #endif 19 | FILEOS VOS_NT 20 | FILETYPE VFT_DLL 21 | FILESUBTYPE 0x0L 22 | BEGIN 23 | BLOCK "StringFileInfo" 24 | BEGIN 25 | BLOCK "040904E4" 26 | BEGIN 27 | VALUE "CompanyName", "OctaneSnail\0" 28 | VALUE "FileDescription", "RAR File Source DirectShow Filter\0" 29 | VALUE "FileVersion", "0.9.3\0" 30 | VALUE "InternalName", "RARFileSource\0" 31 | VALUE "LegalCopyright", "(C) 2008-2012, OctaneSnail" 32 | VALUE "OriginalFilename", "RARFileSource.ax\0" 33 | VALUE "ProductName", "RAR File Source\0" 34 | VALUE "ProductVersion", "0.9.3\0" 35 | VALUE "ActiveMovie", "Filter dll\0" 36 | VALUE "OLESelfRegister", "AM20\0" 37 | END 38 | END 39 | BLOCK "VarFileInfo" 40 | BEGIN 41 | VALUE "Translation", 0x409, 1252 42 | END 43 | END 44 | 45 | ///////////////////////////////////////////////////////////////////////////// 46 | // 47 | // Dialog 48 | // 49 | 50 | IDD_FILELIST DIALOGEX 0, 0, 316, 115 51 | STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU 52 | CAPTION "File Selection" 53 | FONT 8, "MS Shell Dlg", 400, 0, 0x1 54 | BEGIN 55 | DEFPUSHBUTTON "Select",IDOK,204,94,50,14 56 | PUSHBUTTON "Cancel",IDCANCEL,259,94,50,14 57 | LISTBOX IDC_FILELIST,7,7,302,84,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP 58 | END 59 | -------------------------------------------------------------------------------- /Utils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008-2012, OctaneSnail 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "Utils.h" 23 | 24 | void ErrorMsg (DWORD errorCode, wchar_t *format, ...) 25 | { 26 | wchar_t buffer [1024]; 27 | wchar_t *end; 28 | size_t remaining; 29 | va_list argptr; 30 | 31 | // __asm int 3; 32 | 33 | va_start (argptr, format); 34 | StringCchVPrintfEx (buffer, 1024, &end, &remaining, 0, format, argptr); 35 | va_end (argptr); 36 | 37 | if (errorCode && remaining > 9) 38 | { 39 | wcscpy (end, L"\n\nError: "); 40 | end += 9; 41 | remaining -= 9; 42 | 43 | FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 44 | NULL, errorCode, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), end, (DWORD) remaining, NULL); 45 | } 46 | 47 | DbgLog((LOG_ERROR, 0, L"%s", buffer)); 48 | MessageBox (NULL, buffer, L"RAR File Source", MB_OK | MB_ICONERROR); 49 | } 50 | 51 | #ifdef _DEBUG 52 | 53 | static wchar_t *mhd_flags [] = 54 | { 55 | L"MHD_VOLUME", 56 | L"MHD_COMMENT", 57 | L"MHD_LOCK", 58 | L"MHD_SOLID", 59 | L"MHD_NEWNUMBERING", 60 | L"MHD_AV", 61 | L"MHD_PROTECT", 62 | L"MHD_PASSWORD", 63 | L"MHD_FIRSTVOLUME", 64 | L"MHD_ENCRYPTVER" 65 | }; 66 | 67 | static wchar_t *lhd_flags1 [] = 68 | { 69 | L"LHD_SPLIT_BEFORE", 70 | L"LHD_SPLIT_AFTER", 71 | L"LHD_PASSWORD", 72 | L"LHD_COMMENT", 73 | L"LHD_SOLID" 74 | }; 75 | 76 | static wchar_t *lhd_flags2 [] = 77 | { 78 | L"LHD_LARGE", 79 | L"LHD_UNICODE", 80 | L"LHD_SALT", 81 | L"LHD_VERSION", 82 | L"LHD_EXTTIME", 83 | L"LHD_EXTFLAGS" 84 | }; 85 | 86 | static wchar_t *earc_flags [] = 87 | { 88 | L"EARC_NEXT_VOLUME", 89 | L"EARC_DATACRC", 90 | L"EARC_REVSPACE", 91 | L"EARC_VOLNUMBER" 92 | }; 93 | 94 | void LogHeader (rar_header_t *rh) 95 | { 96 | int i; 97 | WORD flags = rh->ch.flags; 98 | 99 | DbgLog((LOG_TRACE, 2, L"Header CRC %04hx TYPE %02x FLAGS %04hx SIZE %08lx %08lx", 100 | rh->ch.crc, rh->ch.type, rh->ch.flags, rh->ch.size.HighPart, rh->ch.size.LowPart)); 101 | 102 | switch (rh->ch.type) 103 | { 104 | case HEADER_TYPE_MARKER: 105 | DbgLog((LOG_TRACE, 2, L" HEADER_TYPE_MARKER")); 106 | break; 107 | 108 | case HEADER_TYPE_ARCHIVE: 109 | DbgLog((LOG_TRACE, 2, L" HEADER_TYPE_ARCHIVE")); 110 | 111 | for (i = 0; i < 10; i ++) 112 | { 113 | if (flags & 1) 114 | DbgLog((LOG_TRACE, 2, L" %s", mhd_flags [i])); 115 | 116 | flags >>= 1; 117 | } 118 | break; 119 | 120 | case HEADER_TYPE_FILE: 121 | DbgLog((LOG_TRACE, 2, L" HEADER_TYPE_FILE")); 122 | 123 | for (i = 0; i < 5; i ++) 124 | { 125 | if (flags & 1) 126 | DbgLog((LOG_TRACE, 2, L" %s", lhd_flags1 [i])); 127 | 128 | flags >>= 1; 129 | } 130 | 131 | flags >>= 3; 132 | 133 | for (i = 0; i < 6; i ++) 134 | { 135 | if (flags & 1) 136 | DbgLog((LOG_TRACE, 2, L" %s", lhd_flags2 [i])); 137 | 138 | flags >>= 1; 139 | } 140 | break; 141 | 142 | case HEADER_TYPE_SUBBLOCK: 143 | DbgLog((LOG_TRACE, 2, L" HEADER_TYPE_SUBBLOCK")); 144 | break; 145 | 146 | case HEADER_TYPE_RECOVERY: 147 | DbgLog((LOG_TRACE, 2, L" HEADER_TYPE_RECOVERY")); 148 | break; 149 | 150 | case HEADER_TYPE_NEWSUBLOCK: 151 | DbgLog((LOG_TRACE, 2, L" HEADER_TYPE_NEWSUBLOCK")); 152 | break; 153 | 154 | case HEADER_TYPE_END: 155 | DbgLog((LOG_TRACE, 2, L" HEADER_TYPE_END")); 156 | 157 | for (i = 0; i < 4; i ++) 158 | { 159 | if (flags & 1) 160 | DbgLog((LOG_TRACE, 2, L" %s", earc_flags [i])); 161 | 162 | flags >>= 1; 163 | } 164 | break; 165 | 166 | default: 167 | DbgLog((LOG_TRACE, 2, L" HEADER_TYPE_UNKNOWN")); 168 | } 169 | 170 | if (rh->ch.flags & SKIP_IF_UNKNOWN) 171 | DbgLog((LOG_TRACE, 2, L" SKIP_IF_UNKNOWN")); 172 | 173 | if (rh->ch.flags & LONG_BLOCK) 174 | DbgLog((LOG_TRACE, 2, L" LONG_BLOCK")); 175 | } 176 | 177 | #endif // _DEBUG 178 | -------------------------------------------------------------------------------- /Utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008-2012, OctaneSnail 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef UTILS_H 19 | #define UTILS_H 20 | 21 | #include 22 | 23 | void ErrorMsg (DWORD errorCode, wchar_t *format, ...); 24 | 25 | #ifdef _DEBUG 26 | #include "RAR.h" 27 | 28 | void LogHeader (rar_header_t *rh); 29 | #define LOG_HEADER(rh) LogHeader(rh) 30 | #else 31 | #define LOG_HEADER(rh) 32 | #endif 33 | 34 | #endif // UTILS_H 35 | -------------------------------------------------------------------------------- /resource.h: -------------------------------------------------------------------------------- 1 | 2 | #define IDOK 1 3 | #define IDCANCEL 2 4 | #define IDC_FILELIST 1000 5 | #define IDD_FILELIST 2000 6 | --------------------------------------------------------------------------------