Skip to content

Commit

Permalink
Merge pull request #100 from filip26/patch/uri-files
Browse files Browse the repository at this point in the history
[De]Compress Improvements
  • Loading branch information
filip26 authored Jul 27, 2024
2 parents 9dd586b + fac2f5c commit f8e07d0
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 20 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Options:
### `file:/` scheme support

```bash
> ld-cli compress -i file:/home/filip/example.jsonld output.cborld
> ld-cli compress -i file:/home/filip/example.jsonld
```

## Contributing
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/apicatalog/cli/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
}
)
public final class App {

@Option(names = { "-h", "--help" }, usageHelp = true, description = "display help message")
boolean help = false;

Expand Down
51 changes: 38 additions & 13 deletions src/main/java/com/apicatalog/cli/command/CompressCmd.java
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
package com.apicatalog.cli.command;

import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.Callable;

import com.apicatalog.base.Base16;
import com.apicatalog.cborld.CborLd;
import com.apicatalog.cborld.barcode.BarcodesConfig;
import com.apicatalog.cborld.config.DefaultConfig;
import com.apicatalog.cborld.config.V05Config;
import com.apicatalog.cborld.encoder.EncoderConfig;
import com.apicatalog.jsonld.document.Document;
import com.apicatalog.jsonld.document.JsonDocument;
import com.apicatalog.jsonld.json.JsonUtils;
import com.apicatalog.jsonld.loader.DocumentLoader;
import com.apicatalog.jsonld.loader.DocumentLoaderOptions;
import com.apicatalog.jsonld.loader.SchemeRouter;

import jakarta.json.JsonStructure;
import picocli.CommandLine.Command;
import picocli.CommandLine.Model.CommandSpec;
import picocli.CommandLine.Option;
import picocli.CommandLine.Parameters;
import picocli.CommandLine.Spec;

@Command(name = "compress", mixinStandardHelpOptions = false, description = "Compress JSON-LD document into CBOR-LD", sortOptions = true, descriptionHeading = "%n", parameterListHeading = "%nParameters:%n", optionListHeading = "%nOptions:%n")
Expand All @@ -29,10 +31,10 @@ public final class CompressCmd implements Callable<Integer> {
@Option(names = { "-h", "--help" }, hidden = true, usageHelp = true)
boolean help = false;

@Option(names = { "-i", "--input" }, description = "input document IRI")
@Option(names = { "-i", "--input" }, description = "input document IRI or filepath")
URI input = null;

@Parameters(index = "0", arity = "1", description = "output document filename")
@Option(names = { "-o", "--output" }, description = "output document filename, -x is implicit when missing")
String output = null;

@Option(names = { "-b", "--base" }, description = "input document base IRI")
Expand All @@ -44,6 +46,9 @@ public final class CompressCmd implements Callable<Integer> {
@Option(names = { "-m", "--mode" }, description = "processing mode", paramLabel = "default|barcodes|v05")
String mode = "default";

@Option(names = { "-x", "--hex" }, description = "print encoded as hexadecimal bytes")
boolean hex = false;

@Spec
CommandSpec spec;

Expand All @@ -56,37 +61,57 @@ public Integer call() throws Exception {
final Document document;

if (input != null) {
final DocumentLoader loader = SchemeRouter.defaultInstance();
document = loader.loadDocument(input, new DocumentLoaderOptions());
if (input.isAbsolute()) {
final DocumentLoader loader = SchemeRouter.defaultInstance();
document = loader.loadDocument(input, new DocumentLoaderOptions());
} else {
document = JsonDocument.of(new ByteArrayInputStream(Files.readAllBytes(Path.of(input.toString()))));
}

} else {
document = JsonDocument.of(System.in);
}

final JsonStructure json = document.getJsonContent()
var json = document.getJsonContent()
.orElseThrow(() -> new IllegalArgumentException("Invalid input document. JSON document expected but got [" + document.getContentType() + "]."));

if (JsonUtils.isNotObject(json)) {
throw new IllegalArgumentException("The input docunent root is not JSON object but [" + json.getValueType() + "].");
}

final EncoderConfig config = switch (mode) {
var config = switch (mode) {
case "barcodes" -> BarcodesConfig.INSTANCE;
case "v05" -> V05Config.INSTANCE;
default -> DefaultConfig.INSTANCE;
};

final byte[] encoded = CborLd.createEncoder(config)
var encoded = CborLd.createEncoder(config)
.base(base)
.compactArray(!keepArrays)
.build()
.encode(json.asJsonObject());

try (FileOutputStream os = new FileOutputStream(output)) {
os.write(encoded);
os.flush();
if (output == null) {
System.out.write(encode(encoded, true));

} else {
try (var os = new FileOutputStream(output)) {
os.write(encode(encoded, hex));
os.flush();
}
}

return spec.exitCodeOnSuccess();
}

static byte[] encode(byte[] encoded, boolean hex) throws IOException {
return hex
? Base16.encode(encoded, Base16.ALPHABET_LOWER).getBytes()
: encoded;
}

static final String toString(byte value) {
return String.format("%02x", value);
}

}
60 changes: 55 additions & 5 deletions src/main/java/com/apicatalog/cli/command/DecompressCmd.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package com.apicatalog.cli.command;

import java.io.File;
import java.net.URI;
import java.net.http.HttpClient.Redirect;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse.BodyHandlers;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.concurrent.Callable;

import com.apicatalog.base.Base16;
import com.apicatalog.cborld.CborLd;
import com.apicatalog.cborld.barcode.BarcodesConfig;
import com.apicatalog.cborld.config.DefaultConfig;
Expand All @@ -17,7 +22,6 @@
import picocli.CommandLine.Command;
import picocli.CommandLine.Model.CommandSpec;
import picocli.CommandLine.Option;
import picocli.CommandLine.Parameters;
import picocli.CommandLine.Spec;

@Command(name = "decompress", mixinStandardHelpOptions = false, description = "Decompress CBOR-LD document into JSON-LD", sortOptions = true, descriptionHeading = "%n", parameterListHeading = "%nParameters:%n", optionListHeading = "%nOptions:%n")
Expand All @@ -29,8 +33,8 @@ public final class DecompressCmd implements Callable<Integer> {
@Option(names = { "-p", "--pretty" }, description = "pretty print output JSON")
boolean pretty = false;

@Parameters(index = "0", arity = "1", description = "input document filename")
File input = null;
@Option(names = { "-i", "--input" }, description = "input document IRI or filepath, -x is implicit when missing")
URI input = null;

@Option(names = { "-b", "--base" }, description = "input document base IRI")
URI base = null;
Expand All @@ -41,16 +45,21 @@ public final class DecompressCmd implements Callable<Integer> {
@Option(names = { "-m", "--mode" }, description = "processing mode", paramLabel = "default|barcodes|v05")
String mode = "default";

@Option(names = { "-x", "--hex" }, description = "input is encoded as hexadecimal bytes")
boolean hex = false;

@Spec
CommandSpec spec;

static final java.net.http.HttpClient CLIENT = java.net.http.HttpClient.newBuilder().followRedirects(Redirect.ALWAYS).build();

private DecompressCmd() {
}

@Override
public Integer call() throws Exception {

final byte[] encoded = Files.readAllBytes(input.toPath());
var encoded = decode(fetch());

final DecoderConfig config = switch (mode) {
case "barcodes" -> BarcodesConfig.INSTANCE;
Expand All @@ -68,4 +77,45 @@ public Integer call() throws Exception {

return spec.exitCodeOnSuccess();
}

byte[] fetch() throws Exception {
if (input == null) {
hex = true;
return System.in.readAllBytes();
}

if (input.isAbsolute()) {
if ("file".equalsIgnoreCase(input.getScheme())) {
return Files.readAllBytes(Path.of(input));
}
return fetch(input);
}
return Files.readAllBytes(Path.of(input.toString()));
}

static byte[] fetch(URI uri) throws Exception {

var request = HttpRequest.newBuilder()
.GET()
.uri(uri)
.header("Accept", "*/*")
.timeout(Duration.ofMinutes(1));

var response = CLIENT.send(request.build(), BodyHandlers.ofInputStream());

if (response.statusCode() != 200) {
throw new IllegalArgumentException("The [" + uri + "] has returned code " + response.statusCode() + ", expected 200 OK");
}

try (var is = response.body()) {
return is.readAllBytes();
}
}

byte[] decode(byte[] data) {
if (hex) {
return Base16.decode(new String(data).strip());
}
return data;
}
}

0 comments on commit f8e07d0

Please sign in to comment.