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);
 }
예제 #6
0
 public int getIndex() {
   return Util.readIntBE(index);
 }
예제 #7
0
 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);
 }
예제 #9
0
  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);
 }
예제 #12
0
 /** 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);
 }
예제 #14
0
 public void printFields(PrintStream ps, String prefix) {
   ps.println(prefix + " xdrStABN: " + Util.unsign(getXdrStABN()));
   ps.println(prefix + " xdrNumABlks: " + Util.unsign(getXdrNumABlks()));
 }
예제 #15
0
 /** number of allocation blocks */
 public short getXdrNumABlks() {
   return Util.readShortBE(xdrNumABlks);
 }
예제 #16
0
 /** first allocation block */
 public short getXdrStABN() {
   return Util.readShortBE(xdrStABN);
 }
예제 #17
0
 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);
 }
예제 #18
0
 /**
  * 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());
 }
예제 #27
0
  /**
   * 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());
 }
예제 #29
0
 public void printFields(PrintStream ps, String prefix) {
   ps.println(prefix + " key:");
   key.print(ps, prefix + "  ");
   ps.println(prefix + " index: " + Util.unsign(getIndex()));
 }
예제 #30
0
 private long getDataPos(ReferenceListEntry entry) {
   ResourceHeader header = getHeader();
   return Util.unsign(header.getDataOffset()) + entry.getResourceDataOffset();
 }