Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/keenwrite.git

Separate graphics constants, re-add unit test, move fetching status messages

Author DaveJarvis <email>
Date 2021-04-05 18:18:11 GMT-0700
Commit aa6f8ca8bac7d77a4bf6adcfc39f0718ce8a6f31
Parent c4d8101
src/main/java/com/keenwrite/Constants.java
import com.keenwrite.service.Settings;
-import javafx.scene.image.Image;
-import javafx.scene.image.ImageView;
import java.io.File;
import java.nio.charset.Charset;
import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Locale;
public static final String STYLESHEET_PREVIEW_LOCALE =
"file.stylesheet.preview.locale";
-
- public static final List<Image> LOGOS = createImages(
- "file.logo.16",
- "file.logo.32",
- "file.logo.128",
- "file.logo.256",
- "file.logo.512"
- );
-
- public static final Image ICON_DIALOG = LOGOS.get( 1 );
- public static final ImageView ICON_DIALOG_NODE = new ImageView( ICON_DIALOG );
public static final String FILE_PREFERENCES = getPreferencesFilename();
}
- private static String get( final String key ) {
+ static String get( final String key ) {
return sSettings.getSetting( key, "" );
}
APP_TITLE_LOWERCASE
);
- }
-
- /**
- * Converts the given file names to images, such as application icons.
- *
- * @param keys The file names to convert to images.
- * @return The images loaded from the file name references.
- */
- private static List<Image> createImages( final String... keys ) {
- final List<Image> images = new ArrayList<>( keys.length );
-
- for( final var key : keys ) {
- images.add( new Image( get( key ) ) );
- }
-
- return images;
}
}
src/main/java/com/keenwrite/GraphicsConstants.java
+/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */
+package com.keenwrite;
+
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.keenwrite.Constants.get;
+
+/**
+ * Defines application-wide default values for GUI-related items. This helps
+ * ensure that unit tests that have no graphical dependencies will pass.
+ */
+public class GraphicsConstants {
+ public static final List<Image> LOGOS = createImages(
+ "file.logo.16",
+ "file.logo.32",
+ "file.logo.128",
+ "file.logo.256",
+ "file.logo.512"
+ );
+
+ public static final Image ICON_DIALOG = LOGOS.get( 1 );
+
+ public static final ImageView ICON_DIALOG_NODE = new ImageView( ICON_DIALOG );
+
+ /**
+ * Converts the given file names to images, such as application icons.
+ *
+ * @param keys The file names to convert to images.
+ * @return The images loaded from the file name references.
+ */
+ private static List<Image> createImages( final String... keys ) {
+ final List<Image> images = new ArrayList<>( keys.length );
+
+ for( final var key : keys ) {
+ images.add( new Image( get( key ) ) );
+ }
+
+ return images;
+ }
+}
src/main/java/com/keenwrite/MainApp.java
import static com.keenwrite.Bootstrap.APP_TITLE;
-import static com.keenwrite.Constants.LOGOS;
+import static com.keenwrite.GraphicsConstants.LOGOS;
import static com.keenwrite.preferences.WorkspaceKeys.*;
import static com.keenwrite.util.FontLoader.initFonts;
src/main/java/com/keenwrite/events/StatusEvent.java
/**
- * Indicates that there are no issues to bring to the user's attention.
- */
- private static final StatusEvent OK =
- new StatusEvent( get( STATUS_BAR_OK, "OK" ) );
-
- /**
* Detailed information about a problem.
*/
*/
public static void clue() {
- OK.fire();
+ // Indicates that there are no issues to bring to the user's attention.
+ new StatusEvent( get( STATUS_BAR_OK, "OK" ) );
}
src/main/java/com/keenwrite/io/HttpFacade.java
import java.util.zip.GZIPInputStream;
+import static com.keenwrite.events.StatusEvent.clue;
import static java.lang.System.getProperty;
import static java.lang.System.setProperty;
*/
public static Response httpGet( final URI uri ) throws IOException {
+ clue( "Main.status.image.request.init" );
return httpGet( uri.toURL() );
}
mConn.setRequestProperty( "connection", "close" );
mConn.connect();
+ clue( "Main.status.image.request.fetch", url.getHost() );
final var code = mConn.getResponseCode();
if( mediaType.isUndefined() ) {
- mediaType = StreamMediaType.getMediaType( mStream );
+ mediaType = MediaTypeSniffer.getMediaType( mStream );
}
+ clue( "Main.status.image.request.success", mediaType );
return mediaType;
}
src/main/java/com/keenwrite/io/HttpMediaType.java
-/* Copyright 2020-2021 White Magic Software, Ltd. -- All rights reserved. */
-package com.keenwrite.io;
-
-import java.io.IOException;
-import java.net.URI;
-
-import static com.keenwrite.events.StatusEvent.clue;
-import static com.keenwrite.io.HttpFacade.httpGet;
-import static com.keenwrite.io.MediaType.UNDEFINED;
-
-/**
- * Responsible for determining {@link MediaType} based on the content-type from
- * an HTTP request.
- */
-public final class HttpMediaType {
-
- /**
- * Performs an HTTP request to determine the media type based on the
- * Content-Type header returned from the server.
- *
- * @param uri Determine the media type for this resource.
- * @return The data type for the resource or {@link MediaType#UNDEFINED} if
- * unmapped.
- * @throws IOException The {@link URI} could not be fetched.
- */
- public static MediaType valueFrom( final URI uri ) throws IOException {
- var mediaType = UNDEFINED;
-
- clue( "Main.status.image.request.init" );
-
- try( final var response = httpGet( uri ) ) {
- clue( "Main.status.image.request.fetch", uri.getHost() );
- mediaType = response.getMediaType();
- clue( "Main.status.image.request.success", mediaType );
- }
-
- return mediaType;
- }
-}
src/main/java/com/keenwrite/io/MediaTypeSniffer.java
+package com.keenwrite.io;
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Path;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import static com.keenwrite.io.MediaType.*;
+import static java.lang.System.arraycopy;
+
+/**
+ * Responsible for associating file signatures with IANA-defined
+ * {@link MediaType} instances. For details see:
+ * <ul>
+ * <li>
+ * <a href="https://www.garykessler.net/library/file_sigs.html">Kessler's List</a>
+ * </li>
+ * <li>
+ * <a href="https://en.wikipedia.org/wiki/List_of_file_signatures">Wikipedia's List</a>
+ * </li>
+ * <li>
+ * <a href="https://github.com/veniware/Space-Maker/blob/master/FileSignatures.cs">Space Maker's List</a>
+ * </li>
+ * </ul>
+ */
+public class MediaTypeSniffer {
+ private static final int FORMAT_LENGTH = 11;
+ private static final int END_OF_DATA = -2;
+
+ private static final Map<int[], MediaType> FORMAT = new LinkedHashMap<>();
+
+ static {
+ //@formatter:off
+ FORMAT.put( ints( 0x3C, 0x73, 0x76, 0x67, 0x20 ), IMAGE_SVG_XML );
+ FORMAT.put( ints( 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A ), IMAGE_PNG );
+ FORMAT.put( ints( 0xFF, 0xD8, 0xFF, 0xE0 ), IMAGE_JPEG );
+ FORMAT.put( ints( 0xFF, 0xD8, 0xFF, 0xEE ), IMAGE_JPEG );
+ FORMAT.put( ints( 0xFF, 0xD8, 0xFF, 0xE1, -1, -1, 0x45, 0x78, 0x69, 0x66, 0x00 ), IMAGE_JPEG );
+ FORMAT.put( ints( 0x49, 0x49, 0x2A, 0x00 ), IMAGE_TIFF );
+ FORMAT.put( ints( 0x4D, 0x4D, 0x00, 0x2A ), IMAGE_TIFF );
+ FORMAT.put( ints( 0x47, 0x49, 0x46, 0x38 ), IMAGE_GIF );
+ FORMAT.put( ints( 0x25, 0x50, 0x44, 0x46, 0x2D, 0x31, 0x2E ), APP_PDF );
+ FORMAT.put( ints( 0x25, 0x21, 0x50, 0x53, 0x2D, 0x41, 0x64, 0x6F, 0x62, 0x65, 0x2D ), APP_EPS );
+ FORMAT.put( ints( 0x25, 0x21, 0x50, 0x53 ), APP_PS );
+ FORMAT.put( ints( 0x38, 0x42, 0x50, 0x53, 0x00, 0x01 ), IMAGE_PHOTOSHOP );
+ FORMAT.put( ints( 0x8A, 0x4D, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A ), VIDEO_MNG );
+ FORMAT.put( ints( 0x42, 0x4D ), IMAGE_BMP );
+ FORMAT.put( ints( 0xFF, 0xFB, 0x30 ), AUDIO_MP3 );
+ FORMAT.put( ints( 0x49, 0x44, 0x33 ), AUDIO_MP3 );
+ FORMAT.put( ints( 0x3C, 0x21 ), TEXT_HTML );
+ FORMAT.put( ints( 0x3C, 0x68, 0x74, 0x6D, 0x6C ), TEXT_HTML );
+ FORMAT.put( ints( 0x3C, 0x68, 0x65, 0x61, 0x64 ), TEXT_HTML );
+ FORMAT.put( ints( 0x3C, 0x62, 0x6F, 0x64, 0x79 ), TEXT_HTML );
+ FORMAT.put( ints( 0x3C, 0x48, 0x54, 0x4D, 0x4C ), TEXT_HTML );
+ FORMAT.put( ints( 0x3C, 0x48, 0x45, 0x41, 0x44 ), TEXT_HTML );
+ FORMAT.put( ints( 0x3C, 0x42, 0x4F, 0x44, 0x59 ), TEXT_HTML );
+ FORMAT.put( ints( 0x3C, 0x3F, 0x78, 0x6D, 0x6C, 0x20 ), TEXT_XML );
+ FORMAT.put( ints( 0xFE, 0xFF, 0x00, 0x3C, 0x00, 0x3f, 0x00, 0x78 ), TEXT_XML );
+ FORMAT.put( ints( 0xFF, 0xFE, 0x3C, 0x00, 0x3F, 0x00, 0x78, 0x00 ), TEXT_XML );
+ FORMAT.put( ints( 0x23, 0x64, 0x65, 0x66 ), IMAGE_X_BITMAP );
+ FORMAT.put( ints( 0x21, 0x20, 0x58, 0x50, 0x4D, 0x32 ), IMAGE_X_PIXMAP );
+ FORMAT.put( ints( 0x2E, 0x73, 0x6E, 0x64 ), AUDIO_BASIC );
+ FORMAT.put( ints( 0x64, 0x6E, 0x73, 0x2E ), AUDIO_BASIC );
+ FORMAT.put( ints( 0x52, 0x49, 0x46, 0x46 ), AUDIO_WAV );
+ FORMAT.put( ints( 0x50, 0x4B ), APP_ZIP );
+ FORMAT.put( ints( 0x41, 0x43, -1, -1, -1, -1, 0x00, 0x00, 0x00, 0x00, 0x00 ), APP_ACAD );
+ FORMAT.put( ints( 0xCA, 0xFE, 0xBA, 0xBE ), APP_JAVA );
+ FORMAT.put( ints( 0xAC, 0xED ), APP_JAVA_OBJECT );
+ //@formatter:on
+ }
+
+ private MediaTypeSniffer() {
+ }
+
+ /**
+ * Returns the {@link MediaType} for a given set of bytes.
+ *
+ * @param data Binary data to compare against the list of known formats.
+ * @return The IANA-defined {@link MediaType}, or
+ * {@link MediaType#UNDEFINED} if indeterminate.
+ */
+ public static MediaType getMediaType( final byte[] data ) {
+ assert data != null;
+
+ final var source = new int[]{
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+ for( int i = 0; i < data.length; i++ ) {
+ source[ i ] = data[ i ] & 0xFF;
+ }
+
+ for( final var key : FORMAT.keySet() ) {
+ int i = -1;
+ boolean matches = true;
+
+ while( ++i < FORMAT_LENGTH && key[ i ] != END_OF_DATA && matches ) {
+ matches = key[ i ] == source[ i ] || key[ i ] == -1;
+ }
+
+ if( matches ) {
+ return FORMAT.get( key );
+ }
+ }
+
+ return UNDEFINED;
+ }
+
+ /**
+ * Convenience method to return the probed media type for the given
+ * {@link Path} instance by delegating to {@link #getMediaType(InputStream)}.
+ *
+ * @param path Path to ascertain the {@link MediaType}.
+ * @return The IANA-defined {@link MediaType}, or
+ * {@link MediaType#UNDEFINED} if indeterminate.
+ * @throws IOException Could not read from the {@link File}.
+ */
+ public static MediaType getMediaType( final Path path ) throws IOException {
+ return getMediaType( path.toFile() );
+ }
+
+ /**
+ * Convenience method to return the probed media type for the given
+ * {@link File} instance by delegating to {@link #getMediaType(InputStream)}.
+ *
+ * @param file File to ascertain the {@link MediaType}.
+ * @return The IANA-defined {@link MediaType}, or
+ * {@link MediaType#UNDEFINED} if indeterminate.
+ * @throws IOException Could not read from the {@link File}.
+ */
+ public static MediaType getMediaType( final java.io.File file )
+ throws IOException {
+ try( final var fis = new FileInputStream( file ) ) {
+ return getMediaType( fis );
+ }
+ }
+
+ /**
+ * Convenience method to return the probed media type for the given
+ * {@link BufferedInputStream} instance. <strong>This resets the stream
+ * pointer</strong> making the call idempotent. Users of this class should
+ * prefer to call this method when operating on streams to avoid advancing
+ * the stream.
+ *
+ * @param bis Data source to ascertain the {@link MediaType}.
+ * @return The IANA-defined {@link MediaType}, or
+ * {@link MediaType#UNDEFINED} if indeterminate.
+ * @throws IOException Could not read from the {@link File}.
+ */
+ public static MediaType getMediaType( final BufferedInputStream bis )
+ throws IOException {
+ bis.mark( FORMAT_LENGTH );
+ final var result = getMediaType( (InputStream) bis );
+ bis.reset();
+
+ return result;
+ }
+
+ /**
+ * Helper method to return the probed media type for the given
+ * {@link InputStream} instance. The caller is responsible for closing
+ * the stream. <strong>This advances the stream pointer.</strong>
+ *
+ * @param is Data source to ascertain the {@link MediaType}.
+ * @return The IANA-defined {@link MediaType}, or
+ * {@link MediaType#UNDEFINED} if indeterminate.
+ * @throws IOException Could not read from the {@link InputStream}.
+ * @see #getMediaType(BufferedInputStream) to perform a non-destructive
+ * read.
+ */
+ private static MediaType getMediaType( final InputStream is )
+ throws IOException {
+ final var input = new byte[ FORMAT_LENGTH ];
+ final var count = is.read( input, 0, FORMAT_LENGTH );
+
+ if( count > 1 ) {
+ final var available = new byte[ count ];
+ arraycopy( input, 0, available, 0, count );
+ return getMediaType( available );
+ }
+
+ return UNDEFINED;
+ }
+
+ /**
+ * Creates an array of integers from the given data, padded with {@link
+ * #END_OF_DATA} values up to {@link #FORMAT_LENGTH}.
+ *
+ * @param data The input byte values to pad.
+ * @return The data with padding.
+ */
+ private static int[] ints( final int... data ) {
+ final var magic = new int[ FORMAT_LENGTH ];
+ int i = -1;
+ while( ++i < data.length ) {
+ magic[ i ] = data[ i ];
+ }
+
+ while( i < FORMAT_LENGTH ) {
+ magic[ i++ ] = END_OF_DATA;
+ }
+
+ return magic;
+ }
+}
src/main/java/com/keenwrite/io/StreamMediaType.java
-package com.keenwrite.io;
-
-import java.io.BufferedInputStream;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.Path;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import static com.keenwrite.io.MediaType.*;
-import static java.lang.System.arraycopy;
-
-/**
- * Responsible for associating file signatures with IANA-defined
- * {@link MediaType} instances. For details see:
- * <ul>
- * <li>
- * <a href="https://www.garykessler.net/library/file_sigs.html">Kessler's List</a>
- * </li>
- * <li>
- * <a href="https://en.wikipedia.org/wiki/List_of_file_signatures">Wikipedia's List</a>
- * </li>
- * <li>
- * <a href="https://github.com/veniware/Space-Maker/blob/master/FileSignatures.cs">Space Maker's List</a>
- * </li>
- * </ul>
- */
-public class StreamMediaType {
- private static final int FORMAT_LENGTH = 11;
- private static final int END_OF_DATA = -2;
-
- private static final Map<int[], MediaType> FORMAT = new LinkedHashMap<>();
-
- static {
- //@formatter:off
- FORMAT.put( ints( 0x3C, 0x73, 0x76, 0x67, 0x20 ), IMAGE_SVG_XML );
- FORMAT.put( ints( 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A ), IMAGE_PNG );
- FORMAT.put( ints( 0xFF, 0xD8, 0xFF, 0xE0 ), IMAGE_JPEG );
- FORMAT.put( ints( 0xFF, 0xD8, 0xFF, 0xEE ), IMAGE_JPEG );
- FORMAT.put( ints( 0xFF, 0xD8, 0xFF, 0xE1, -1, -1, 0x45, 0x78, 0x69, 0x66, 0x00 ), IMAGE_JPEG );
- FORMAT.put( ints( 0x49, 0x49, 0x2A, 0x00 ), IMAGE_TIFF );
- FORMAT.put( ints( 0x4D, 0x4D, 0x00, 0x2A ), IMAGE_TIFF );
- FORMAT.put( ints( 0x47, 0x49, 0x46, 0x38 ), IMAGE_GIF );
- FORMAT.put( ints( 0x8A, 0x4D, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A ), VIDEO_MNG );
- FORMAT.put( ints( 0x25, 0x50, 0x44, 0x46, 0x2D, 0x31, 0x2E ), APP_PDF );
- FORMAT.put( ints( 0x38, 0x42, 0x50, 0x53, 0x00, 0x01 ), IMAGE_PHOTOSHOP );
- FORMAT.put( ints( 0x25, 0x21, 0x50, 0x53, 0x2D, 0x41, 0x64, 0x6F, 0x62, 0x65, 0x2D ), APP_EPS );
- FORMAT.put( ints( 0x25, 0x21, 0x50, 0x53 ), APP_PS );
- FORMAT.put( ints( 0xFF, 0xFB, 0x30 ), AUDIO_MP3 );
- FORMAT.put( ints( 0x49, 0x44, 0x33 ), AUDIO_MP3 );
- FORMAT.put( ints( 0x3C, 0x21 ), TEXT_HTML );
- FORMAT.put( ints( 0x3C, 0x68, 0x74, 0x6D, 0x6C ), TEXT_HTML );
- FORMAT.put( ints( 0x3C, 0x68, 0x65, 0x61, 0x64 ), TEXT_HTML );
- FORMAT.put( ints( 0x3C, 0x62, 0x6F, 0x64, 0x79 ), TEXT_HTML );
- FORMAT.put( ints( 0x3C, 0x48, 0x54, 0x4D, 0x4C ), TEXT_HTML );
- FORMAT.put( ints( 0x3C, 0x48, 0x45, 0x41, 0x44 ), TEXT_HTML );
- FORMAT.put( ints( 0x3C, 0x42, 0x4F, 0x44, 0x59 ), TEXT_HTML );
- FORMAT.put( ints( 0x3C, 0x3F, 0x78, 0x6D, 0x6C, 0x20 ), TEXT_XML );
- FORMAT.put( ints( 0xFE, 0xFF, 0x00, 0x3C, 0x00, 0x3f, 0x00, 0x78 ), TEXT_XML );
- FORMAT.put( ints( 0xFF, 0xFE, 0x3C, 0x00, 0x3F, 0x00, 0x78, 0x00 ), TEXT_XML );
- FORMAT.put( ints( 0x42, 0x4D ), IMAGE_BMP );
- FORMAT.put( ints( 0x23, 0x64, 0x65, 0x66 ), IMAGE_X_BITMAP );
- FORMAT.put( ints( 0x21, 0x20, 0x58, 0x50, 0x4D, 0x32 ), IMAGE_X_PIXMAP );
- FORMAT.put( ints( 0x2E, 0x73, 0x6E, 0x64 ), AUDIO_BASIC );
- FORMAT.put( ints( 0x64, 0x6E, 0x73, 0x2E ), AUDIO_BASIC );
- FORMAT.put( ints( 0x52, 0x49, 0x46, 0x46 ), AUDIO_WAV );
- FORMAT.put( ints( 0x50, 0x4B ), APP_ZIP );
- FORMAT.put( ints( 0x41, 0x43, -1, -1, -1, -1, 0x00, 0x00, 0x00, 0x00, 0x00 ), APP_ACAD );
- FORMAT.put( ints( 0xCA, 0xFE, 0xBA, 0xBE ), APP_JAVA );
- FORMAT.put( ints( 0xAC, 0xED ), APP_JAVA_OBJECT );
- //@formatter:on
- }
-
- private StreamMediaType() {
- }
-
- /**
- * Returns the {@link MediaType} for a given set of bytes.
- *
- * @param data Binary data to compare against the list of known formats.
- * @return The IANA-defined {@link MediaType}, or
- * {@link MediaType#UNDEFINED} if indeterminate.
- */
- public static MediaType getMediaType( final byte[] data ) {
- assert data != null;
-
- final var source = new int[]{
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
-
- for( int i = 0; i < data.length; i++ ) {
- source[ i ] = data[ i ] & 0xFF;
- }
-
- for( final var key : FORMAT.keySet() ) {
- int i = -1;
- boolean matches = true;
-
- while( ++i < FORMAT_LENGTH && key[ i ] != END_OF_DATA && matches ) {
- matches = key[ i ] == source[ i ] || key[ i ] == -1;
- }
-
- if( matches ) {
- return FORMAT.get( key );
- }
- }
-
- return UNDEFINED;
- }
-
- /**
- * Convenience method to return the probed media type for the given
- * {@link Path} instance by delegating to {@link #getMediaType(InputStream)}.
- *
- * @param path Path to ascertain the {@link MediaType}.
- * @return The IANA-defined {@link MediaType}, or
- * {@link MediaType#UNDEFINED} if indeterminate.
- * @throws IOException Could not read from the {@link File}.
- */
- public static MediaType getMediaType( final Path path ) throws IOException {
- return getMediaType( path.toFile() );
- }
-
- /**
- * Convenience method to return the probed media type for the given
- * {@link File} instance by delegating to {@link #getMediaType(InputStream)}.
- *
- * @param file File to ascertain the {@link MediaType}.
- * @return The IANA-defined {@link MediaType}, or
- * {@link MediaType#UNDEFINED} if indeterminate.
- * @throws IOException Could not read from the {@link File}.
- */
- public static MediaType getMediaType( final java.io.File file )
- throws IOException {
- try( final var fis = new FileInputStream( file ) ) {
- return getMediaType( fis );
- }
- }
-
- /**
- * Convenience method to return the probed media type for the given
- * {@link BufferedInputStream} instance. <strong>This resets the stream
- * pointer</strong> making the call idempotent. Users of this class should
- * prefer to call this method when operating on streams to avoid advancing
- * the stream.
- *
- * @param bis Data source to ascertain the {@link MediaType}.
- * @return The IANA-defined {@link MediaType}, or
- * {@link MediaType#UNDEFINED} if indeterminate.
- * @throws IOException Could not read from the {@link File}.
- */
- public static MediaType getMediaType( final BufferedInputStream bis )
- throws IOException {
- bis.mark( FORMAT_LENGTH );
- final var result = getMediaType( (InputStream) bis );
- bis.reset();
-
- return result;
- }
-
- /**
- * Helper method to return the probed media type for the given
- * {@link InputStream} instance. The caller is responsible for closing
- * the stream. <strong>This advances the stream pointer.</strong>
- *
- * @param is Data source to ascertain the {@link MediaType}.
- * @return The IANA-defined {@link MediaType}, or
- * {@link MediaType#UNDEFINED} if indeterminate.
- * @throws IOException Could not read from the {@link InputStream}.
- * @see #getMediaType(BufferedInputStream) to perform a non-destructive
- * read.
- */
- private static MediaType getMediaType( final InputStream is )
- throws IOException {
- final var input = new byte[ FORMAT_LENGTH ];
- final var count = is.read( input, 0, FORMAT_LENGTH );
-
- if( count > 1 ) {
- final var available = new byte[ count ];
- arraycopy( input, 0, available, 0, count );
- return getMediaType( available );
- }
-
- return UNDEFINED;
- }
-
- /**
- * Creates an array of integers from the given data, padded with {@link
- * #END_OF_DATA} values up to {@link #FORMAT_LENGTH}.
- *
- * @param data The input byte values to pad.
- * @return The data with padding.
- */
- private static int[] ints( final int... data ) {
- final var magic = new int[ FORMAT_LENGTH ];
- int i = -1;
- while( ++i < data.length ) {
- magic[ i ] = data[ i ];
- }
-
- while( i < FORMAT_LENGTH ) {
- magic[ i++ ] = END_OF_DATA;
- }
-
- return magic;
- }
-}
src/main/java/com/keenwrite/preferences/PreferencesController.java
import static com.dlsc.formsfx.model.structure.Field.ofStringType;
import static com.dlsc.preferencesfx.PreferencesFxEvent.EVENT_PREFERENCES_SAVED;
-import static com.keenwrite.Constants.ICON_DIALOG;
+import static com.keenwrite.GraphicsConstants.ICON_DIALOG;
import static com.keenwrite.Messages.get;
import static com.keenwrite.preferences.LocaleProperty.localeListProperty;
src/main/java/com/keenwrite/preferences/SimpleFontControl.java
import org.controlsfx.dialog.FontSelectorDialog;
-import static com.keenwrite.Constants.ICON_DIALOG;
+import static com.keenwrite.GraphicsConstants.ICON_DIALOG;
import static com.keenwrite.events.StatusEvent.clue;
import static java.lang.System.currentTimeMillis;
src/main/java/com/keenwrite/preview/SvgReplacedElementFactory.java
package com.keenwrite.preview;
-import com.keenwrite.io.HttpMediaType;
import com.keenwrite.io.MediaType;
import com.keenwrite.ui.adapters.ReplacedElementAdapter;
import static com.keenwrite.events.StatusEvent.clue;
-import static com.keenwrite.io.MediaType.UNDEFINED;
+import static com.keenwrite.io.HttpFacade.httpGet;
import static com.keenwrite.preview.MathRenderer.MATH_RENDERER;
import static com.keenwrite.preview.SvgRasterizer.BROKEN_IMAGE_PLACEHOLDER;
case HTML_IMAGE -> {
final var source = e.getAttribute( HTML_IMAGE_SRC );
+ var mediaType = MediaType.fromFilename( source );
URI uri = null;
if( getProtocol( source ).isHttp() ) {
- var mediaType = MediaType.fromFilename( source );
-
- if( mediaType.isSvg() || mediaType == UNDEFINED ) {
+ if( mediaType.isSvg() || mediaType.isUndefined() ) {
uri = new URI( source );
+
+ try( final var response = httpGet( uri ) ) {
+ mediaType = response.getMediaType();
+ }
// Attempt to rasterize SVG depending on URL resource content.
- if( !HttpMediaType.valueFrom( uri ).isSvg() ) {
+ if( !mediaType.isSvg() ) {
uri = null;
}
}
}
- else if( MediaType.fromFilename( source ).isSvg() ) {
+ else if( mediaType.isSvg() ) {
// Attempt to rasterize based on file name.
final var path = Path.of( new URI( source ).getPath() );
src/main/java/com/keenwrite/service/events/impl/DefaultNotifier.java
import java.nio.file.Path;
-import static com.keenwrite.Constants.ICON_DIALOG_NODE;
+import static com.keenwrite.GraphicsConstants.ICON_DIALOG_NODE;
import static com.keenwrite.Messages.get;
import static javafx.scene.control.Alert.AlertType.CONFIRMATION;
src/main/java/com/keenwrite/ui/actions/ApplicationActions.java
import static com.keenwrite.Bootstrap.*;
-import static com.keenwrite.Constants.ICON_DIALOG_NODE;
+import static com.keenwrite.GraphicsConstants.ICON_DIALOG_NODE;
import static com.keenwrite.ExportFormat.*;
import static com.keenwrite.Messages.get;
src/main/java/com/keenwrite/ui/dialogs/AbstractDialog.java
import javafx.stage.Window;
-import static com.keenwrite.Constants.ICON_DIALOG;
+import static com.keenwrite.GraphicsConstants.ICON_DIALOG;
import static com.keenwrite.Messages.get;
import static javafx.scene.control.ButtonType.CANCEL;
src/main/java/com/keenwrite/ui/logging/LogView.java
import static com.keenwrite.Bootstrap.APP_TITLE_LOWERCASE;
import static com.keenwrite.Constants.ACTION_PREFIX;
-import static com.keenwrite.Constants.ICON_DIALOG;
+import static com.keenwrite.GraphicsConstants.ICON_DIALOG;
import static com.keenwrite.Messages.get;
import static com.keenwrite.events.Bus.register;
src/test/java/com/keenwrite/io/MediaTypeSnifferTest.java
+package com.keenwrite.io;
+
+import org.junit.jupiter.api.Test;
+
+import static com.keenwrite.io.MediaTypeExtension.valueFrom;
+import static org.apache.commons.io.FilenameUtils.getExtension;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Responsible for testing that {@link MediaTypeSniffer} can return the
+ * correct IANA-defined {@link MediaType} for known file types.
+ */
+class MediaTypeSnifferTest {
+
+ @Test
+ void test_Read_KnownFileTypes_MediaTypeReturned()
+ throws Exception {
+ final var clazz = getClass();
+ final var pkgName = clazz.getPackageName();
+ final var dir = pkgName.replace( '.', '/' );
+
+ final var urls = clazz.getClassLoader().getResources( dir + "/images" );
+ assertTrue( urls.hasMoreElements() );
+
+ while( urls.hasMoreElements() ) {
+ final var url = urls.nextElement();
+ final var path = new File( url.toURI().getPath() );
+
+ for( final var image : path.listFiles() ) {
+ final var media = MediaTypeSniffer.getMediaType( image );
+ final var actualExtension = valueFrom( media ).getExtension();
+ final var expectedExtension = getExtension( image.toString() );
+ assertEquals( expectedExtension, actualExtension );
+ }
+ }
+ }
+}
src/test/java/com/keenwrite/io/MediaTypeTest.java
import java.util.Map;
+import static com.keenwrite.io.HttpFacade.httpGet;
import static com.keenwrite.io.MediaType.*;
import static org.junit.jupiter.api.Assertions.*;
/**
- * Test that {@link HttpMediaType#valueFrom(URI)} will pull and identify the
- * type of resource based on the HTTP Content-Type header.
+ * Test that remote fetches will pull and identify the type of resource
+ * based on the HTTP Content-Type header (or shallow decoding).
*/
@Test
public void test_HttpRequest_Supported_Success() {
//@formatter:off
final var map = Map.of(
"https://stackoverflow.com/robots.txt", TEXT_PLAIN,
"https://place-hold.it/300x500", IMAGE_GIF,
+ "https://placekitten.com/g/200/300", IMAGE_JPEG,
"https://upload.wikimedia.org/wikipedia/commons/9/9f/Vimlogo.svg", IMAGE_SVG_XML,
- "https://kroki.io//graphviz/svg/eNpLyUwvSizIUHBXqPZIzcnJ17ULzy_KSanlAgB1EAjQ", TEXT_PLAIN
+ "https://kroki.io//graphviz/svg/eNpLyUwvSizIUHBXqPZIzcnJ17ULzy_KSanlAgB1EAjQ", IMAGE_SVG_XML
);
//@formatter:on
map.forEach( ( k, v ) -> {
- try {
- assertEquals( v, HttpMediaType.valueFrom( new URI( k ) ) );
+ try( var response = httpGet( new URI( k ) ) ) {
+ assertEquals( v, response.getMediaType() );
} catch( Exception e ) {
fail();
src/test/java/com/keenwrite/io/StreamMediaTypeTest.java
-package com.keenwrite.io;
-
-import org.junit.jupiter.api.Test;
-
-import static com.keenwrite.io.MediaTypeExtension.valueFrom;
-import static org.apache.commons.io.FilenameUtils.getExtension;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-/**
- * Responsible for testing that {@link StreamMediaType} can return the
- * correct IANA-defined {@link MediaType} for known file types.
- */
-class StreamMediaTypeTest {
-
- @Test
- void test_Read_KnownFileTypes_MediaTypeReturned()
- throws Exception {
- final var clazz = getClass();
- final var pkgName = clazz.getPackageName();
- final var dir = pkgName.replace( '.', '/' );
-
- final var urls = clazz.getClassLoader().getResources( dir + "/images" );
- assertTrue( urls.hasMoreElements() );
-
- while( urls.hasMoreElements() ) {
- final var url = urls.nextElement();
- final var path = new File( url.toURI().getPath() );
-
- for( final var image : path.listFiles() ) {
- final var media = StreamMediaType.getMediaType( image );
- final var actualExtension = valueFrom( media ).getExtension();
- final var expectedExtension = getExtension( image.toString() );
- assertEquals( expectedExtension, actualExtension );
- }
- }
- }
-}
Delta 320 lines added, 343 lines removed, 23-line decrease