mirror of
https://github.com/xpipe-io/xpipe.git
synced 2026-08-13 04:51:03 +00:00
Various small fixes
This commit is contained in:
@@ -1,49 +1,111 @@
|
||||
package io.xpipe.core.charsetter;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
import io.xpipe.core.util.Identifiers;
|
||||
import lombok.Value;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Value
|
||||
public class StreamCharset {
|
||||
|
||||
public static final StreamCharset UTF8 = new StreamCharset(StandardCharsets.UTF_8, null);
|
||||
public static final StreamCharset UTF8_BOM =
|
||||
new StreamCharset(StandardCharsets.UTF_8, new byte[] {(byte) 0xEF, (byte) 0xBB, (byte) 0xBF});
|
||||
public static final StreamCharset UTF16_BE = new StreamCharset(StandardCharsets.UTF_16BE, null);
|
||||
public static final StreamCharset UTF16_BE_BOM =
|
||||
new StreamCharset(StandardCharsets.UTF_16BE, new byte[] {(byte) 0xFE, (byte) 0xFF});
|
||||
public static final StreamCharset UTF16_LE = new StreamCharset(StandardCharsets.UTF_16LE, null);
|
||||
public static final StreamCharset UTF16_LE_BOM =
|
||||
new StreamCharset(StandardCharsets.UTF_16LE, new byte[] {(byte) 0xFF, (byte) 0xFE});
|
||||
public static final StreamCharset UTF8 =
|
||||
new StreamCharset(StandardCharsets.UTF_8, null, Identifiers.get("utf", "8"));
|
||||
|
||||
public static final StreamCharset UTF32_LE = new StreamCharset(Charset.forName("utf-32le"), null);
|
||||
public static final StreamCharset UTF32_LE_BOM =
|
||||
new StreamCharset(Charset.forName("utf-32le"), new byte[] {0x00, 0x00, (byte) 0xFE, (byte) 0xFF});
|
||||
public static final StreamCharset UTF32_BE = new StreamCharset(Charset.forName("utf-32be"), null);
|
||||
public static final StreamCharset UTF32_BE_BOM =
|
||||
new StreamCharset(Charset.forName("utf-32be"), new byte[] {(byte) 0xFF, (byte) 0xFE, 0x00, 0x00, });
|
||||
public static final StreamCharset UTF8_BOM = new StreamCharset(
|
||||
StandardCharsets.UTF_8,
|
||||
new byte[] {(byte) 0xEF, (byte) 0xBB, (byte) 0xBF},
|
||||
Identifiers.get("utf", "8", "bom"));
|
||||
|
||||
// ======
|
||||
// UTF-16
|
||||
// ======
|
||||
|
||||
public static final StreamCharset UTF16_BE =
|
||||
new StreamCharset(StandardCharsets.UTF_16BE, null, Identifiers.get("utf", "16", "be"));
|
||||
|
||||
public static final StreamCharset UTF16_BE_BOM = new StreamCharset(
|
||||
StandardCharsets.UTF_16BE,
|
||||
new byte[] {(byte) 0xFE, (byte) 0xFF},
|
||||
Identifiers.get("utf", "16", "be", "bom"));
|
||||
|
||||
public static final StreamCharset UTF16_LE =
|
||||
new StreamCharset(StandardCharsets.UTF_16LE, null, Identifiers.get("utf", "16", "le"));
|
||||
|
||||
public static final StreamCharset UTF16_LE_BOM = new StreamCharset(
|
||||
StandardCharsets.UTF_16LE,
|
||||
new byte[] {(byte) 0xFF, (byte) 0xFE},
|
||||
Identifiers.get("utf", "16", "le", "bom"));
|
||||
|
||||
public static final StreamCharset UTF16 =
|
||||
new StreamCharset(StandardCharsets.UTF_16, null, Identifiers.get("utf", "16"));
|
||||
|
||||
public static final StreamCharset UTF16_BOM = new StreamCharset(
|
||||
StandardCharsets.UTF_16,
|
||||
ByteOrder.nativeOrder().equals(ByteOrder.BIG_ENDIAN)
|
||||
? UTF16_BE_BOM.getByteOrderMark()
|
||||
: UTF16_LE_BOM.getByteOrderMark(),
|
||||
Identifiers.get("utf", "16", "bom"));
|
||||
|
||||
// ======
|
||||
// UTF-32
|
||||
// ======
|
||||
|
||||
public static final StreamCharset UTF32_LE =
|
||||
new StreamCharset(Charset.forName("utf-32le"), null, Identifiers.get("utf", "32", "le"));
|
||||
|
||||
public static final StreamCharset UTF32_LE_BOM = new StreamCharset(
|
||||
Charset.forName("utf-32le"),
|
||||
new byte[] {0x00, 0x00, (byte) 0xFE, (byte) 0xFF},
|
||||
Identifiers.get("utf", "32", "le", "bom"));
|
||||
|
||||
public static final StreamCharset UTF32_BE =
|
||||
new StreamCharset(Charset.forName("utf-32be"), null, Identifiers.get("utf", "32", "be"));
|
||||
|
||||
public static final StreamCharset UTF32_BE_BOM = new StreamCharset(
|
||||
Charset.forName("utf-32be"),
|
||||
new byte[] {
|
||||
(byte) 0xFF, (byte) 0xFE, 0x00, 0x00,
|
||||
},
|
||||
Identifiers.get("utf", "32", "be", "bom"));
|
||||
|
||||
public static final List<StreamCharset> COMMON = List.of(
|
||||
UTF8,
|
||||
UTF8_BOM,
|
||||
UTF16_BE,
|
||||
UTF16_BE_BOM,
|
||||
UTF16_LE,
|
||||
UTF16_LE_BOM,
|
||||
new StreamCharset(StandardCharsets.US_ASCII, null),
|
||||
new StreamCharset(StandardCharsets.ISO_8859_1, null),
|
||||
new StreamCharset(Charset.forName("Windows-1251"), null),
|
||||
new StreamCharset(Charset.forName("Windows-1252"), null));
|
||||
private static final List<StreamCharset> RARE_KNOWN = List.of(UTF32_LE, UTF32_LE_BOM, UTF32_BE, UTF32_BE_BOM);
|
||||
UTF16,
|
||||
UTF16_BOM,
|
||||
new StreamCharset(
|
||||
StandardCharsets.US_ASCII,
|
||||
null,
|
||||
Identifiers.join(Identifiers.get("ascii"), Identifiers.get("us", "ascii"))),
|
||||
new StreamCharset(
|
||||
StandardCharsets.ISO_8859_1,
|
||||
null,
|
||||
Identifiers.join(
|
||||
Identifiers.get("iso", "8859"),
|
||||
Identifiers.get("iso", "8859", "1"),
|
||||
Identifiers.get("8859"),
|
||||
Identifiers.get("8859", "1"))),
|
||||
new StreamCharset(
|
||||
Charset.forName("Windows-1251"),
|
||||
null,
|
||||
Identifiers.join(Identifiers.get("windows", "1251"), Identifiers.get("1251"))),
|
||||
new StreamCharset(
|
||||
Charset.forName("Windows-1252"),
|
||||
null,
|
||||
Identifiers.join(Identifiers.get("windows", "1252"), Identifiers.get("1252"))));
|
||||
|
||||
private static final List<StreamCharset> RARE_NAMED =
|
||||
List.of(UTF16_LE, UTF16_LE_BOM, UTF16_BE, UTF16_BE_BOM, UTF32_LE, UTF32_LE_BOM, UTF32_BE, UTF32_BE_BOM);
|
||||
|
||||
public static final List<StreamCharset> RARE = Stream.concat(
|
||||
RARE_KNOWN.stream(),
|
||||
RARE_NAMED.stream(),
|
||||
Charset.availableCharsets().values().stream()
|
||||
.filter(charset -> !charset.equals(StandardCharsets.UTF_16)
|
||||
&& !charset.equals(Charset.forName("utf-32"))
|
||||
@@ -52,31 +114,59 @@ public class StreamCharset {
|
||||
&& !charset.displayName().endsWith("-BOM")
|
||||
&& COMMON.stream()
|
||||
.noneMatch(c -> c.getCharset().equals(charset))
|
||||
&& RARE_KNOWN.stream()
|
||||
&& RARE_NAMED.stream()
|
||||
.noneMatch(c -> c.getCharset().equals(charset)))
|
||||
.map(charset -> new StreamCharset(charset, null)))
|
||||
.map(charset -> new StreamCharset(
|
||||
charset,
|
||||
null,
|
||||
Identifiers.get(charset.name().split("-")))))
|
||||
.toList();
|
||||
|
||||
public static final List<StreamCharset> ALL = Stream.concat(COMMON.stream(), RARE.stream()).toList();
|
||||
|
||||
|
||||
|
||||
Charset charset;
|
||||
byte[] byteOrderMark;
|
||||
List<String> names;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof StreamCharset that)) {
|
||||
return false;
|
||||
}
|
||||
return charset.equals(that.charset) && Arrays.equals(byteOrderMark, that.byteOrderMark);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = Objects.hash(charset);
|
||||
result = 31 * result + Arrays.hashCode(byteOrderMark);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static StreamCharset get(Charset charset, boolean byteOrderMark) {
|
||||
return Stream.concat(COMMON.stream(), RARE.stream())
|
||||
return ALL.stream()
|
||||
.filter(streamCharset ->
|
||||
streamCharset.getCharset().equals(charset) && streamCharset.hasByteOrderMark() == byteOrderMark)
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
}
|
||||
|
||||
@JsonCreator
|
||||
public static StreamCharset get(String s) {
|
||||
var byteOrderMark = s.endsWith("-bom");
|
||||
var charset = Charset.forName(s.substring(0, s.length() - (byteOrderMark ? 4 : 0)));
|
||||
return StreamCharset.get(charset, byteOrderMark);
|
||||
var found = ALL.stream().filter(streamCharset -> streamCharset.getNames().contains(s.toLowerCase(Locale.ROOT))).findFirst();
|
||||
if (found.isEmpty()) {
|
||||
throw new IllegalArgumentException("Unknown charset name: " + s);
|
||||
}
|
||||
|
||||
return found.get();
|
||||
}
|
||||
|
||||
@JsonValue
|
||||
public String toString() {
|
||||
return getCharset().name().toLowerCase(Locale.ROOT) + (hasByteOrderMark() ? "-bom" : "");
|
||||
return getNames().get(0);
|
||||
}
|
||||
|
||||
public boolean hasByteOrderMark() {
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package io.xpipe.core.impl;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||
import io.xpipe.core.store.DataFlow;
|
||||
import io.xpipe.core.store.StreamDataStore;
|
||||
import io.xpipe.core.util.DataStateProvider;
|
||||
import io.xpipe.core.util.JacksonizedValue;
|
||||
import lombok.Getter;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@JsonTypeName("internalStream")
|
||||
@SuperBuilder
|
||||
@Jacksonized
|
||||
@Getter
|
||||
public class InternalStreamStore extends JacksonizedValue implements StreamDataStore {
|
||||
|
||||
private final UUID uuid;
|
||||
|
||||
public InternalStreamStore() {
|
||||
this.uuid = UUID.randomUUID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataFlow getFlow() {
|
||||
return DataFlow.INPUT_OUTPUT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> determineDefaultName() {
|
||||
return Optional.of(uuid.toString());
|
||||
}
|
||||
|
||||
private Path getFile() {
|
||||
return DataStateProvider.get().getInternalStreamStore(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Instant> determineLastModified() throws IOException {
|
||||
return Optional.of(Files.getLastModifiedTime(getFile()).toInstant());
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream openInput() throws Exception {
|
||||
return Files.newInputStream(getFile());
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream openOutput() throws Exception {
|
||||
return Files.newOutputStream(getFile());
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import io.xpipe.core.impl.StdinDataStore;
|
||||
import io.xpipe.core.impl.StdoutDataStore;
|
||||
import io.xpipe.core.source.DataSource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -101,7 +102,7 @@ public interface DataStore {
|
||||
/**
|
||||
* Determines the last modified of this data store if this data store supports it.
|
||||
*/
|
||||
default Optional<Instant> determineLastModified() {
|
||||
default Optional<Instant> determineLastModified() throws IOException {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ package io.xpipe.core.util;
|
||||
|
||||
import io.xpipe.core.store.DataStore;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public abstract class DataStateProvider {
|
||||
@@ -22,4 +24,6 @@ public abstract class DataStateProvider {
|
||||
public abstract void putState(DataStore store, String key, Object value);
|
||||
|
||||
public abstract <T> T getState(DataStore store, String key, Class<T> c, Supplier<T> def);
|
||||
|
||||
public abstract Path getInternalStreamStore(UUID id);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package io.xpipe.core.util;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class Identifiers {
|
||||
|
||||
@SafeVarargs
|
||||
public static List<String> join(List<String>... s) {
|
||||
return Arrays.stream(s).flatMap(Collection::stream).toList();
|
||||
}
|
||||
|
||||
public static List<String> get(String... s) {
|
||||
return nameAlternatives(Arrays.asList(s));
|
||||
}
|
||||
|
||||
private static List<String> nameAlternatives(List<String> split) {
|
||||
return List.of(
|
||||
String.join("", split),
|
||||
String.join(" ", split),
|
||||
String.join("_", split),
|
||||
String.join("-", split));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user