diff options
Diffstat (limited to 'src/main/java/de/waldheinz/fs/fat/ShortName.java')
-rw-r--r-- | src/main/java/de/waldheinz/fs/fat/ShortName.java | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/src/main/java/de/waldheinz/fs/fat/ShortName.java b/src/main/java/de/waldheinz/fs/fat/ShortName.java new file mode 100644 index 0000000..0fb382a --- /dev/null +++ b/src/main/java/de/waldheinz/fs/fat/ShortName.java @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2009,2010 Matthias Treydte <mt@waldheinz.de> + * + * 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 de.waldheinz.fs.fat; + +import java.math.BigInteger; +import java.util.Arrays; + +/** + * Represents a "short" (8.3) file name as used by DOS. + * + * @author Matthias Treydte <waldheinz at gmail.com> + */ +final class ShortName { + + /** + * These are taken from the FAT specification. + */ + private final static byte[] ILLEGAL_CHARS = { + 0x22, 0x2A, 0x2B, 0x2C, 0x2E, 0x2F, 0x3A, 0x3B, + 0x3C, 0x3D, 0x3E, 0x3F, 0x5B, 0x5C, 0x5D, 0x7C + }; + + /** + * The name of the "current directory" (".") entry of a FAT directory. + */ + public final static ShortName DOT = new ShortName(".", ""); // NOI18N + + /** + * The name of the "parent directory" ("..") entry of a FAT directory. + */ + public final static ShortName DOT_DOT = new ShortName("..", ""); // NOI18N + + private final char[] name; + private boolean mShortNameOnly; + + private ShortName(String nameExt) { + if (nameExt.length() > 12) + throw new IllegalArgumentException("name too long"); + + final int i = nameExt.indexOf('.'); + final String nameString, extString; + + if (i < 0) { + nameString = nameExt.toUpperCase(); + extString = ""; + } else { + nameString = nameExt.substring(0, i).toUpperCase(); + extString = nameExt.substring(i + 1).toUpperCase(); + } + + this.name = toCharArray(nameString, extString); + checkValidChars(this.name); + } + + ShortName(String name, String ext) { + this.name = toCharArray(name, ext); + } + + ShortName(char[] name) { + this.name = name; + } + + public ShortName(char[] nameArr, char[] extArr) { + char[] result = new char[11]; + System.arraycopy(nameArr, 0, result, 0, nameArr.length); + System.arraycopy(extArr, 0, result, 8, extArr.length); + this.name = result; + } + + private static char[] toCharArray(String name, String ext) { + checkValidName(name); + checkValidExt(ext); + + final char[] result = new char[11]; + Arrays.fill(result, ' '); + System.arraycopy(name.toCharArray(), 0, result, 0, name.length()); + System.arraycopy(ext.toCharArray(), 0, result, 8, ext.length()); + + return result; + } + + /** + * Calculates the checksum that is used to test a long file name for it's + * validity. + * + * @return the {@code ShortName}'s checksum + */ + public byte checkSum() { + final byte[] dest = new byte[11]; + for (int i = 0; i < 11; i++) + dest[i] = (byte) name[i]; + + int sum = dest[0]; + for (int i = 1; i < 11; i++) { + sum = dest[i] + (((sum & 1) << 7) + ((sum & 0xfe) >> 1)); + } + + return (byte) (sum & 0xff); + } + + /** + * Parses the specified string into a {@code ShortName}. + * + * @param name the name+extension of the {@code ShortName} to get + * @return the {@code ShortName} representing the specified name + * @throws IllegalArgumentException if the specified name can not be parsed + * into a {@code ShortName} + * @see #canConvert(java.lang.String) + */ + public static ShortName get(String name) throws IllegalArgumentException { + if (name.equals(".")) + return DOT; + else if (name.equals("..")) + return DOT_DOT; + else + return new ShortName(name); + } + + /** + * Tests if the specified string can be converted to a {@code ShortName}. + * + * @param nameExt the string to test + * @return if the string can be converted + * @see #get(java.lang.String) + */ + public static boolean canConvert(String nameExt) { + /* TODO: do this without exceptions */ + try { + ShortName.get(nameExt); + return true; + } catch (IllegalArgumentException ex) { + return false; + } + } + + public static ShortName parse(byte[] data) { + final char[] nameArr = new char[8]; + + for (int i = 0; i < nameArr.length; i++) { + nameArr[i] = (char) LittleEndian.getUInt8(data, i); + } + + final char[] extArr = new char[3]; + for (int i = 0; i < extArr.length; i++) { + extArr[i] = (char) LittleEndian.getUInt8(data, 0x08 + i); + } + + return new ShortName(nameArr, extArr); + } + + public void write(byte[] dest) { + for (int i = 0; i < 11; i++) { + dest[i] = (byte) name[i]; + } + } + + public String asSimpleString() { + return new String(this.name).trim(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < this.name.length; i++) { + sb.append(Integer.toHexString(name[i])); + sb.append(' '); + } + return getClass().getSimpleName() + + " [" + + asSimpleString() + " -- " + + sb.toString() + "]"; // NOI18N + } + + private static void checkValidName(String name) { + checkString(name, "name", 1, 8); + } + + private static void checkValidExt(String ext) { + checkString(ext, "extension", 0, 3); + } + + private static void checkString(String str, String strType, + int minLength, int maxLength) { + + if (str == null) + throw new IllegalArgumentException(strType + + " is null"); + if (str.length() < minLength) + throw new IllegalArgumentException(strType + + " must have at least " + minLength + + " characters: " + str); + if (str.length() > maxLength) + throw new IllegalArgumentException(strType + + " has more than " + maxLength + + " characters: " + str); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ShortName)) { + return false; + } + + final ShortName other = (ShortName) obj; + return Arrays.equals(name, other.name); + } + + @Override + public int hashCode() { + return Arrays.hashCode(this.name); + } + + public void setHasShortNameOnly(boolean hasShortNameOnly) { + mShortNameOnly = hasShortNameOnly; + } + + public boolean hasShortNameOnly() { + return mShortNameOnly; + } + + /** + * Checks if the specified char array consists only of "valid" byte values + * according to the FAT specification. + * + * @param chars the char array to test + * @throws IllegalArgumentException if invalid chars are contained + */ + public static void checkValidChars(char[] chars) + throws IllegalArgumentException { + + if (chars[0] == 0x20) + throw new IllegalArgumentException( + "0x20 can not be the first character"); + + for (int i = 0; i < chars.length; i++) { + if ((chars[i] & 0xff) != chars[i]) + throw new IllegalArgumentException("multi-byte character at " + i); + + final byte toTest = (byte) (chars[i] & 0xff); + + if (toTest < 0x20 && toTest != 0x05) + throw new IllegalArgumentException("character < 0x20 at" + i); + + for (int j = 0; j < ILLEGAL_CHARS.length; j++) { + if (toTest == ILLEGAL_CHARS[j]) + throw new IllegalArgumentException("illegal character " + + ILLEGAL_CHARS[j] + " at " + i); + } + } + } +} |