Fix proper UTF-8 encoding for CSV export
This commit is contained in:
Joe Pfeiffer 2021-05-12 17:01:59 -06:00 committed by GitHub
commit fea2497ecc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -3,6 +3,7 @@ package net.sf.openrocket.file;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -18,10 +19,10 @@ import net.sf.openrocket.unit.Unit;
import net.sf.openrocket.util.TextUtil; import net.sf.openrocket.util.TextUtil;
public class CSVExport { public class CSVExport {
/** /**
* Exports the specified flight data branch into a CSV file. * Exports the specified flight data branch into a CSV file.
* *
* @param stream the stream to write to. * @param stream the stream to write to.
* @param simulation the simulation being exported. * @param simulation the simulation being exported.
* @param branch the branch to export. * @param branch the branch to export.
@ -38,27 +39,27 @@ public class CSVExport {
FlightDataBranch branch, FlightDataType[] fields, Unit[] units, FlightDataBranch branch, FlightDataType[] fields, Unit[] units,
String fieldSeparator, String commentStarter, boolean simulationComments, String fieldSeparator, String commentStarter, boolean simulationComments,
boolean fieldComments, boolean eventComments) throws IOException { boolean fieldComments, boolean eventComments) throws IOException {
if (fields.length != units.length) { if (fields.length != units.length) {
throw new IllegalArgumentException("fields and units lengths must be equal " + throw new IllegalArgumentException("fields and units lengths must be equal " +
"(" + fields.length + " vs " + units.length + ")"); "(" + fields.length + " vs " + units.length + ")");
} }
PrintWriter writer = null; PrintWriter writer = null;
try { try {
writer = new PrintWriter(stream); writer = new PrintWriter(stream, false, Charset.forName("UTF-8"));
// Write the initial comments // Write the initial comments
if (simulationComments) { if (simulationComments) {
writeSimulationComments(writer, simulation, branch, fields, commentStarter); writeSimulationComments(writer, simulation, branch, fields, commentStarter);
} }
if (simulationComments && fieldComments) { if (simulationComments && fieldComments) {
writer.println(commentStarter); writer.println(commentStarter);
} }
if (fieldComments) { if (fieldComments) {
writer.print(commentStarter + " "); writer.print(commentStarter + " ");
for (int i = 0; i < fields.length; i++) { for (int i = 0; i < fields.length; i++) {
@ -69,10 +70,10 @@ public class CSVExport {
} }
writer.println(); writer.println();
} }
writeData(writer, branch, fields, units, fieldSeparator, writeData(writer, branch, fields, units, fieldSeparator,
eventComments, commentStarter); eventComments, commentStarter);
} finally { } finally {
if (writer != null) { if (writer != null) {
@ -84,25 +85,25 @@ public class CSVExport {
} }
} }
} }
private static void writeData(PrintWriter writer, FlightDataBranch branch, private static void writeData(PrintWriter writer, FlightDataBranch branch,
FlightDataType[] fields, Unit[] units, String fieldSeparator, boolean eventComments, FlightDataType[] fields, Unit[] units, String fieldSeparator, boolean eventComments,
String commentStarter) { String commentStarter) {
// Number of data points // Number of data points
int n = branch.getLength(); int n = branch.getLength();
// Flight events in occurrance order // Flight events in occurrance order
List<FlightEvent> events = branch.getEvents(); List<FlightEvent> events = branch.getEvents();
Collections.sort(events); Collections.sort(events);
int eventPosition = 0; int eventPosition = 0;
// List of field values // List of field values
List<List<Double>> fieldValues = new ArrayList<List<Double>>(); List<List<Double>> fieldValues = new ArrayList<List<Double>>();
for (FlightDataType t : fields) { for (FlightDataType t : fields) {
fieldValues.add(branch.get(t)); fieldValues.add(branch.get(t));
} }
// Time variable // Time variable
List<Double> time = branch.get(FlightDataType.TYPE_TIME); List<Double> time = branch.get(FlightDataType.TYPE_TIME);
if (eventComments && time == null) { if (eventComments && time == null) {
@ -112,22 +113,22 @@ public class CSVExport {
} }
eventPosition = events.size(); eventPosition = events.size();
} }
// Loop over all data points // Loop over all data points
for (int pos = 0; pos < n; pos++) { for (int pos = 0; pos < n; pos++) {
// Check for events to store // Check for events to store
if (eventComments && time != null) { if (eventComments && time != null) {
double t = time.get(pos); double t = time.get(pos);
while ((eventPosition < events.size()) && while ((eventPosition < events.size()) &&
(events.get(eventPosition).getTime() <= t)) { (events.get(eventPosition).getTime() <= t)) {
printEvent(writer, events.get(eventPosition), commentStarter); printEvent(writer, events.get(eventPosition), commentStarter);
eventPosition++; eventPosition++;
} }
} }
// Store CSV line // Store CSV line
for (int i = 0; i < fields.length; i++) { for (int i = 0; i < fields.length; i++) {
double value = fieldValues.get(i).get(pos); double value = fieldValues.get(i).get(pos);
@ -137,9 +138,9 @@ public class CSVExport {
} }
} }
writer.println(); writer.println();
} }
// Store any remaining events // Store any remaining events
if (eventComments && time != null) { if (eventComments && time != null) {
while (eventPosition < events.size()) { while (eventPosition < events.size()) {
@ -147,61 +148,61 @@ public class CSVExport {
eventPosition++; eventPosition++;
} }
} }
} }
private static void printEvent(PrintWriter writer, FlightEvent e, private static void printEvent(PrintWriter writer, FlightEvent e,
String commentStarter) { String commentStarter) {
writer.println(commentStarter + " Event " + e.getType().name() + writer.println(commentStarter + " Event " + e.getType().name() +
" occurred at t=" + TextUtil.doubleToString(e.getTime()) + " seconds"); " occurred at t=" + TextUtil.doubleToString(e.getTime()) + " seconds");
} }
private static void writeSimulationComments(PrintWriter writer, private static void writeSimulationComments(PrintWriter writer,
Simulation simulation, FlightDataBranch branch, FlightDataType[] fields, Simulation simulation, FlightDataBranch branch, FlightDataType[] fields,
String commentStarter) { String commentStarter) {
String line; String line;
line = simulation.getName(); line = simulation.getName();
FlightData data = simulation.getSimulatedData(); FlightData data = simulation.getSimulatedData();
switch (simulation.getStatus()) { switch (simulation.getStatus()) {
case UPTODATE: case UPTODATE:
line += " (Up to date)"; line += " (Up to date)";
break; break;
case LOADED: case LOADED:
line += " (Data loaded from a file)"; line += " (Data loaded from a file)";
break; break;
case OUTDATED: case OUTDATED:
line += " (Data is out of date)"; line += " (Data is out of date)";
break; break;
case EXTERNAL: case EXTERNAL:
line += " (Imported data)"; line += " (Imported data)";
break; break;
case NOT_SIMULATED: case NOT_SIMULATED:
line += " (Not simulated yet)"; line += " (Not simulated yet)";
break; break;
} }
writer.println(commentStarter + " " + line); writer.println(commentStarter + " " + line);
writer.println(commentStarter + " " + branch.getLength() + " data points written for " writer.println(commentStarter + " " + branch.getLength() + " data points written for "
+ fields.length + " variables."); + fields.length + " variables.");
if (data == null) { if (data == null) {
writer.println(commentStarter + " No simulation data available."); writer.println(commentStarter + " No simulation data available.");
return; return;
} }
WarningSet warnings = data.getWarningSet(); WarningSet warnings = data.getWarningSet();
if (!warnings.isEmpty()) { if (!warnings.isEmpty()) {
writer.println(commentStarter + " Simulation warnings:"); writer.println(commentStarter + " Simulation warnings:");
for (Warning w : warnings) { for (Warning w : warnings) {
@ -209,5 +210,5 @@ public class CSVExport {
} }
} }
} }
} }