diff --git a/build.gradle b/build.gradle
index a2e72723..507a7f4a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -62,6 +62,7 @@ dependencies {
testImplementation 'junit:junit:4.12'
testImplementation 'org.assertj:assertj-core:3.8.0'
testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0")
+ testImplementation 'org.mockito:mockito-core:3.+'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
@@ -92,6 +93,7 @@ dependencies {
implementation 'org.apache.commons:commons-compress:1.20'
implementation 'org.apache.commons:commons-lang3:3.8.1'
implementation 'org.apache.commons:commons-math3:3.6.1'
+ implementation 'org.apache.commons:commons-csv:1.9.0'
implementation 'org.apache.mina:mina-core:2.1.3'
implementation 'org.apache.mina:mina-http:2.1.3'
implementation 'org.controlsfx:controlsfx:11.1.0'
diff --git a/src/main/java/io/github/dsheirer/module/log/DecodeEventLogger.java b/src/main/java/io/github/dsheirer/module/log/DecodeEventLogger.java
index 566aa9ca..129dda56 100644
--- a/src/main/java/io/github/dsheirer/module/log/DecodeEventLogger.java
+++ b/src/main/java/io/github/dsheirer/module/log/DecodeEventLogger.java
@@ -33,10 +33,13 @@ import io.github.dsheirer.module.decode.event.IDecodeEvent;
import io.github.dsheirer.module.decode.event.IDecodeEventListener;
import io.github.dsheirer.preference.TimestampFormat;
import io.github.dsheirer.sample.Listener;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.QuoteMode;
import java.nio.file.Path;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@@ -47,6 +50,16 @@ public class DecodeEventLogger extends EventLogger implements IDecodeEventListen
private AliasList mAliasList;
private AliasModel mAliasModel;
+ /**
+ * The CSV format that SDR Trunk will use to write decode event logs
+ *
+ * It uses the standard, default CSV format (RFC 4180 and permitting empty lines) but *always* quoting cells since
+ * that's what SDR Trunk has done previously when hand-crafting CSV rows.
+ */
+ private final CSVFormat mCsvFormat = CSVFormat.Builder.create(CSVFormat.DEFAULT)
+ .setQuoteMode(QuoteMode.ALL)
+ .build();
+
public DecodeEventLogger(AliasModel aliasModel, Path logDirectory, String fileNameSuffix, long frequency)
{
super(logDirectory, fileNameSuffix, frequency);
@@ -83,25 +96,23 @@ public class DecodeEventLogger extends EventLogger implements IDecodeEventListen
private String toCSV(IDecodeEvent event)
{
+ List