public void printFields(PrintStream ps, String prefix) { ps.println(prefix + " sbSig: \"" + getSbSigAsString() + "\""); ps.println(prefix + " sbBlkSize: " + getSbBlkSize()); ps.println(prefix + " sbBlkCount: " + getSbBlkCount()); ps.println(prefix + " sbDevType: " + getSbDevType()); ps.println(prefix + " sbDevId: " + getSbDevId()); ps.println(prefix + " sbData: " + getSbData()); ps.println(prefix + " sbDrvrCount: " + getSbDrvrCount()); ps.println(prefix + " entries (" + entries.length + " elements):"); for (int i = 0; i < entries.length; ++i) { ps.println(prefix + " entries[" + i + "]: "); entries[i].print(ps, prefix + " "); } if (entries.length == 0) ps.println(prefix + " <empty>"); ps.println(prefix + " ddPad:"); ps.print(prefix + " byte[" + ddPad.length + "] {"); for (int i = 0; i < ddPad.length; ++i) { if (i % 16 == 0) { ps.println(); ps.print(prefix + " "); } ps.print(" " + Util.toHexStringBE(ddPad[i])); } ps.println(); ps.println(prefix + " }"); try { byte[] md5sum = MessageDigest.getInstance("MD5").digest(ddPad); ps.println(prefix + " MD5: " + Util.byteArrayToHexString(md5sum)); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } }
public VisualizeUnicodeNormalization() { super("HFS+ Unicode Decomposition Table"); JPanel mainPanel = new JPanel(); JScrollPane mainPanelScroller = new JScrollPane( mainPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); mainPanelScroller.getVerticalScrollBar().setUnitIncrement(20); UnicodeNormalizationToolkit unt = UnicodeNormalizationToolkit.getDefaultInstance(); Map<Character, char[]> table = unt.getDecompositionTable(); StringBuilder sb = new StringBuilder(); Comparator<Map.Entry<Character, char[]>> cmp = new Comparator<Map.Entry<Character, char[]>>() { public int compare(Map.Entry<Character, char[]> o1, Map.Entry<Character, char[]> o2) { return o1.getKey().compareTo(o2.getKey()); } @Override public boolean equals(Object obj) { return super.equals(obj); } }; TreeSet<Map.Entry<Character, char[]>> ts = new TreeSet<Map.Entry<Character, char[]>>(cmp); for (Map.Entry<Character, char[]> ent : table.entrySet()) ts.add(ent); // ts.addAll(table.entrySet()); for (Map.Entry<Character, char[]> ent : ts) { Character key = ent.getKey(); char[] value = ent.getValue(); sb.append(Util.toHexStringBE(key.charValue())); sb.append(": \" "); sb.append(key.toString()); sb.append(" \" -> \" "); sb.append(value[0]); for (int i = 1; i < value.length; ++i) { sb.append(" \", \" "); sb.append(value[i]); } sb.append(" \""); JLabel cur = new JLabel(sb.toString()); cur.setFont(new java.awt.Font("Monospaced", 0, 20)); mainPanel.add(cur); sb.setLength(0); } add(mainPanelScroller, BorderLayout.CENTER); setDefaultCloseOperation(EXIT_ON_CLOSE); pack(); setLocationRelativeTo(null); }
/** * Creates a new DriverDescriptorRecord from the supplied parameters. * * @param blockSize the block size of the volume. Commonly 512 or 4096 for hard disks and 2048 for * optical drives. * @param blockCount the size of the volume in blockSize-sized blocks. */ public DriverDescriptorRecord(int blockSize, long blockCount) { if (blockSize < 0 || blockSize > 0xFFFF) throw new IllegalArgumentException("Invalid value for " + "'blockSize': " + blockSize); if (blockCount < 0 || blockCount > 0xFFFFFFFFL) throw new IllegalArgumentException("Invalid value for " + "'blockCount': " + blockCount); Util.arrayPutBE(this.sbSig, 0, DDR_SIGNATURE); Util.arrayPutBE(this.sbBlkSize, 0, (short) blockSize); Util.arrayPutBE(this.sbBlkCount, 0, (int) blockCount); Util.arrayPutBE(this.sbDevType, 0, (short) 0); Util.arrayPutBE(this.sbDevId, 0, (short) 0); Util.arrayPutBE(this.sbData, 0, (int) 0); Util.arrayPutBE(this.sbDrvrCount, 0, (short) 0); this.entries = new DriverDescriptorEntry[0]; this.ddPad = new byte[blockSize - 18]; Arrays.fill(ddPad, (byte) 0); }
/** Reserved. */ public byte[] getDdPad() { return Util.createCopy(ddPad); }
/** Returns a String representation of the device signature. */ public String getSbSigAsString() { return Util.toASCIIString(sbSig); }
public int getIndex() { return Util.readIntBE(index); }
private long getDataLength(long dataPos) { byte[] dataLengthBytes = new byte[4]; forkStream.readFrom(dataPos, dataLengthBytes); return Util.unsign(Util.readIntBE(dataLengthBytes)); }
/** * <b>Note that the return value from this function should be interpreted as an unsigned integer, * for instance using Util.unsign(...).</b> */ public short getRawSbDrvrCount() { return Util.readShortBE(sbDrvrCount); }
public static void main(String[] args) { final boolean verbose; final String fsPath; if (args.length == 2 && args[0].equals("-v")) { verbose = true; fsPath = args[1]; } else if (args.length == 1) { verbose = false; fsPath = args[0]; } else { System.err.println("usage: ScanDecmpfs [-v] <device|file>"); System.err.println(); System.err.println( " Scans an HFS+/HFSX volume for decmpfs " + "compressed files and prints the"); System.err.println(" file's CNID, compression type and " + "decompressed size."); System.err.println( " If '-v' is supplied, the path of the " + "compressed file is also resolved and"); System.err.println(" printed after the decompressed size."); System.exit(1); return; } final ReadableRandomAccessStream fsStream = ReadableWin32FileStream.isSystemSupported() ? new ReadableWin32FileStream(fsPath) : new ReadableFileStream(fsPath); final FileSystemHandlerFactory fsHandlerFactory; switch (HFSCommonFileSystemRecognizer.detectFileSystem(fsStream, 0)) { case HFS_WRAPPED_HFS_PLUS: case HFS_PLUS: fsHandlerFactory = FileSystemMajorType.APPLE_HFS_PLUS.createDefaultHandlerFactory(); break; case HFSX: fsHandlerFactory = FileSystemMajorType.APPLE_HFSX.createDefaultHandlerFactory(); break; default: System.err.println("No HFS+/HFSX filesystem detected."); System.exit(1); return; } final FileSystemHandler fsHandlerGeneric = fsHandlerFactory.createHandler(new ReadableStreamDataLocator(fsStream)); if (!(fsHandlerGeneric instanceof HFSPlusFileSystemHandler)) { System.err.println( "Unexpected: File system handler object is " + "not of HFSPlusFileSystemHandler class (class: " + fsHandlerGeneric.getClass() + ")."); System.exit(1); return; } final HFSPlusFileSystemHandler fsHandler = (HFSPlusFileSystemHandler) fsHandlerGeneric; final AttributesFile attributesFile = fsHandler.getFSView().getAttributesFile(); LinkedList<Long> nodeQueue = new LinkedList<Long>(); nodeQueue.addLast(attributesFile.getRootNodeNumber()); /* Depth-first search for "com.apple.decmpfs" attribute records. */ while (!nodeQueue.isEmpty()) { long curNodeNumber = nodeQueue.removeFirst(); CommonBTNode curNode = attributesFile.getNode(curNodeNumber); if (curNode instanceof CommonHFSAttributesIndexNode) { CommonHFSAttributesIndexNode indexNode = (CommonHFSAttributesIndexNode) curNode; List<CommonBTIndexRecord<CommonHFSAttributesKey>> records = indexNode.getBTKeyedRecords(); ListIterator<CommonBTIndexRecord<CommonHFSAttributesKey>> it = records.listIterator(records.size()); /* For the search to be depth first, add elements in reverse * order. */ while (it.hasPrevious()) { nodeQueue.addFirst(it.previous().getIndex()); } } else if (curNode instanceof CommonHFSAttributesLeafNode) { final CommonHFSAttributesLeafNode leafNode = (CommonHFSAttributesLeafNode) curNode; for (CommonHFSAttributesLeafRecord rec : leafNode.getLeafRecords()) { final CommonHFSAttributesKey k = rec.getKey(); if (!new String(k.getAttrName(), 0, k.getAttrNameLen()).equals("com.apple.decmpfs")) { continue; } else if (k.getStartBlock() != 0) { System.err.println( "[WARNING] " + k.getFileID().toLong() + " has " + "com.apple.decmpfs attribute with non-0 " + "start block (" + k.getStartBlock() + "). " + "Skipping..."); continue; } final HFSPlusAttributesLeafRecordData data = rec.getRecordData(); if (!(data instanceof HFSPlusAttributesData)) { System.err.println( "[WARNING] " + k.getFileID().toLong() + " has " + "com.apple.decmpfs attribute without inline " + "data (" + data.getRecordTypeAsString() + "). Skipping..."); continue; } final DecmpfsHeader header = new DecmpfsHeader(((HFSPlusAttributesData) data).getAttrData(), 0); if (header.getMagic() != DecmpfsHeader.MAGIC) { System.err.println( "[WARNING] " + k.getFileID().toLong() + " has " + "com.apple.decmpfs attribute with " + "mismatching magic (expected: 0x" + Util.toHexStringBE((int) DecmpfsHeader.MAGIC) + ", actual: 0x" + Util.toHexStringBE(header.getRawMagic()) + "). Skipping..."); continue; } final StringBuilder pathBuilder; if (verbose) { pathBuilder = new StringBuilder(); boolean firstComponent = true; for (CommonHFSCatalogLeafRecord pathComponent : fsHandler.getFSView().getCatalogFile().getPathTo(k.getFileID())) { /* Skip name of root directory. */ if (!firstComponent) { final char[] nodeName = fsHandler .getFSView() .decodeString(pathComponent.getKey().getNodeName()) .toCharArray(); for (int i = 0; i < nodeName.length; ++i) { /* '/' transformed into ':' and vice versa. * This is part of the POSIX-translation of * filenames in HFS+ (original Mac OS had * ':' as a reserved character, while '/' is * reserved in Mac OS X/POSIX). */ if (nodeName[i] == '/') { nodeName[i] = ':'; } else if (nodeName[i] == ':') { /* Note: This should really be * considered an illegal HFS+ * character. */ nodeName[i] = '/'; } } pathBuilder.append('/').append(nodeName); } else { firstComponent = false; } } } else { pathBuilder = null; } System.out.println( "CNID: " + k.getFileID().toLong() + " " + "Type: " + header.getCompressionType() + " " + "Size: " + header.getFileSize() + (pathBuilder != null ? " Path: " + pathBuilder.toString() : "")); } } else { System.err.println( "[WARNING] Unexpected attributes B-tree " + "node type: " + curNode.getClass()); } } fsHandler.close(); System.exit(0); }
/** * <b>Note that the return value from this function should be interpreted as an unsigned integer, * for instance using Util.unsign(...).</b> */ public int getRawSbBlkCount() { return Util.readIntBE(sbBlkCount); }
/** * <b>Note that the return value from this function should be interpreted as an unsigned integer, * for instance using Util.unsign(...).</b> */ public short getRawSbDevId() { return Util.readShortBE(sbDevId); }
/** Reserved. */ public short getFrFlags() { return Util.readShortBE(frFlags); }
/** * <b>Note that the return value from this function should be interpreted as an unsigned integer, * for instance using Util.unsign(...).</b> */ public short getRawSbSig() { return Util.readShortBE(sbSig); }
public void printFields(PrintStream ps, String prefix) { ps.println(prefix + " xdrStABN: " + Util.unsign(getXdrStABN())); ps.println(prefix + " xdrNumABlks: " + Util.unsign(getXdrNumABlks())); }
/** number of allocation blocks */ public short getXdrNumABlks() { return Util.readShortBE(xdrNumABlks); }
/** first allocation block */ public short getXdrStABN() { return Util.readShortBE(xdrStABN); }
public ExtDescriptor(short xdrStABN, short xdrNumABlks) { System.arraycopy(Util.toByteArrayBE(xdrStABN), 0, this.xdrStABN, 0, 2); System.arraycopy(Util.toByteArrayBE(xdrNumABlks), 0, this.xdrNumABlks, 0, 2); }
/** * The manner in which folders are displayed; this is set by the user with commands from the View * menu of the Finder. */ public short getFrView() { return Util.readShortBE(frView); }
/** * <b>Note that the return value from this function should be interpreted as an unsigned integer, * for instance using Util.unsign(...).</b> */ public short getRawSbBlkSize() { return Util.readShortBE(sbBlkSize); }
/** Device signature. (Should be "ER"...) */ public int getSbSig() { return Util.unsign(getRawSbSig()); }
/** * <b>Note that the return value from this function should be interpreted as an unsigned integer, * for instance using Util.unsign(...).</b> */ public short getRawSbDevType() { return Util.readShortBE(sbDevType); }
/** Block size of the device. */ public int getSbBlkSize() { return Util.unsign(getRawSbBlkSize()); }
/** * <b>Note that the return value from this function should be interpreted as an unsigned integer, * for instance using Util.unsign(...).</b> */ public int getRawSbData() { return Util.readIntBE(sbData); }
/** Number of blocks on the device. */ public long getSbBlkCount() { return Util.unsign(getRawSbBlkCount()); }
/** Reserved. */ public int getSbDevId() { return Util.unsign(getRawSbDevId()); }
/** Reserved. */ public long getSbData() { return Util.unsign(getRawSbData()); }
/** * Re-reads the contents of the .plist file and updates the cached data. * * @throws IOException if there is an I/O error, or the data in the plist is invalid. */ protected void refresh() throws IOException { long fileLength = file.length(); if (fileLength > Integer.MAX_VALUE) throw new ArrayIndexOutOfBoundsException( "Info.plist is " + "unreasonably large and doesn't fit in memory."); byte[] plistData = new byte[(int) fileLength]; int bytesRead = file.read(plistData); if (bytesRead != fileLength) throw new IOException( "Failed to read entire file. Read " + bytesRead + "/" + fileLength + " bytes."); XmlPlist plist = new XmlPlist(plistData, true); PlistNode dictNode = plist.getRootNode().cd("dict"); if (dictNode == null) { throw new IOException("Malformed Info.plist file: No 'dict' " + "element at root."); } final String cfBundleInfoDictionaryVersionKey = "CFBundleInfoDictionaryVersion"; final String bandSizeKey = "band-size"; final String bundleBackingstoreVersionKey = "bundle-backingstore-version"; final String diskImageBundleTypeKey = "diskimage-bundle-type"; final String sizeKey = "size"; Reader cfBundleInfoDictionaryVersionReader = dictNode.getKeyValue(cfBundleInfoDictionaryVersionKey); Reader bandSizeReader = dictNode.getKeyValue(bandSizeKey); Reader bundleBackingstoreVersionReader = dictNode.getKeyValue(bundleBackingstoreVersionKey); Reader diskImageBundleTypeReader = dictNode.getKeyValue(diskImageBundleTypeKey); Reader sizeReader = dictNode.getKeyValue(sizeKey); if (cfBundleInfoDictionaryVersionReader == null) throw new IOException( "Could not find '" + cfBundleInfoDictionaryVersionKey + "' key in Info.plist " + "file."); if (bandSizeReader == null) throw new IOException("Could not find '" + bandSizeKey + "' key " + "in Info.plist file."); if (bundleBackingstoreVersionReader == null) throw new IOException( "Could not find '" + bundleBackingstoreVersionKey + "' key in Info.plist file."); if (diskImageBundleTypeReader == null) throw new IOException( "Could not find '" + diskImageBundleTypeKey + "' key in Info.plist file."); if (sizeReader == null) throw new IOException("Could not find '" + sizeKey + "' key in " + "Info.plist file."); // We ignore the value of the dictionary version. // String cfBundleInfoDictionaryVersionString = // Util.readFully(cfBundleInfoDictionaryVersionReader); String bandSizeString = Util.readFully(bandSizeReader); String bundleBackingstoreVersionString = Util.readFully(bundleBackingstoreVersionReader); String diskImageBundleTypeString = Util.readFully(diskImageBundleTypeReader); String sizeString = Util.readFully(sizeReader); if (!diskImageBundleTypeString.equals("com.apple.diskimage.sparsebundle")) { throw new IOException( "Unexpected value for '" + diskImageBundleTypeKey + "': " + diskImageBundleTypeString); } if (!bundleBackingstoreVersionString.equals("1")) { throw new IOException("Unknown backing store version: " + bundleBackingstoreVersionString); } final long bandSizeLong; try { bandSizeLong = Long.parseLong(bandSizeString); } catch (NumberFormatException nfe) { throw new IOException("Illegal numeric value for " + bandSizeKey + ": " + bandSizeString); } final long sizeLong; try { sizeLong = Long.parseLong(sizeString); } catch (NumberFormatException nfe) { throw new IOException("Illegal numeric value for " + sizeKey + ": " + sizeString); } this.bandSize = bandSizeLong; this.size = sizeLong; }
/** Number of driver descriptor entries. Won't be more than 31 in a valid structure. */ public int getSbDrvrCount() { return Util.unsign(getRawSbDrvrCount()); }
public void printFields(PrintStream ps, String prefix) { ps.println(prefix + " key:"); key.print(ps, prefix + " "); ps.println(prefix + " index: " + Util.unsign(getIndex())); }
private long getDataPos(ReferenceListEntry entry) { ResourceHeader header = getHeader(); return Util.unsign(header.getDataOffset()) + entry.getResourceDataOffset(); }