Encapsulate “rarfile” parameter in “Opt” class
[rarfs.git] / src / fileblock.cc
blob4d16e65087acf396027f8ba3d2a8f3877741a7d4
1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU Library General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 // Class: FileBlock
21 // Created by: Kent Gustavsson <nedo80@gmail.com>
22 // Created on: Mon Mar 6 21:41:03 2006
25 #include "fileblock.h"
26 #include <time.h>
27 #include <ios>
28 #include <cstdlib>
30 /* MS-DOS time/date conversion routines derived from: */
33 * linux/fs/msdos/misc.c
35 * Written 1992,1993 by Werner Almesberger
38 /* Convert a MS-DOS time/date pair (unspecified local time zones) to a UNIX
39 time_t. */
41 time_t date_dos2unix(unsigned short time,unsigned short date)
43 struct tm tm;
44 tm.tm_year = 1980 + (date >> 9) - 1900,
45 tm.tm_mon = ((date >> 5) & 15) - 1,
46 tm.tm_mday = date & 31,
47 tm.tm_hour = time >> 11,
48 tm.tm_min = (time >> 5) & 63,
49 tm.tm_sec = (time & 31)*2,
50 tm.tm_isdst = -1; /* unknown; mktime will guess */
51 return mktime(&tm);
54 FileBlock::FileBlock(std::istream &in) : RARBlock(in),
55 in(in)
57 unsigned int end = in.tellg();
58 start = end - size - headsize;
60 in.seekg(end + 20-size-headsize);
61 unsigned short time;
62 unsigned short date;
63 time = in.get();
64 time += in.get() *256;
65 date = in.get();
66 date += in.get() *256;
67 filedate.tv_sec=date_dos2unix(time,date);
69 in.seekg(end + 25-size-headsize);
71 if ( in.get() == 48 )
72 compressed = false;
73 else
74 compressed = true;
76 unsigned int filenamesize = in.get();
77 filenamesize += in.get() * 256;
79 in.seekg(4, std::ios::cur);
80 char m[filenamesize+1];
82 if( flags & 0x0100 )
84 unsigned long high_pack_size = in.get();
85 high_pack_size |= in.get() << 8;
86 high_pack_size |= in.get() << 16;
87 high_pack_size |= in.get() << 24;
88 if( high_pack_size )
90 std::cerr << "Packed file size >= 4 GiB not "
91 "implemented" << std::endl;
92 std::abort();
94 in.seekg(4, std::ios::cur);
97 in.read(m, filenamesize);
98 m[filenamesize] = 0;
99 filename = m;
101 if ( flags & 0x0400 ) /* Salt field present */
103 in.seekg(min(in.tellg() + std::streamoff(8),
104 std::streampos(start + headsize)));
107 /* Extended time stamp field present */
108 if ( flags & 0x1000 &&
109 in.tellg() + std::streamoff(2) <= start + headsize )
111 ParseXtime();
114 in.seekg(end);
116 if ( ( flags & 0xE0 ) == 0xE0 )
117 folder = true;
118 else
119 folder = false;
122 /* Derived from _parse_ext_time function in "rarfile" Python module.
123 http://rarfile.berlios.de/ */
124 void
125 FileBlock::ParseXtime()
127 unsigned int flags = in.get();
128 flags += in.get() * 256;
129 int field = 4;
131 --field;
132 unsigned int field_flags = flags >> field * 4 & 0xF;
134 unsigned long frac = 0; /* 100 ns units; 24 bits */
135 if ( field_flags & 8 ) /* mtime field present */
137 filedate.tv_sec += field_flags >> 2 & 1;
139 for ( unsigned int i = 0; i < (field_flags & 3); ++i )
141 frac >>= 8;
142 frac += in.get() << 16;
145 filedate.tv_nsec = frac * 100;
147 /* Not interested in the three other time fields */
148 while ( field > 0 )
150 --field;
151 field_flags = flags >> field * 4 & 0xF;
152 if ( 0 != (field_flags & 8) )
154 in.seekg(field_flags & 3, std::ios::cur);
159 void
160 FileBlock::GetFileDate(struct timespec* tp)
162 tp->tv_sec = filedate.tv_sec;
163 tp->tv_nsec = filedate.tv_nsec;
166 FileBlock::~FileBlock()
171 bool
172 FileBlock::isFolder()
174 return folder;
177 bool
178 FileBlock::isCompressed()
180 return compressed;
183 unsigned int
184 FileBlock::GetDataSize()
186 return size;
189 std::string
190 FileBlock::GetFileName()
192 return filename;
196 FileBlock::GetData(char *buf, unsigned int offset, unsigned int len)
198 std::streampos old = in.tellg();
200 in.seekg(start + headsize + offset);
202 if ( offset > size || !len)
203 return 0;
204 if ( offset + len > size )
205 len = size - offset;
207 in.read(buf, len);
208 in.seekg(old);
210 return len;