Skip to content

Commit

Permalink
Numerous updates
Browse files Browse the repository at this point in the history
* Update workflows.
* Use OSGi bundle versioning annotations.
* Update pom.xml to modern standards.
* Add README
  • Loading branch information
io7m committed May 16, 2024
1 parent d9e91bc commit db392de
Show file tree
Hide file tree
Showing 18 changed files with 377 additions and 464 deletions.
66 changes: 66 additions & 0 deletions .github/workflows/run-with-xvfb.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/bin/bash -ex
#
# Automatically generated: DO NOT EDIT.
#
# Generation code: https://www.github.com/io7m-com/.github/
#

exec > >(tee build.txt) 2>&1

#---------------------------------------------------------------------
# Install all of the various required packages.
#
# We use:
# xvfb to provide a virtual X server
# fluxbox to provide a bare-minimum window manager with click-to-focus
# ffmpeg to record the session
# feh to set a background
#

sudo apt-get -y update
sudo apt-get -y upgrade
sudo apt-get -y install xvfb fluxbox feh ffmpeg

#---------------------------------------------------------------------
# Start Xvfb on a new display.
#

Xvfb :99 &
export DISPLAY=:99
sleep 1

#---------------------------------------------------------------------
# Start recording the session.
#

ffmpeg -f x11grab -y -r 60 -video_size 1280x1024 -i :99 -vcodec vp9 test-suite.webm &
FFMPEG_PID="$!"

#---------------------------------------------------------------------
# Start fluxbox on the X server.
#

fluxbox &
sleep 1

#---------------------------------------------------------------------
# Set a desktop image.
#

feh --bg-tile .github/workflows/wallpaper.png
sleep 1

#---------------------------------------------------------------------
# Execute the passed-in build command.
#

"$@"

#---------------------------------------------------------------------
# Wait a while, and then instruct ffmpeg to stop recording. This step
# is necessary because video files need to be processed when recording
# stops.
#

sleep 20
kill -INT "${FFMPEG_PID}" || true
Binary file added .github/workflows/wallpaper.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 7 additions & 1 deletion README-CHANGES.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<c:changelog project="com.io7m.jspiel" xmlns:c="urn:com.io7m.changelog:4.0">
<c:releases/>
<c:releases>
<c:release date="2024-05-16T10:58:48+00:00" is-open="true" ticket-system="com.github.io7m.jspiel" version="1.0.0">
<c:changes>
<c:change date="2024-05-16T10:58:48+00:00" summary="Initial public release."/>
</c:changes>
</c:release>
</c:releases>
<c:ticket-systems>
<c:ticket-system default="true" id="com.github.io7m.jspiel" url="https://www.github.com/io7m/jspiel/issues/"/>
</c:ticket-systems>
Expand Down
129 changes: 129 additions & 0 deletions README.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@

## jspiel

The `jspiel` package implements a set of types and functions for manipulating
RIFF files. It provides efficient parsing and serialization of RIFF files.

## Features

