1 /***************************************************************************
2 * Copyright (C) 2006-2008 Kent Gustavsson <nedo80@gmail.com>
3 ****************************************************************************/
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.
24 // Created by: Kent Gustavsson <nedo80@gmail.com>
25 // Created on: Sun Mar 5 00:40:27 2006
28 #include "rararchive.h"
31 #include <sys/types.h>
38 RARArchive::RARArchive()
44 RARArchive::~RARArchive()
46 std::vector
<std::ifstream
*>::iterator iter
;
48 for( iter
= streams
.begin() ; iter
!= streams
.end() ; iter
++)
55 RARArchive::Init(std::string filename
)
58 stat(filename
.c_str(), &st
);
59 default_date
= st
.st_mtime
;
62 this->filename
= filename
;
66 std::string numprefix
;
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" */
85 offset
= voldigits
+volsuffix
.size();
86 if ( offset
>= filename
.size() ||
87 !isdigit(filename
[filename
.size()-offset
-1]))
95 std::cerr
<< "Too many digits in volume number" <<
101 offset
= numprefix
.size() + voldigits
+ volsuffix
.size();
102 if ( offset
<= filename
.size() && filename
.substr(
103 filename
.size() - offset
, numprefix
.size()) == numprefix
)
105 offset
= volsuffix
.size()+voldigits
;
106 volprefix
= filename
.substr(0, filename
.size()-offset
);
107 firstfile
= atoi( filename
.substr(
108 filename
.size()-offset
, voldigits
).c_str() );
117 RARArchive::GetFileName(int n
)
124 if ( voldigits
== 0 )
126 /* n=0 => .rar (see above), n=1 => .r00, n=2 => .r01, etc */
128 f
<< filename
.substr(0,filename
.size()-2) << 0 << n
-1;
130 f
<< filename
.substr(0,filename
.size()-2) << n
-1;
151 RARArchive::HasFile(std::string f
)
153 if( fileblocks
.find(f
) == fileblocks
.end() )
160 RARArchive::HasFolder(std::string f
)
162 if( folderblocks
.find(f
) == folderblocks
.end() )
167 unsigned long long int
168 RARArchive::GetFileSize(std::string file
)
170 unsigned long long int size
= 0;
171 if( fileblocks
.find(file
) == fileblocks
.end() )
174 std::vector
<FileBlock
*>::iterator i
;
175 for(i
= fileblocks
[file
].begin() ; i
!= fileblocks
[file
].end() ; i
++ )
177 size
+= (*i
)->GetDataSize();
184 RARArchive::Parse(bool showcompressed
)
189 std::ifstream
*file
= new std::ifstream(GetFileName(n
++).c_str());
192 streams
.push_back(file
);
201 //for some rar files there are seeks past file end, then directly to file end
202 //which makes file->good() return true, but there is nothing to read
203 //so with file->gcount() we check if we actually read something
204 //otherwise we use old bufer and crash somewhere
205 if(file
->gcount()==0)
208 file
->seekg (-3, std::ios::cur
);
215 blocks
.push_back( new MarkerBlock(*file
) );
218 blocks
.push_back( new ArchiveBlock(*file
) );
222 f
= new FileBlock(*file
);
224 if ( showcompressed
|| !f
->isCompressed() )
227 folderblocks
[f
->GetFileName()].push_back(f
);
230 fileblocks
[f
->GetFileName()].push_back(f
);
232 for ( int pos
= 0 ; ( pos
= f
->GetFileName().find("\\", pos
) ) != std::string::npos
; pos
++)
234 if( folderblocks
.find(f
->GetFileName().substr(0,pos
)) == folderblocks
.end())
235 folderblocks
[f
->GetFileName().substr(0,pos
)].push_back(NULL
);
240 blocks
.push_back( f
);
244 blocks
.push_back( new RARBlock(*file
) );
247 if ( buf
[2] == 0 || buf
[2] == 0x7B || buf
[2] == 0x78 )
260 RARArchive::Read(const char *path
, char *buf
, size_t size
, off_t offset
)
262 unsigned int pos
= 0;
263 if ( fileblocks
.find(path
) == fileblocks
.end() )
267 std::vector
<FileBlock
*>::iterator i
;
268 for(i
= fileblocks
[path
].begin() ; i
!= fileblocks
[path
].end() ; i
++ )
270 if ( (*i
)->GetDataSize() > offset
)
272 unsigned int len
= (*i
)->GetData(buf
+ pos
, offset
, size
);
279 offset
-= (*i
)->GetDataSize();
285 std::vector
< std::string
>
286 RARArchive::GetFolders()
288 std::vector
<std::string
> retdata
;
290 std::map
<std::string
, std::vector
<FileBlock
*> >::iterator iter
;
292 for( iter
= folderblocks
.begin() ; iter
!= folderblocks
.end() ; iter
++)
293 retdata
.push_back(iter
->first
);
299 std::vector
< std::string
>
300 RARArchive::GetFiles()
302 std::vector
<std::string
> retdata
;
303 std::map
<std::string
, std::vector
<FileBlock
* > >::iterator iter
;
305 for( iter
= fileblocks
.begin() ; iter
!= fileblocks
.end() ; iter
++)
307 retdata
.push_back(iter
->first
);
314 RARArchive::PrintFiles()
318 std::map
<std::string
, std::vector
<FileBlock
* > >::iterator iter
;
320 for( iter
= fileblocks
.begin() ; iter
!= fileblocks
.end() ; iter
++)
322 unsigned long long int s
= 0;
323 std::vector
<FileBlock
*>::iterator i
;
324 for(i
= iter
->second
.begin() ; i
!= iter
->second
.end() ; i
++ )
326 s
+= (*i
)->GetDataSize();
329 std::cout
<< iter
->first
<< " blocks: " << iter
->second
.size() << " size: " << s
<< std::endl
;
334 RARArchive::GetDate(std::string file
, struct timespec
* tp
)
336 if( fileblocks
.find(file
) == fileblocks
.end() )
338 tp
->tv_sec
= default_date
;
343 std::vector
<FileBlock
*>::iterator i
;
344 i
= fileblocks
[file
].begin();
345 (*i
)->GetFileDate(tp
);
349 RARArchive::PrintFolders()
351 std::map
<std::string
, std::vector
<FileBlock
* > >::iterator iter
;
353 for( iter
= folderblocks
.begin() ; iter
!= folderblocks
.end() ; iter
++)
355 unsigned long long int s
= 0;
356 std::vector
<FileBlock
*>::iterator i
;
357 for(i
= iter
->second
.begin() ; i
!= iter
->second
.end() ; i
++ )
358 s
+= (*i
)->GetDataSize();
360 std::cout
<< iter
->first
<< " blocks: " << iter
->second
.size() << " size: " << s
<< std::endl
;