/*
* $Id$
*
* Copyright (C) 2003-2015 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.fs.exfat;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import org.apache.log4j.Logger;
/**
* @author Matthias Treydte <waldheinz at gmail.com>
*/
final class EntryTimes {
public static EntryTimes read(ByteBuffer src) throws IOException {
/* read create date/time */
final int cTime = DeviceAccess.getUint16(src);
final int cDate = DeviceAccess.getUint16(src);
/* read modify date/time */
final int mTime = DeviceAccess.getUint16(src);
final int mDate = DeviceAccess.getUint16(src);
/* read access date/time */
final int aTime = DeviceAccess.getUint16(src);
final int aDate = DeviceAccess.getUint16(src);
/* read c/m centiseconds */
final int cTimeCs = DeviceAccess.getUint8(src);
final int mTimeCs = DeviceAccess.getUint8(src);
/* read time zone offsets */
final int cOffset = DeviceAccess.getUint8(src);
final int mOffset = DeviceAccess.getUint8(src);
final int aOffset = DeviceAccess.getUint8(src);
final Date created = exfatToUnix(cDate, cTime, cTimeCs, cOffset);
final Date modified = exfatToUnix(mDate, mTime, mTimeCs, mOffset);
final Date accessed = exfatToUnix(aDate, aTime, 0, aOffset);
return new EntryTimes(created, modified, accessed);
}
private static final int EXFAT_EPOCH = 1980;
private static Date exfatToUnix(int date, int time, int cs, int tzOffset) {
try {
final GregorianCalendar cal =
new GregorianCalendar(TimeZone.getTimeZone("UTC"));
cal.setTimeInMillis(0);
final int day = date & 0x1f;
final int month = ((date >> 5) & 0x0f);
final int year = ((date >> 9) & 0x7f) + EXFAT_EPOCH;
if ((day == 0) || (month <= 0) || (month > 12)) {
throw new IllegalStateException(
"bad day (" + day + ") or month ("
+ month + ") value");
}
cal.set(year, month - 1, day);
final int twoSec = (time & 0x1f);
final int min = ((time >> 5) & 0x0f);
final int hour = (time >> 11);
if ((hour > 23) || (min > 59) || (twoSec > 29)) {
throw new IllegalStateException("bad hour ("
+ hour + ") or minute ("
+ min + ") value");
}
if (cs > 199) {
throw new IllegalStateException("bad centiseconds value");
}
cal.add(GregorianCalendar.HOUR_OF_DAY, hour);
cal.add(GregorianCalendar.MINUTE, min);
cal.add(GregorianCalendar.SECOND, twoSec * 2);
cal.setTimeInMillis(cal.getTimeInMillis() + (cs * 10));
/* adjust for TZ offset */
final boolean tzNeg = ((tzOffset & 0x40) != 0);
tzOffset &= 0x3f;
tzOffset *= tzNeg ? -15 : 15;
cal.add(GregorianCalendar.MINUTE, tzOffset);
return cal.getTime();
} catch (Exception e) {
Logger.getLogger(EntryTimes.class).error("Error getting entry times", e);
return null;
}
}
private final Date created;
private final Date modified;
private final Date accessed;
private EntryTimes(Date created, Date modified, Date accessed) {
this.created = created;
this.modified = modified;
this.accessed = accessed;
}
public Date getCreated() {
return created == null ? null : (Date) created.clone();
}
public Date getModified() {
return modified == null ? null : (Date) modified.clone();
}
public Date getAccessed() {
return accessed == null ? null : (Date) accessed.clone();
}
}