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); }
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); }