Skip to content

Commit

Permalink
Add CBOR-LD custom dictionaries (#102)
Browse files Browse the repository at this point in the history
  • Loading branch information
filip26 committed Jul 30, 2024
1 parent 30a5db7 commit 53c81b1
Show file tree
Hide file tree
Showing 10 changed files with 154 additions and 106 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ buildNumber.properties
*.swp

/out.cborld
/o.cborld
/ex.jsonld
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ Options:
> ld-cli compress -i file:/home/filip/example.jsonld
```

### Custom CBOR-LD dictionaries
```bash
> ld-cli decompress --pretty --dictionary=./utopia-barcodes-dictionary-example.json <<< 'd90664a60183198000198001198002189d82187618a418b8a3189c18a618ce18b218d01ae592208118baa2189c18a018a8447582002018be18aa18c0a5189c186c18d60418e018e618e258417ab7c2e56b49e2cce62184ce26818e15a8b173164401b5d3bb93ffd6d2b5eb8f6ac0971502ae3dd49d17ec66528164034c912685b8111bc04cdc9ec13dbadd91cc18e418ac'
```

## Contributing

All PR's welcome!
Expand Down
22 changes: 13 additions & 9 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,13 @@

<titanium.version>1.4.1</titanium.version>
<iridium.version>0.2.2</iridium.version>
<jakarta.json-p.version>2.0.1</jakarta.json-p.version>
<jakarta.json.version>2.0.1</jakarta.json.version>

<graal.version>24.0.2</graal.version>
<picocli.version>4.7.6</picocli.version>
<picocli-jansi-graalvm.version>1.2.0</picocli-jansi-graalvm.version>

<jansi.version>2.4.1</jansi.version>
<!-- <jansi.version>1.18</jansi.version>-->

<junit.jupiter.version>5.10.3</junit.jupiter.version>
</properties>
Expand All @@ -54,10 +53,15 @@
<version>${iridium.version}</version>
</dependency>

<dependency>
<groupId>jakarta.json</groupId>
<artifactId>jakarta.json-api</artifactId>
<version>${jakarta.json.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.json</artifactId>
<version>${jakarta.json-p.version}</version>
<version>${jakarta.json.version}</version>
</dependency>

<dependency>
Expand Down Expand Up @@ -184,18 +188,18 @@
<version>0.10.2</version>
<extensions>true</extensions>
<configuration>
<!-- <imageName>${command.name}</imageName>-->
<!-- <mainClass>${mainClass}</mainClass>-->
<!-- <imageName>${command.name}</imageName>-->
<!-- <mainClass>${mainClass}</mainClass>-->
<buildArgs>&#45;&#45;no-server &#45;&#45;no-fallback
&#45;&#45;report-unsupported-elements-at-runtime
&#45;H:+UnlockExperimentalVMOptions
&#45;H:+ReportExceptionStackTraces
&#45;H:+AddAllCharsets
&#45;H:+AddAllCharsets
&#45;H:ReflectionConfigurationFiles=${project.basedir}/graal.json
&#45;H:IncludeResourceBundles=org.glassfish.json.messages
&#45;H:IncludeResources=.*/.*jsonld$</buildArgs>
</configuration>

<executions>
<execution>
<id>build-native</id>
Expand All @@ -212,7 +216,7 @@
<phase>test</phase>
</execution>
</executions>
</plugin>
</plugin>
</plugins>
</build>
</profile>
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/com/apicatalog/cli/JsonCborConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.apicatalog.cli;

public class JsonCborConfig {

}
77 changes: 77 additions & 0 deletions src/main/java/com/apicatalog/cli/JsonCborDictionary.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.apicatalog.cli;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;

import com.apicatalog.cborld.document.DocumentDictionary;
import com.apicatalog.cborld.document.DocumentDictionaryBuilder;
import com.apicatalog.jsonld.JsonLdError;
import com.apicatalog.jsonld.document.Document;
import com.apicatalog.jsonld.loader.DocumentLoader;
import com.apicatalog.jsonld.loader.DocumentLoaderOptions;
import com.apicatalog.jsonld.loader.SchemeRouter;

import jakarta.json.Json;
import jakarta.json.JsonNumber;
import jakarta.json.JsonObject;
import jakarta.json.stream.JsonParser;

public class JsonCborDictionary {

public static DocumentDictionary of(URI input) throws IOException, JsonLdError {
if (input.isAbsolute()) {
final DocumentLoader loader = SchemeRouter.defaultInstance();
return of(loader.loadDocument(input, new DocumentLoaderOptions()));
}
return of(new ByteArrayInputStream(Files.readAllBytes(Path.of(input.toString()))));
}

public static DocumentDictionary of(Document doc) {
return of(doc.getJsonContent().orElseThrow(() -> new IllegalArgumentException("Invalid dictionary")).asJsonObject());
}

public static DocumentDictionary of(InputStream is) {
return of(parse(is));
}

public static DocumentDictionary of(JsonObject json) {
var builder = DocumentDictionaryBuilder.create(json.getInt("code"));

for (var item : json.entrySet()) {
switch (item.getKey()) {
case "code":
continue;
case "context":
item.getValue().asJsonObject().entrySet()
.forEach(e -> builder.context(
((JsonNumber) e.getValue()).intValue(),
e.getKey()));
default:
item.getValue().asJsonObject().entrySet()
.forEach(e -> builder.type(
item.getKey(),
((JsonNumber) e.getValue()).intValue(),
e.getKey()));
}
}

return builder.build();
}

public static JsonObject parse(InputStream json) {
try (final JsonParser parser = Json.createParser(json)) {

if (!parser.hasNext()) {
throw new IllegalArgumentException("Invalid dictionary definition");
}

parser.next();

return parser.getObject();
}
}
}
47 changes: 0 additions & 47 deletions src/main/java/com/apicatalog/cli/JsonDictionary.java

This file was deleted.

19 changes: 13 additions & 6 deletions src/main/java/com/apicatalog/cli/command/CompressCmd.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@

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.cli.JsonCborDictionary;
import com.apicatalog.jsonld.document.Document;
import com.apicatalog.jsonld.document.JsonDocument;
import com.apicatalog.jsonld.json.JsonUtils;
Expand Down Expand Up @@ -43,9 +43,12 @@ public final class CompressCmd implements Callable<Integer> {
@Option(names = { "-a", "--keep-arrays" }, description = "keep arrays with just one element")
boolean keepArrays = false;

@Option(names = { "-m", "--mode" }, description = "processing mode", paramLabel = "default|barcodes|v05")
@Option(names = { "-m", "--mode" }, description = "processing mode", paramLabel = "default|v05")
String mode = "default";

@Option(names = { "-d", "--dictionary" }, description = "a custom dictionary (JSON) location")
URI dictionary = null;

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

Expand Down Expand Up @@ -80,14 +83,19 @@ public Integer call() throws Exception {
}

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

var encoded = CborLd.createEncoder(config)
var encoder = CborLd.createEncoder(config)
.base(base)
.compactArray(!keepArrays)
.compactArray(!keepArrays);

if (dictionary != null) {
encoder.dictionary(JsonCborDictionary.of(dictionary));
}

var encoded = encoder
.build()
.encode(json.asJsonObject());

Expand All @@ -113,5 +121,4 @@ static byte[] encode(byte[] encoded, boolean hex) throws IOException {
static final String toString(byte value) {
return String.format("%02x", value);
}

}
44 changes: 25 additions & 19 deletions src/main/java/com/apicatalog/cli/command/DecompressCmd.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.apicatalog.cli.command;

import java.io.InputStream;
import java.net.URI;
import java.net.http.HttpClient.Redirect;
import java.net.http.HttpRequest;
Expand All @@ -11,14 +12,12 @@

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.decoder.DecoderConfig;
import com.apicatalog.cli.JsonCborDictionary;
import com.apicatalog.cli.JsonOutput;

import jakarta.json.JsonStructure;
import jakarta.json.JsonValue;
import picocli.CommandLine.Command;
import picocli.CommandLine.Model.CommandSpec;
import picocli.CommandLine.Option;
Expand All @@ -42,12 +41,15 @@ public final class DecompressCmd implements Callable<Integer> {
@Option(names = { "-a", "--keep-arrays" }, description = "keep arrays with just one element")
boolean keepArrays = false;

@Option(names = { "-m", "--mode" }, description = "processing mode", paramLabel = "default|barcodes|v05")
String mode = "default";
@Option(names = { "-d", "--dictionary" }, description = "a custom dictionary (JSON) location")
URI dictionary = null;

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

@Option(names = { "-m", "--mode" }, description = "processing mode", paramLabel = "default|v05")
String mode = "default";

@Spec
CommandSpec spec;

Expand All @@ -59,41 +61,48 @@ private DecompressCmd() {
@Override
public Integer call() throws Exception {

var encoded = decode(fetch());
hex = hex || input == null;

final DecoderConfig config = switch (mode) {
case "barcodes" -> BarcodesConfig.INSTANCE;
var encoded = decode(fetch(input));

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

final JsonValue output = CborLd.createDecoder(config)
var decoder = CborLd.createDecoder(config)
.base(base)
.compactArray(!keepArrays)
.build()
.compactArray(!keepArrays);

if (dictionary != null) {
decoder.dictionary(JsonCborDictionary.of(dictionary));
}

var output = decoder.build()
.decode(encoded);

JsonOutput.print((JsonStructure) output, pretty);

return spec.exitCodeOnSuccess();
}

byte[] fetch() throws Exception {
static byte[] fetch(URI input) 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);
try (var is = fetchHttp(input)) {
return is.readAllBytes();
}
}
return Files.readAllBytes(Path.of(input.toString()));
}

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

var request = HttpRequest.newBuilder()
.GET()
Expand All @@ -106,10 +115,7 @@ static byte[] fetch(URI uri) throws Exception {
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();
}
return response.body();
}

byte[] decode(byte[] data) {
Expand Down
Loading

0 comments on commit 53c81b1

Please sign in to comment.