* Ultra-efficient memory-mapped RIFF parsing.
* Safe, easy, and correct lazy RIFF file output with chunk streaming.
* Command-line tools and API.
* Strongly-typed interfaces with a heavy emphasis on immutable value types.
* Fully documented (JavaDoc).
* Example code included.
* [OSGi-ready](https://www.osgi.org/)
* [JPMS-ready](https://en.wikipedia.org/wiki/Java_Platform_Module_System)
* ISC license.
* High-coverage automated test suite.

## Usage

### Reading

Memory-map a RIFF file and use a `RiffFileParserType` to obtain the RIFF
structure of the file:

```
final var parsers =
ServiceLoader.load(RiffFileParserProviderType.class)
.findFirst()
.orElseThrow(() -> new IllegalStateException("No RIFF file parser service available"));

try (var channel = FileChannel.open(path, READ)) {
final var map = channel.map(READ_ONLY, 0L, channel.size());
final var parser = parsers.createForByteBuffer(this.path.toUri(), map);
final var file = parser.parse();

for (final var chunk : file.chunks()) {
// Examine chunks and use the information to seek the channel
// to different offsets within the chunks to obtain data.
//
// The chunks form a tree structure and have full parent/child
// connectivity information.
}
}
```

### Writing

Use a `RiffFileBuilderType` to express the RIFF structure of the intended file,
and then pass the built description to a `RiffFileWriterType` to serialize it.

```
final var builders =
ServiceLoader.load(RiffFileBuilderProviderType.class)
.findFirst()
.orElseThrow(() -> new IllegalStateException("No RIFF file builder service available"));

final var writers =
ServiceLoader.load(RiffFileWriterProviderType.class)
.findFirst()
.orElseThrow(() -> new IllegalStateException("No RIFF file writer service available"));

// Create a little-endian RIFF file description

final var builder =
this.builders()
.create(LITTLE_ENDIAN);

// The root chunk of the RIFF file must be RIFF, and has an "io7m" form
// in this case.

try (var root = builder.setRootChunk(RiffChunkID.of("RIFF"), "io7m")) {

// The AAAA chunk is variable-length; the given writer function
// can write as much data as it likes. The writer function is
// presented with an NIO seekable byte channel interface where position 0
// on the channel represents the start of the data section in the
// chunk.

try (var c = root.addSubChunk(RiffChunkID.of("AAAA"))) {
c.setDataWriter(data -> data.write(...));
}

// The BBBB chunk is declared to have a length of 27 bytes; the given
// writer function can write at most 27 bytes (and writing will be
// terminated with an exception if it tries to write more). The library
// will zero-pad any space that the writer does not use.
//
// The library also takes care of adding the padding
// byte required by the RIFF specification (because 27 is not evenly
// divisible into 16-bit words and so must be padded to 28 bytes).

try (var c = root.addSubChunk(RiffChunkID.of("BBBB"))) {
c.setSize(27L);
c.setDataWriter(data -> data.write(...));
}

// The LIST chunk with form "cwss" contains three subchunks of varying
// types and sizes.

try (var c = root.addSubChunk(RiffChunkID.of("LIST"))) {
c.setForm("cwss");

try (var d = c.addSubChunk(RiffChunkID.of("cw05"))) {
d.setSize(5L);
d.setDataWriter(data -> data.write(...));
}
try (var d = c.addSubChunk(RiffChunkID.of("cw10"))) {
d.setSize(10L);
d.setDataWriter(data -> data.write(...));
}
try (var d = c.addSubChunk(RiffChunkID.of("cw20"))) {
d.setSize(20L);
d.setDataWriter(data -> data.write(...));
}
}
}

// Build the description and serialize it to the given byte channel.
// The writer functions specified in the description are called as the
// file is serialized.

final var description = builder.build();
try (final var channel = FileChannel.open(file, TRUNCATE_EXISTING, WRITE, CREATE)) {
final var writer = writers.createForChannel(URI.create(file.toUri()), description, channel);
writer.write();
}
```
129 changes: 129 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,132 @@ jspiel
| OpenJDK (Temurin) LTS | Linux | [![Build (OpenJDK (Temurin) LTS, Linux)](https://img.shields.io/github/actions/workflow/status/io7m-com/jspiel/main.linux.temurin.lts.yml)](https://www.github.com/io7m-com/jspiel/actions?query=workflow%3Amain.linux.temurin.lts)|
| OpenJDK (Temurin) Current | Windows | [![Build (OpenJDK (Temurin) Current, Windows)](https://img.shields.io/github/actions/workflow/status/io7m-com/jspiel/main.windows.temurin.current.yml)](https://www.github.com/io7m-com/jspiel/actions?query=workflow%3Amain.windows.temurin.current)|
| OpenJDK (Temurin) LTS | Windows | [![Build (OpenJDK (Temurin) LTS, Windows)](https://img.shields.io/github/actions/workflow/status/io7m-com/jspiel/main.windows.temurin.lts.yml)](https://www.github.com/io7m-com/jspiel/actions?query=workflow%3Amain.windows.temurin.lts)|

## jspiel

The `jspiel` package implements a set of types and functions for manipulating
RIFF files. It provides efficient parsing and serialization of RIFF files.

## Features

* Ultra-efficient memory-mapped RIFF parsing.
* Safe, easy, and correct lazy RIFF file output with chunk streaming.
* Command-line tools and API.
* Strongly-typed interfaces with a heavy emphasis on immutable value types.
* Fully documented (JavaDoc).
* Example code included.
* [OSGi-ready](https://www.osgi.org/)
* [JPMS-ready](https://en.wikipedia.org/wiki/Java_Platform_Module_System)
* ISC license.
* High-coverage automated test suite.

## Usage

### Reading

Memory-map a RIFF file and use a `RiffFileParserType` to obtain the RIFF
structure of the file:

```
final var parsers =
ServiceLoader.load(RiffFileParserProviderType.class)
.findFirst()
.orElseThrow(() -> new IllegalStateException("No RIFF file parser service available"));
try (var channel = FileChannel.open(path, READ)) {
final var map = channel.map(READ_ONLY, 0L, channel.size());
final var parser = parsers.createForByteBuffer(this.path.toUri(), map);
final var file = parser.parse();
for (final var chunk : file.chunks()) {
// Examine chunks and use the information to seek the channel
// to different offsets within the chunks to obtain data.
//
// The chunks form a tree structure and have full parent/child
// connectivity information.
}
}
```

### Writing

Use a `RiffFileBuilderType` to express the RIFF structure of the intended file,
and then pass the built description to a `RiffFileWriterType` to serialize it.

```
final var builders =
ServiceLoader.load(RiffFileBuilderProviderType.class)
.findFirst()
.orElseThrow(() -> new IllegalStateException("No RIFF file builder service available"));
final var writers =
ServiceLoader.load(RiffFileWriterProviderType.class)
.findFirst()
.orElseThrow(() -> new IllegalStateException("No RIFF file writer service available"));
// Create a little-endian RIFF file description
final var builder =
this.builders()
.create(LITTLE_ENDIAN);
// The root chunk of the RIFF file must be RIFF, and has an "io7m" form
// in this case.
try (var root = builder.setRootChunk(RiffChunkID.of("RIFF"), "io7m")) {
// The AAAA chunk is variable-length; the given writer function
// can write as much data as it likes. The writer function is
// presented with an NIO seekable byte channel interface where position 0
// on the channel represents the start of the data section in the
// chunk.
try (var c = root.addSubChunk(RiffChunkID.of("AAAA"))) {
c.setDataWriter(data -> data.write(...));
}
// The BBBB chunk is declared to have a length of 27 bytes; the given
// writer function can write at most 27 bytes (and writing will be
// terminated with an exception if it tries to write more). The library
// will zero-pad any space that the writer does not use.
//
// The library also takes care of adding the padding
// byte required by the RIFF specification (because 27 is not evenly
// divisible into 16-bit words and so must be padded to 28 bytes).
try (var c = root.addSubChunk(RiffChunkID.of("BBBB"))) {
c.setSize(27L);
c.setDataWriter(data -> data.write(...));
}
// The LIST chunk with form "cwss" contains three subchunks of varying
// types and sizes.
try (var c = root.addSubChunk(RiffChunkID.of("LIST"))) {
c.setForm("cwss");
try (var d = c.addSubChunk(RiffChunkID.of("cw05"))) {
d.setSize(5L);
d.setDataWriter(data -> data.write(...));
}
try (var d = c.addSubChunk(RiffChunkID.of("cw10"))) {
d.setSize(10L);
d.setDataWriter(data -> data.write(...));
}
try (var d = c.addSubChunk(RiffChunkID.of("cw20"))) {
d.setSize(20L);
d.setDataWriter(data -> data.write(...));
}
}
}
// Build the description and serialize it to the given byte channel.
// The writer functions specified in the description are called as the
// file is serialized.
final var description = builder.build();
try (final var channel = FileChannel.open(file, TRUNCATE_EXISTING, WRITE, CREATE)) {
final var writer = writers.createForChannel(URI.create(file.toUri()), description, channel);
writer.write();
}
```
18 changes: 7 additions & 11 deletions com.io7m.jspiel.api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,24 +31,20 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.io7m.immutables.style</groupId>
<artifactId>com.io7m.immutables.style</artifactId>
<groupId>com.io7m.immutables-style</groupId>
<artifactId>com.io7m.immutables-style</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.annotation.bundle</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.annotation.versioning</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,9 @@
* RIFF I/O (API)
*/

@org.osgi.annotation.bundle.Export
@Export
@Version("1.0.0")
package com.io7m.jspiel.api;

import org.osgi.annotation.bundle.Export;
import org.osgi.annotation.versioning.Version;

0 comments on commit db392de

Please sign in to comment.