Hook version command-line option
[rarfs.git] / src / rararchive.cc
blob905e326c3ed98355d8afa40da533ce95d13b06af
1 /***************************************************************************
2 * Copyright (C) 2006-2008 Kent Gustavsson <nedo80@gmail.com>
3 ****************************************************************************/
4 /*
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 // Class: RARArchive
24 // Created by: Kent Gustavsson <nedo80@gmail.com>
25 // Created on: Sun Mar 5 00:40:27 2006
28 #include "rararchive.h"
29 #include <fstream>
30 #include <sstream>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <unistd.h>
34 #include <stdlib.h>
35 #include <cstdlib>
36 #include <time.h>
38 RARArchive::RARArchive()
40 default_date = 0;
44 RARArchive::~RARArchive()
46 std::vector <std::ifstream*>::iterator iter;
48 for( iter = streams.begin() ; iter != streams.end() ; iter++)
50 (*iter)->close();
54 int
55 RARArchive::Init(std::string filename)
57 struct stat st;
58 stat(filename.c_str(), &st);
59 default_date = st.st_mtime;
61 // Hate this part
62 this->filename = filename;
64 volsuffix = ".rar";
65 voldigits = 0;
66 std::string numprefix;
67 std::size_t offset;
69 offset = volsuffix.size();
70 if ( offset <= filename.size() &&
71 filename.substr(filename.size()-offset) == volsuffix )
73 /* Ends in ".rar"; check for "part<N>.rar" */
74 numprefix = "part";
76 else
78 /* Try ".<N>" */
79 volsuffix = "";
80 numprefix = ".";
83 while(true)
85 offset = voldigits+volsuffix.size();
86 if ( offset >= filename.size() ||
87 !isdigit(filename[filename.size()-offset-1]))
89 break;
92 voldigits++;
93 if ( voldigits > 5 )
94 return false;
97 offset = numprefix.size() + voldigits + volsuffix.size();
98 if ( offset <= filename.size() && filename.substr(
99 filename.size() - offset, numprefix.size()) == numprefix )
101 offset = volsuffix.size()+voldigits;
102 volprefix = filename.substr(0, filename.size()-offset);
103 firstfile = atoi( filename.substr(
104 filename.size()-offset, voldigits).c_str() );
106 else
107 voldigits = 0;
109 return true;
112 std::string
113 RARArchive::GetFileName(int n)
115 if ( n == 0 )
116 return filename;
118 std::stringstream f;
120 if ( voldigits == 0 )
122 /* n=0 => .rar (see above), n=1 => .r00, n=2 => .r01, etc */
123 if( n-1 < 10 )
124 f << filename.substr(0,filename.size()-2) << 0 << n-1;
125 else
126 f << filename.substr(0,filename.size()-2) << n-1;
128 else
130 char prev;
132 f << volprefix;
134 prev = f.fill ('0');
135 f.width (voldigits);
136 f << n + firstfile;
137 f.fill(prev);
138 f.width(0);
140 f << volsuffix;
143 return f.str();
146 bool
147 RARArchive::HasFile(std::string f)
149 if( fileblocks.find(f) == fileblocks.end() )
150 return false;
151 return true;
155 bool
156 RARArchive::HasFolder(std::string f)
158 if( folderblocks.find(f) == folderblocks.end() )
159 return false;
160 return true;
163 unsigned long long int
164 RARArchive::GetFileSize(std::string file)
166 unsigned long long int size = 0;
167 if( fileblocks.find(file) == fileblocks.end() )
168 return 0;
170 std::vector <FileBlock *>::iterator i;
171 for(i = fileblocks[file].begin() ; i != fileblocks[file].end() ; i++ )
173 size += (*i)->GetDataSize();
176 return size;
179 void
180 RARArchive::Parse(bool showcompressed)
182 int n = 0;
183 for(;;)
185 std::ifstream *file = new std::ifstream(GetFileName(n++).c_str());
186 if(!file->good())
187 return;
188 streams.push_back(file);
190 for(;;)
192 if(!file->good())
193 break;
195 char buf[4];
196 file->read(buf,3);
197 //for some rar files there are seeks past file end, then directly to file end
198 //which makes file->good() return true, but there is nothing to read
199 //so with file->gcount() we check if we actually read something
200 //otherwise we use old bufer and crash somewhere
201 if(file->gcount()==0)
202 break;
204 file->seekg (-3, std::ios::cur);
206 switch( buf[2] )
208 case 0x00:
209 break;
210 case 0x72:
211 blocks.push_back( new MarkerBlock(*file) );
212 break;
213 case 0x73:
214 blocks.push_back( new ArchiveBlock(*file) );
215 break;
216 case 0x74:
217 FileBlock *f;
218 f = new FileBlock(*file);
220 if ( showcompressed || !f->isCompressed() )
222 if ( f->isFolder() )
223 folderblocks[f->GetFileName()].push_back(f);
224 else
226 fileblocks[f->GetFileName()].push_back(f);
228 for ( int pos = 0 ; ( pos = f->GetFileName().find("\\", pos) ) != std::string::npos ; pos++)
230 if( folderblocks.find(f->GetFileName().substr(0,pos)) == folderblocks.end())
231 folderblocks[f->GetFileName().substr(0,pos)].push_back(NULL);
236 blocks.push_back( f );
238 break;
239 default:
240 blocks.push_back( new RARBlock(*file) );
243 if ( buf[2] == 0 || buf[2] == 0x7B || buf[2] == 0x78 )
246 break;
249 file->clear();
250 file->seekg(0);
255 unsigned int
256 RARArchive::Read(const char *path, char *buf, size_t size, off_t offset)
258 unsigned int pos = 0;
259 if ( fileblocks.find(path) == fileblocks.end() )
260 // return -ENOENT;
261 return -1;
263 std::vector <FileBlock *>::iterator i;
264 for(i = fileblocks[path].begin() ; i != fileblocks[path].end() ; i++ )
266 if ( (*i)->GetDataSize() > offset )
268 unsigned int len = (*i)->GetData(buf + pos, offset, size);
269 pos += len;
270 size -= len;
271 offset = 0;
273 else
275 offset -= (*i)->GetDataSize();
278 return pos;
281 std::vector < std::string >
282 RARArchive::GetFolders()
284 std::vector <std::string> retdata;
286 std::map<std::string, std::vector <FileBlock *> >::iterator iter;
288 for( iter = folderblocks.begin() ; iter != folderblocks.end() ; iter++)
289 retdata.push_back(iter->first);
292 return retdata;
295 std::vector < std::string >
296 RARArchive::GetFiles()
298 std::vector <std::string> retdata;
299 std::map<std::string, std::vector <FileBlock * > >::iterator iter;
301 for( iter = fileblocks.begin() ; iter != fileblocks.end() ; iter++)
303 retdata.push_back(iter->first);
306 return retdata;
309 void
310 RARArchive::PrintFiles()
314 std::map<std::string, std::vector <FileBlock * > >::iterator iter;
316 for( iter = fileblocks.begin() ; iter != fileblocks.end() ; iter++)
318 unsigned long long int s = 0;
319 std::vector <FileBlock *>::iterator i;
320 for(i = iter->second.begin() ; i != iter->second.end() ; i++ )
322 s += (*i)->GetDataSize();
325 std::cout << iter->first << " blocks: " << iter->second.size() << " size: " << s << std::endl;
329 void
330 RARArchive::GetDate(std::string file, struct timespec* tp)
332 if( fileblocks.find(file) == fileblocks.end() )
334 tp->tv_sec = default_date;
335 tp->tv_nsec = 0;
336 return;
339 std::vector <FileBlock *>::iterator i;
340 i = fileblocks[file].begin();
341 (*i)->GetFileDate(tp);
344 void
345 RARArchive::PrintFolders()
347 std::map<std::string, std::vector <FileBlock * > >::iterator iter;
349 for( iter = folderblocks.begin() ; iter != folderblocks.end() ; iter++)
351 unsigned long long int s = 0;
352 std::vector <FileBlock *>::iterator i;
353 for(i = iter->second.begin() ; i != iter->second.end() ; i++ )
354 s += (*i)->GetDataSize();
356 std::cout << iter->first << " blocks: " << iter->second.size() << " size: " << s << std::endl;