/** * Copyright 2012 Perforce Software Inc., All Rights Reserved. */ package com.perforce.p4java.io.apple; import com.perforce.p4java.Log; import com.perforce.p4java.exception.FileDecoderException; /** * This abstract class handles AppleSingle/Double files. It contains a common * method to verify the Apple file, and figure out if it is an AppleSingle or * AppleDouble formatted file. * <p> * * The AppleSingle format is a representation of Macintosh files as one * consecutive stream of bytes. AppleSingle combines the data fork, resource * fork and the related Finder meta-file information into a single file. * <p> * * The AppleDouble format stores the data fork, resource fork as two separate * files. AppleDouble leaves the data fork in its original format, and the * resource fork and Finder information were combined into a second file. * <p> * * Apple defined the magic number for the AppleSingle format as 0x00051600, and * the magic number for the AppleDouble format as 0x00051607. * * <pre> * AppleSingle file header: * * Field Length * ----- ------ * Magic number ------- 4 bytes * Version number ------ 4 bytes * Filler ------------- 16 bytes * Number of entries ----- 2 bytes * * Entry descriptor for each entry: * Entry ID ------ 4 bytes * Offset -------- 4 bytes * Length -------- 4 bytes * * Apple reserved entry IDs: * * Data Fork -------- 1 Data fork * Resource Fork ----- 2 Resource fork * Real Name -------- 3 File's name as created on home file system * Comment --------- 4 Standard Macintosh comment * Icon, B&W -------- 5 Standard Macintosh black and white icon * Icon, Color -------- 6 Macintosh color icon * File Dates Info ------8 File creation date, modification date, and so on * Finder Info -------- 9 Standard Macintosh Finder information * Macintosh File Info ---10 Macintosh file information, attributes, and so on * ProDOS File Info -----11 ProDOS file information, attributes, and so on * MS-DOS File Info ----12 MS-DOS file information, attributes, and so on * Short Name --------13 AFP short name * AFP File Info ------- 14 AFP file information, attributes, and so on * Directory ID --------15 AFP directory ID * </pre> * * See RFC 1740 for reference: http://tools.ietf.org/html/rfc1740 */ public abstract class AppleFile { /** The Apple file format: AppleSingle, AppleDouble, default to unknown. */ protected FileFormat format = FileFormat.UNKNOWN; /** The raw Apple file. */ protected AppleFileData fileData = AppleFileData.EMPTY_FILE_DATA; /** Entry 1: Data fork. */ protected AppleFileData dataFork = AppleFileData.EMPTY_FILE_DATA; /** Entry 2: Resource fork. */ protected AppleFileData resourceFork = AppleFileData.EMPTY_FILE_DATA; /** Entry 3: File's name as created on home file system. */ protected AppleFileData realName = AppleFileData.EMPTY_FILE_DATA; /** Entry 4: Standard Macintosh comment. */ protected AppleFileData comment = AppleFileData.EMPTY_FILE_DATA; /** Entry 5: Standard Macintosh black and white icon. */ protected AppleFileData iconBW = AppleFileData.EMPTY_FILE_DATA; /** Entry 6: Macintosh color icon. */ protected AppleFileData iconColor = AppleFileData.EMPTY_FILE_DATA; /** Entry 8: File creation date, modification date, and so on. */ protected AppleFileData fileDatesInfo = AppleFileData.EMPTY_FILE_DATA; /** The file dates info entry. */ protected FileDatesInfoEntry fileDatesInfoEntry = null; /** Entry 9: Standard Macintosh Finder information. */ protected AppleFileData finderInfo = AppleFileData.EMPTY_FILE_DATA; /** Entry 10: Macintosh file information, attributes, and so on. */ protected AppleFileData macintoshInfo = AppleFileData.EMPTY_FILE_DATA; /** Entry 11: ProDOS file information, attributes, and so on. */ protected AppleFileData proDOSFileInfo = AppleFileData.EMPTY_FILE_DATA; /** Entry 12: MS-DOS file information, attributes, and so on. */ protected AppleFileData msDOSFileInfo = AppleFileData.EMPTY_FILE_DATA; /** Entry 13: AFP short name. */ protected AppleFileData shortName = AppleFileData.EMPTY_FILE_DATA; /** Entry 14: AFP file information, attributes, and so on. */ protected AppleFileData afpFileInfo = AppleFileData.EMPTY_FILE_DATA; /** Entry 15: AFP directory ID. */ protected AppleFileData directoryID = AppleFileData.EMPTY_FILE_DATA; /** The num entries. */ protected int numEntries = 0; /** * The Apple file format. */ public enum FileFormat { APPLE_SINGLE, APPLE_DOUBLE, UNKNOWN; /** * Return a suitable Apple file format as inferred from the passed-in * string. Otherwise return the UNKNOWN file format. * * @param fileFormat * the file format * @return the FileFormat */ public static FileFormat fromString(String fileFormat) { if (fileFormat == null) { return null; } try { return FileFormat.valueOf(fileFormat.toUpperCase()); } catch (IllegalArgumentException iae) { Log.error("Bad conversion attempt in FileFormat.fromString; string: " + fileFormat + "; message: " + iae.getMessage()); Log.exception(iae); return UNKNOWN; } } }; /** * This class represents the file dates. */ public class FileDatesInfoEntry { /** The create time. */ private int createTime = Integer.MIN_VALUE; /** The modify time. */ private int modifyTime = Integer.MIN_VALUE; /** The backup time. */ private int backupTime = Integer.MIN_VALUE; /** The access time. */ private int accessTime = Integer.MIN_VALUE; /** * Instantiates a new file dates info entry. */ public FileDatesInfoEntry() { } /** * Gets the creates the time. * * @return the creates the time */ public int getCreateTime() { return createTime; } /** * Sets the creates the time. * * @param createTime * the new creates the time */ public void setCreateTime(int createTime) { this.createTime = createTime; } /** * Gets the modify time. * * @return the modify time */ public int getModifyTime() { return modifyTime; } /** * Sets the modify time. * * @param modifyTime * the new modify time */ public void setModifyTime(int modifyTime) { this.modifyTime = modifyTime; } /** * Gets the backup time. * * @return the backup time */ public int getBackupTime() { return backupTime; } /** * Sets the backup time. * * @param backupTime * the new backup time */ public void setBackupTime(int backupTime) { this.backupTime = backupTime; } /** * Gets the access time. * * @return the access time */ public int getAccessTime() { return accessTime; } /** * Sets the access time. * * @param accessTime * the new access time */ public void setAccessTime(int accessTime) { this.accessTime = accessTime; } } /** * Sets the num entries. * * @param numEntries * the new num entries */ public void setNumEntries(int numEntries) { this.numEntries = numEntries; } /** * Verify the validity of the Apple file. * * @throws FileDecoderException * the file decoder exception */ @SuppressWarnings("unused") protected void verify() throws FileDecoderException { byte[] data = this.fileData.getData(); int offset = this.fileData.getOffset(); int length = this.fileData.getLength(); int position = offset; if (length < 26) { throw new FileDecoderException("File is too short"); } /* Magic number */ int magic = 0; magic |= data[(position++)] & 0xFF; magic <<= 8; magic |= data[(position++)] & 0xFF; magic <<= 8; magic |= data[(position++)] & 0xFF; magic <<= 8; magic |= data[(position++)] & 0xFF; /* Check Apple file format: AppleSingle or AppleDobule */ if (magic == 0x00051600) { this.format = FileFormat.APPLE_SINGLE; } else if (magic == 0x00051607) { this.format = FileFormat.APPLE_DOUBLE; } else { throw new FileDecoderException("Invalid Apple file magic number."); } /* Version number */ int version = 0; version |= data[(position++)] & 0xFF; version <<= 8; version |= data[(position++)] & 0xFF; version <<= 8; version |= data[(position++)] & 0xFF; version <<= 8; version |= data[(position++)] & 0xFF; if (version != 0x00020000) { throw new FileDecoderException("Unknown Apple file version"); } /* Filler */ position += 16; /* Number of entries */ this.numEntries = 0; this.numEntries |= data[(position++)] & 0xFF; this.numEntries <<= 8; this.numEntries |= data[(position++)] & 0xFF; if (length < 26 + 12 * this.numEntries) { throw new FileDecoderException("Corrupt Apple file data."); } /* Check entries */ int entryId = 0; int entryOffset = 0; int entryLength = 0; int contentPosition = 26 + 12 * this.numEntries; for (int i = 0; i < this.numEntries; i++) { position = 26 + i * 12; /* Entry ID */ entryId = 0; entryId |= data[(position++)] & 0xFF; entryId <<= 8; entryId |= data[(position++)] & 0xFF; entryId <<= 8; entryId |= data[(position++)] & 0xFF; entryId <<= 8; entryId |= data[(position++)] & 0xFF; /* Entry offset */ entryOffset = 0; entryOffset |= data[(position++)] & 0xFF; entryOffset <<= 8; entryOffset |= data[(position++)] & 0xFF; entryOffset <<= 8; entryOffset |= data[(position++)] & 0xFF; entryOffset <<= 8; entryOffset |= data[(position++)] & 0xFF; entryOffset &= 0x7FFFFFFF; /* Entry length */ entryLength = 0; entryLength |= data[(position++)] & 0xFF; entryLength <<= 8; entryLength |= data[(position++)] & 0xFF; entryLength <<= 8; entryLength |= data[(position++)] & 0xFF; entryLength <<= 8; entryLength |= data[(position++)] & 0xFF; entryLength &= 0x7FFFFFFF; if ((entryOffset < contentPosition) || (length < entryOffset + entryLength)) { throw new FileDecoderException("Corrupt Apple file data."); } } } /** * Extract file dates. * * @param data the data * @param offset the offset * @param length the length */ protected void extractFileDates(byte[] data, int offset, int length) { if ((0 > offset) || (offset > data.length)) throw new IndexOutOfBoundsException(); if ((0 > length) || (length > data.length - offset)) throw new IndexOutOfBoundsException(); int position = offset; int createTime = 0; createTime |= data[(position++)] & 0xFF; createTime <<= 8; createTime |= data[(position++)] & 0xFF; createTime <<= 8; createTime |= data[(position++)] & 0xFF; createTime <<= 8; createTime |= data[(position++)] & 0xFF; int modifyTime = 0; modifyTime |= data[(position++)] & 0xFF; modifyTime <<= 8; modifyTime |= data[(position++)] & 0xFF; modifyTime <<= 8; modifyTime |= data[(position++)] & 0xFF; modifyTime <<= 8; modifyTime |= data[(position++)] & 0xFF; int backupTime = 0; backupTime |= data[(position++)] & 0xFF; backupTime <<= 8; backupTime |= data[(position++)] & 0xFF; backupTime <<= 8; backupTime |= data[(position++)] & 0xFF; backupTime <<= 8; backupTime |= data[(position++)] & 0xFF; int accessTime = 0; accessTime |= data[(position++)] & 0xFF; accessTime <<= 8; accessTime |= data[(position++)] & 0xFF; accessTime <<= 8; accessTime |= data[(position++)] & 0xFF; accessTime <<= 8; accessTime |= data[(position++)] & 0xFF; this.fileDatesInfoEntry = new FileDatesInfoEntry(); fileDatesInfoEntry.setCreateTime(createTime); fileDatesInfoEntry.setModifyTime(modifyTime); fileDatesInfoEntry.setBackupTime(backupTime); fileDatesInfoEntry.setAccessTime(accessTime); } /** * Gets the format. * * @return the format */ public FileFormat getFormat() { return format; } /** * Sets the format. * * @param format * the new format */ public void setFormat(FileFormat format) { this.format = format; } /** * Gets the file data. * * @return the file data */ public AppleFileData getFileData() { return fileData; } /** * Sets the file data. * * @param fileData * the new file data */ public void setFileData(AppleFileData fileData) { this.fileData = fileData; } /** * Gets the data fork. * * @return the data fork */ public AppleFileData getDataFork() { return dataFork; } /** * Sets the data fork. * * @param dataFork * the new data fork */ public void setDataFork(AppleFileData dataFork) { this.dataFork = dataFork; } /** * Gets the resource fork. * * @return the resource fork */ public AppleFileData getResourceFork() { return resourceFork; } /** * Sets the resource fork. * * @param resourceFork * the new resource fork */ public void setResourceFork(AppleFileData resourceFork) { this.resourceFork = resourceFork; } /** * Gets the real name. * * @return the real name */ public AppleFileData getRealName() { return realName; } /** * Sets the real name. * * @param realName * the new real name */ public void setRealName(AppleFileData realName) { this.realName = realName; } /** * Gets the comment. * * @return the comment */ public AppleFileData getComment() { return comment; } /** * Sets the comment. * * @param comment * the new comment */ public void setComment(AppleFileData comment) { this.comment = comment; } /** * Gets the icon bw. * * @return the icon bw */ public AppleFileData getIconBW() { return iconBW; } /** * Sets the icon bw. * * @param iconBW * the new icon bw */ public void setIconBW(AppleFileData iconBW) { this.iconBW = iconBW; } /** * Gets the icon color. * * @return the icon color */ public AppleFileData getIconColor() { return iconColor; } /** * Sets the icon color. * * @param iconColor * the new icon color */ public void setIconColor(AppleFileData iconColor) { this.iconColor = iconColor; } /** * Gets the file dates info. * * @return the file dates info */ public AppleFileData getFileDatesInfo() { return fileDatesInfo; } /** * Sets the file dates info. * * @param fileDatesInfo * the new file dates info */ public void setFileDatesInfo(AppleFileData fileDatesInfo) { this.fileDatesInfo = fileDatesInfo; } /** * Gets the finder info. * * @return the finder info */ public AppleFileData getFinderInfo() { return finderInfo; } /** * Sets the finder info. * * @param finderInfo * the new finder info */ public void setFinderInfo(AppleFileData finderInfo) { this.finderInfo = finderInfo; } /** * Gets the macintosh info. * * @return the macintosh info */ public AppleFileData getMacintoshInfo() { return macintoshInfo; } /** * Sets the macintosh info. * * @param macintoshInfo * the new macintosh info */ public void setMacintoshInfo(AppleFileData macintoshInfo) { this.macintoshInfo = macintoshInfo; } /** * Gets the pro dos file info. * * @return the pro dos file info */ public AppleFileData getProDOSFileInfo() { return proDOSFileInfo; } /** * Sets the pro dos file info. * * @param proDOSFileInfo * the new pro dos file info */ public void setProDOSFileInfo(AppleFileData proDOSFileInfo) { this.proDOSFileInfo = proDOSFileInfo; } /** * Gets the ms dos file info. * * @return the ms dos file info */ public AppleFileData getMsDOSFileInfo() { return msDOSFileInfo; } /** * Sets the ms dos file info. * * @param msDOSFileInfo * the new ms dos file info */ public void setMsDOSFileInfo(AppleFileData msDOSFileInfo) { this.msDOSFileInfo = msDOSFileInfo; } /** * Gets the short name. * * @return the short name */ public AppleFileData getShortName() { return shortName; } /** * Sets the short name. * * @param shortName * the new short name */ public void setShortName(AppleFileData shortName) { this.shortName = shortName; } /** * Gets the afp file info. * * @return the afp file info */ public AppleFileData getAfpFileInfo() { return afpFileInfo; } /** * Sets the afp file info. * * @param afpFileInfo * the new afp file info */ public void setAfpFileInfo(AppleFileData afpFileInfo) { this.afpFileInfo = afpFileInfo; } /** * Gets the directory id. * * @return the directory id */ public AppleFileData getDirectoryID() { return directoryID; } /** * Sets the directory id. * * @param directoryID * the new directory id */ public void setDirectoryID(AppleFileData directoryID) { this.directoryID = directoryID; } /** * Gets the num entries. * * @return the num entries */ public int getNumEntries() { return numEntries; } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 19903 | stuartrowe |
Branching //guest/perforce_software/p4java/... to //guest/stuartrowe/p4java/... |
||
//guest/perforce_software/p4java/r14.1/src/main/java/com/perforce/p4java/io/apple/AppleFile.java | |||||
#1 | 12541 | Matt Attaway | Initial add of the 14.1 p4java source code |