/*
* $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.jfat;
import java.io.IOException;
import java.util.Vector;
import org.apache.log4j.Logger;
import org.jnode.util.NumberUtils;
public class FatRecord {
private static final Logger log = Logger.getLogger(FatRecord.class);
private static final int MAXLONGENTRIES = 20;
private FatShortDirEntry shortEntry;
private final Vector<FatLongDirEntry> longEntries;
private String longName;
public FatRecord() {
init();
longEntries = new Vector<FatLongDirEntry>(MAXLONGENTRIES);
}
public FatRecord(FatDirectory parent, FatName name) throws IOException {
init();
FatFileSystem fs = parent.getFatFileSystem();
FatDirEntry[] free;
FatShortDirEntry s;
int n = name.getNumberOfComponents();
if (!name.isMangled() && (n != 1))
throw new IOException("not mangled and n=" + n);
if (name.isMangled()) {
free = parent.getFatFreeEntries(n + 1);
longEntries = new Vector<FatLongDirEntry>(n + 1);
} else {
free = parent.getFatFreeEntries(1);
longEntries = new Vector<FatLongDirEntry>(0);
}
s = new FatShortDirEntry(fs, name, free[free.length - 1].getIndex());
if (name.isMangled()) {
FatLongDirEntry l = new FatLongDirEntry(
fs, name.getComponent(n - 1), (byte) n, s.getChkSum(),
true, free[0].getIndex());
addSetFatDirEntry(parent, l);
for (int i = (n - 2); i >= 0; i--) {
l = new FatLongDirEntry(fs, name.getComponent(i), (byte) (i + 1),
s.getChkSum(), false, free[n - 1 - i].getIndex());
addSetFatDirEntry(parent, l);
}
}
close(s);
}
private void init() {
shortEntry = null;
longName = null;
}
private void clearLongEntries() {
longEntries.clear();
}
private void mustBeOpen() {
if (shortEntry != null) {
// FIXME ... this is clearly the wrong exception
throw new UnsupportedOperationException("FatRecord is closed");
}
}
private void mustBeClose() {
if (shortEntry == null) {
// FIXME ... this is clearly the wrong exception
throw new UnsupportedOperationException("FatRecord is open");
}
}
public void clear() {
init();
clearLongEntries();
}
public void add(FatLongDirEntry entry) {
mustBeOpen();
if (entry.isDamaged()) {
// FIXME ... this is clearly the wrong exception
throw new UnsupportedOperationException("Damaged entry, shouldn't happen");
}
longEntries.add(entry);
}
private void addSetFatDirEntry(FatDirectory parent, FatLongDirEntry entry) throws IOException {
add(entry);
parent.setFatDirEntry(entry);
}
public void close(FatShortDirEntry entry) {
mustBeOpen();
shortEntry = entry;
mustBeClose();
longName = getShortName();
if (longEntries.isEmpty())
return;
int i;
StringBuilder lname = new StringBuilder(longEntries.size() * FatLongDirEntry.NAMELENGTH);
int last = longEntries.size() - 1;
byte chkSum = getChkSum();
for (i = last; i >= 0; i--) {
FatLongDirEntry l = longEntries.get(i);
int ordinal = last - i + 1;
if (l.getOrdinal() != ordinal && !l.isFreeDirEntry()) {
log.debug("ordinal orphaned vector discarded for " + getShortName());
clearLongEntries();
return;
}
if (l.getChkSum() != chkSum && !l.isFreeDirEntry()) {
log.debug("chksum orphaned vector discarded for " + getShortName());
clearLongEntries();
return;
}
lname.append(l.getComponent());
}
longName = lname.toString();
}
public FatShortDirEntry getShortEntry() {
mustBeClose();
return shortEntry;
}
public String getShortName() {
return getShortEntry().getShortName();
}
public boolean hasLongEntries() {
mustBeClose();
return !longEntries.isEmpty();
}
public int size() {
mustBeClose();
return longEntries.size() + 1;
}
public byte getChkSum() {
mustBeClose();
return shortEntry.getChkSum();
}
public Vector<FatLongDirEntry> getLongEntries() {
mustBeClose();
return longEntries;
}
public String getLongName() {
mustBeClose();
return longName;
}
@Override
public String toString() {
if (shortEntry == null) {
return String.format("FatRecord (Open) %s", longEntries);
} else {
return String.format(
"FatRecord (Closed) ['%s' %s] index:%d chksum:%s size:%d",
getLongName(), getShortName(), getShortEntry().getIndex(), NumberUtils.hex(getChkSum(), 2), size());
}
}
public String toDebugString() {
mustBeClose();
StrWriter out = new StrWriter();
out.println("********************************************************");
out.println("FatRecord (Closed)");
out.println("********************************************************");
out.println("ShortName\t" + "<" + getShortName() + ">");
out.println("ShortIndex\t" + getShortEntry().getIndex());
out.println("ChckSum\t\t" + NumberUtils.hex(getChkSum(), 2));
out.println("Size\t\t" + size());
for (int i = size() - 2; i >= 0; i--) {
FatLongDirEntry l = longEntries.get(i);
out.print(" [" + i + "]\t\t");
out.print("Ord(" + l.getOrdinal() + ")\t");
out.print("Chk(" + NumberUtils.hex(l.getChkSum(), 2) + ")\t");
out.print("Idx(" + l.getIndex() + ")\t");
out.println("<" + l.getComponent() + ">");
}
out.println("LongName\t" + "<" + getLongName() + ">");
out.print("********************************************************");
return out.toString();
}
}