public void split() throws IOException {
    List<ObjectPath> pathTable = asset.getPaths();
    TypeTree typeTree = asset.getTypeTree();

    // assets with just one object can't be split any further
    if (pathTable.size() == 1) {
      L.warning("Asset doesn't contain sub-assets!");
      return;
    }

    for (ObjectPath path : pathTable) {
      // skip filtered classes
      if (cf != null && !cf.accept(path)) {
        continue;
      }

      String className = ClassID.getNameForID(path.getClassID(), true);

      AssetFile subAsset = new AssetFile();
      subAsset.getHeader().setFormat(asset.getHeader().getFormat());

      ObjectPath subFieldPath = new ObjectPath();
      subFieldPath.setClassID1(path.getClassID1());
      subFieldPath.setClassID2(path.getClassID2());
      subFieldPath.setLength(path.getLength());
      subFieldPath.setOffset(0);
      subFieldPath.setPathID(1);
      subAsset.getPaths().add(subFieldPath);

      TypeTree subTypeTree = subAsset.getTypeTree();
      subTypeTree.setEngineVersion(typeTree.getEngineVersion());
      subTypeTree.setVersion(-2);
      subTypeTree.setFormat(typeTree.getFormat());
      subTypeTree.getFields().put(path.getClassID(), typeTree.getFields().get(path.getClassID()));

      subAsset.setDataBuffer(asset.getPathBuffer(path));

      Path subAssetDir = outputDir.resolve(className);
      if (Files.notExists(subAssetDir)) {
        Files.createDirectories(subAssetDir);
      }

      // probe asset name
      String subAssetName = getObjectName(asset, path);
      if (subAssetName != null) {
        // remove any chars that could cause troubles on various file systems
        subAssetName = FilenameSanitizer.sanitizeName(subAssetName);
      } else {
        // use numeric names
        subAssetName = String.format("%06d", path.getPathID());
      }
      subAssetName += ".asset";

      Path subAssetFile = subAssetDir.resolve(subAssetName);
      if (Files.notExists(subAssetFile)) {
        L.log(Level.INFO, "Writing {0}", subAssetFile);
        subAsset.save(subAssetFile);
      }
    }
  }
  private void testWrite(AssetFile asset) throws IOException {
    Path tmpFile = Files.createTempFile("disunity", null);

    try {
      asset.save(tmpFile);

      if (!FileUtils.contentEquals(asset.getSourceFile().toFile(), tmpFile.toFile())) {
        throw new IOException("Files are not equal");
      }
    } finally {
      Files.deleteIfExists(tmpFile);
    }
  }
  @Override
  public void processAsset(AssetFile asset) throws IOException {
    Path assetFile = asset.getSourceFile();
    Path assetDir = assetFile.getParent();
    String assetFileName = assetFile.getFileName().toString();
    String assetPath;

    if (assetDir == null) {
      assetPath = "";
    } else {
      assetPath = assetDir.toAbsolutePath().toString();
      assetPath = FilenameUtils.separatorsToUnix(assetPath) + "/";
    }

    // fix path for all assets with (shared)assets extension
    boolean changed = false;
    for (AssetRef ref : asset.getReferences()) {
      Path refFile = Paths.get(ref.getFilePath());
      String refExt = FilenameUtils.getExtension(refFile.getFileName().toString());
      if (refExt.endsWith("assets") && Files.notExists(refFile)) {
        String filePathOld = ref.getFilePath();
        String filePathNew = assetPath + FilenameUtils.getName(ref.getFilePath());
        Path refFileNew = Paths.get(filePathNew);

        if (Files.exists(refFileNew)) {
          L.log(Level.FINE, "Fixed reference: {0} -> {1}", new Object[] {filePathOld, filePathNew});
          ref.setFilePath(filePathNew);
          changed = true;
        } else {
          L.log(Level.FINE, "Fixed reference not found: {0}", refFileNew);
        }
      }
    }

    if (!changed) {
      L.fine("No references changed, skipping saving");
      return;
    }

    // create backup by renaming the original file
    Path assetFileBackup = assetFile.resolveSibling(assetFileName + ".bak");
    Files.move(assetFile, assetFileBackup, StandardCopyOption.REPLACE_EXISTING);

    // save asset
    asset.save(assetFile);
  }