blob: dbbfdaea639a75d8a5039f2b0f340d2e568f313a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016, 2019 1C-Soft LLC.
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Vladimir Piskarev (1C) - initial API and implementation
*******************************************************************************/
package org.eclipse.handly.snapshot;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import org.eclipse.core.filebuffers.ITextFileBufferManager;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.handly.internal.Activator;
/**
* A snapshot of a text {@link IFileStore}. Thread-safe.
*/
public final class TextFileStoreSnapshot
extends TextFileSnapshotBase
{
private final IFileStore fileStore;
private final long lastModified;
private final IStatus status;
private String contents;
/**
* Constructs a new snapshot of the given text file store. The snapshot may
* use a default charset for decoding the file store's contents if a more
* specific charset could not be detected for the file store.
*
* @param fileStore must not be <code>null</code>
*/
public TextFileStoreSnapshot(IFileStore fileStore)
{
this(fileStore, (String)null);
}
/**
* Constructs a new snapshot of the given text file store using the given
* charset for decoding the file store's contents.
*
* @param fileStore must not be <code>null</code>
* @param charset must not be <code>null</code>
*/
public TextFileStoreSnapshot(IFileStore fileStore, Charset charset)
{
this(fileStore, charset.name());
}
private TextFileStoreSnapshot(IFileStore fileStore, String charset)
{
if (fileStore == null)
throw new IllegalArgumentException();
this.fileStore = fileStore;
this.lastModified = getLastModified(fileStore);
if (this.lastModified == EFS.NONE)
{
this.status = Status.OK_STATUS;
this.contents = ""; //$NON-NLS-1$
}
else
{
IStatus status = Status.OK_STATUS;
String contents = null;
try
{
contents = readContents(fileStore, charset);
}
catch (CoreException e)
{
Activator.logError(e);
status = Activator.createErrorStatus(e.getMessage(), e);
}
this.status = status;
this.contents = contents;
}
}
@Override
public synchronized String getContents()
{
if (contents != null && lastModified != getLastModified(fileStore))
contents = null;
return contents;
}
@Override
public IStatus getStatus()
{
return status;
}
@Override
public boolean exists()
{
return lastModified != EFS.NONE;
}
@Override
protected Boolean predictEquality(Snapshot other)
{
if (lastModified != getLastModified(fileStore) || !status.isOK())
return false; // expired
return null;
}
private static String readContents(IFileStore fileStore, String charset)
throws CoreException
{
if (charset == null)
charset = detectCharset(fileStore);
try (
InputStream stream = fileStore.openInputStream(EFS.NONE, null);
InputStreamReader reader = new InputStreamReader(stream, charset))
{
return String.valueOf(getInputStreamAsCharArray(stream, reader));
}
catch (IOException e)
{
throw new CoreException(Activator.createErrorStatus(e.getMessage(),
e));
}
}
private static String detectCharset(IFileStore fileStore)
throws CoreException
{
String charset = null;
try (InputStream contents = fileStore.openInputStream(EFS.NONE, null))
{
charset = getCharset(contents, fileStore.getName());
}
catch (IOException e)
{
throw new CoreException(Activator.createErrorStatus(e.getMessage(),
e));
}
if (charset == null)
charset = ITextFileBufferManager.DEFAULT.getDefaultEncoding();
return charset;
}
private static long getLastModified(IFileStore fileStore)
{
return fileStore.fetchInfo().getLastModified();
}
}