Decode extended time stamp field for greater resolution
[rarfs.git] / rarfs / src / fileblock.cc
blob851c0d8995b32156b1ac307ab10649d736898d7f
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 "main.h"
27 #include <time.h>
28 #include <ios>
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=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 #ifdef OK_TO_BREAK
83 if( flags & 0x0100 )
84 in.seekg(8, std::ios::cur);
85 #endif
87 in.read(m, filenamesize);
88 m[filenamesize] = 0;
89 filename = m;
91 if ( flags & 0x0400 ) /* Salt field present */
93 in.seekg(min(in.tellg() + std::streamoff(8),
94 std::streampos(start + headsize)));
97 /* Extended time stamp field present */
98 if ( flags & 0x1000 &&
99 in.tellg() + std::streamoff(2) <= start + headsize )
101 ParseXtime();
104 in.seekg(end);
106 if ( ( flags & 0xE0 ) == 0xE0 )
107 folder = true;
108 else
109 folder = false;
112 /* Derived from _parse_ext_time function in "rarfile" Python module.
113 http://rarfile.berlios.de/ */
114 void
115 FileBlock::ParseXtime()
117 unsigned int flags = in.get();
118 flags += in.get() * 256;
119 int field = 4;
121 --field;
122 unsigned int field_flags = flags >> field * 4 & 0xF;
124 unsigned long frac = 0; /* 100 ns units; 24 bits */
125 if ( field_flags & 8 ) /* mtime field present */
127 filedate += field_flags >> 2 & 1;
129 for ( unsigned int i = 0; i < (field_flags & 3); ++i )
131 frac >>= 8;
132 frac += in.get() << 16;
135 /* Add frac * 100 nanoseconds to timestamp */
137 /* Not interested in the three other time fields */
138 while ( field > 0 )
140 --field;
141 field_flags = flags >> field * 4 & 0xF;
142 if ( 0 != (field_flags & 8) )
144 in.seekg(field_flags & 3, std::ios::cur);
149 time_t
150 FileBlock::GetFileDate()
152 return filedate;
155 FileBlock::~FileBlock()
160 bool
161 FileBlock::isFolder()
163 return folder;
166 bool
167 FileBlock::isCompressed()
169 return compressed;
172 unsigned int
173 FileBlock::GetDataSize()
175 return size;
178 std::string
179 FileBlock::GetFileName()
181 return filename;
185 FileBlock::GetData(char *buf, unsigned int offset, unsigned int len)
187 std::streampos old = in.tellg();
189 in.seekg(start + headsize + offset);
191 if ( offset > size || !len)
192 return 0;
193 if ( offset + len > size )
194 len = size - offset;
196 in.read(buf, len);
197 in.seekg(old);
199 return len;