/* * WorldEdit, a Minecraft world manipulation toolkit * Copyright (C) sk89q * Copyright (C) WorldEdit team and contributors * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ // $Id$ package com.sk89q.worldedit.world.snapshot; import com.sk89q.worldedit.world.storage.MissingWorldException; import javax.annotation.Nullable; import java.io.File; import java.io.FilenameFilter; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.List; /** * A repository contains zero or more snapshots. */ public class SnapshotRepository { protected File dir; protected List dateParsers = new ArrayList<>(); /** * Create a new instance of a repository. * * @param dir the directory */ public SnapshotRepository(File dir) { this.dir = dir; // If folder doesn't exist, make it dir.mkdirs(); dateParsers.add(new YYMMDDHHIISSParser()); dateParsers.add(new ModificationTimerParser()); } /** * Create a new instance of a repository. * * @param dir the directory */ public SnapshotRepository(String dir) { this(new File(dir)); } /** * Get a list of snapshots in a directory. The newest snapshot is * near the top of the array. * * @param newestFirst true to get the newest first * @return a list of snapshots */ public List getSnapshots(boolean newestFirst, String worldName) throws MissingWorldException { FilenameFilter filter = (dir, name) -> { File f = new File(dir, name); return isValidSnapshot(f); }; File[] snapshotFiles = dir.listFiles(); if (snapshotFiles == null) { throw new MissingWorldException(worldName); } List list = new ArrayList<>(snapshotFiles.length); for (File file : snapshotFiles) { if (isValidSnapshot(file)) { Snapshot snapshot = new Snapshot(this, file.getName()); if (snapshot.containsWorld(worldName)) { detectDate(snapshot); list.add(snapshot); } } else if (file.isDirectory() && file.getName().equalsIgnoreCase(worldName)) { for (String name : file.list(filter)) { Snapshot snapshot = new Snapshot(this, file.getName() + "/" + name); detectDate(snapshot); list.add(snapshot); } } } if (newestFirst) { list.sort(Collections.reverseOrder()); } else { Collections.sort(list); } return list; } /** * Get the first snapshot after a date. * * @param date a date * @return a snapshot or null */ @Nullable public Snapshot getSnapshotAfter(Calendar date, String world) throws MissingWorldException { List snapshots = getSnapshots(true, world); Snapshot last = null; for (Snapshot snapshot : snapshots) { if (snapshot.getDate() != null && snapshot.getDate().before(date)) { return last; } last = snapshot; } return last; } /** * Get the first snapshot before a date. * * @param date a date * @return a snapshot or null */ @Nullable public Snapshot getSnapshotBefore(Calendar date, String world) throws MissingWorldException { List snapshots = getSnapshots(false, world); Snapshot last = null; for (Snapshot snapshot : snapshots) { if (snapshot.getDate().after(date)) { return last; } last = snapshot; } return last; } /** * Attempt to detect a snapshot's date and assign it. * * @param snapshot the snapshot */ protected void detectDate(Snapshot snapshot) { for (SnapshotDateParser parser : dateParsers) { Calendar date = parser.detectDate(snapshot.getFile()); if (date != null) { snapshot.setDate(date); return; } } snapshot.setDate(null); } /** * Get the default snapshot. * * @param world the world name * @return a snapshot or null */ @Nullable public Snapshot getDefaultSnapshot(String world) throws MissingWorldException { List snapshots = getSnapshots(true, world); if (snapshots.isEmpty()) { return null; } return snapshots.get(0); } /** * Check to see if a snapshot is valid. * * @param snapshot a snapshot name * @return whether it is a valid snapshot */ public boolean isValidSnapshotName(String snapshot) { return isValidSnapshot(new File(dir, snapshot)); } /** * Check to see if a snapshot is valid. * * @param file the file to the snapshot * @return whether it is a valid snapshot */ protected boolean isValidSnapshot(File file) { if (!file.getName().matches("^[A-Za-z0-9_\\- \\./\\\\'\\$@~!%\\^\\*\\(\\)\\[\\]\\+\\{\\},\\?]+$")) { return false; } return (file.isDirectory() && (new File(file, "level.dat")).exists()) || (file.isFile() && (file.getName().toLowerCase().endsWith(".zip") || file.getName().toLowerCase().endsWith(".tar.bz2") || file.getName().toLowerCase().endsWith(".tar.gz") || file.getName().toLowerCase().endsWith(".tar"))); } /** * Get a snapshot. * * @param name the name of the snapshot * @return a snapshot * @throws InvalidSnapshotException if the snapshot is invalid */ public Snapshot getSnapshot(String name) throws InvalidSnapshotException { if (!isValidSnapshotName(name)) { throw new InvalidSnapshotException(); } return new Snapshot(this, name); } /** * Get the snapshot directory. * * @return a path */ public File getDirectory() { return dir; } }