Skip to content

Commit 5790e2e

Browse files
committed
add (simple) ODS writer to Table
1 parent cc89b20 commit 5790e2e

3 files changed

Lines changed: 209 additions & 32 deletions

File tree

core/src/processing/data/IntDict.java

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -26,29 +26,6 @@ public class IntDict {
2626
private HashMap<String, Integer> indices = new HashMap<String, Integer>();
2727

2828

29-
// /**
30-
// * Create a new object by counting the number of times each unique entry
31-
// * shows up in the specified String array.
32-
// */
33-
// static public IntHash fromTally(String[] list) {
34-
// IntHash outgoing = new IntHash();
35-
// for (String s : list) {
36-
// outgoing.inc(s);
37-
// }
38-
// outgoing.crop();
39-
// return outgoing;
40-
// }
41-
//
42-
//
43-
// static public IntHash fromOrder(String[] list) {
44-
// IntHash outgoing = new IntHash();
45-
// for (int i = 0; i < list.length; i++) {
46-
// outgoing.set(list[i], i);
47-
// }
48-
// return outgoing;
49-
// }
50-
51-
5229
public IntDict() {
5330
count = 0;
5431
keys = new String[10];

core/src/processing/data/StringList.java

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -683,14 +683,6 @@ public IntDict getOrder() {
683683
}
684684

685685

686-
// public void println() {
687-
// for (int i = 0; i < count; i++) {
688-
// System.out.println("[" + i + "] " + data[i]);
689-
// }
690-
// System.out.flush();
691-
// }
692-
693-
694686
public String join(String separator) {
695687
if (count == 0) {
696688
return "";

core/src/processing/data/Table.java

Lines changed: 209 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
import java.io.*;
2727
import java.lang.reflect.*;
28+
import java.nio.charset.Charset;
2829
import java.sql.ResultSet;
2930
import java.sql.ResultSetMetaData;
3031
import java.sql.SQLException;
@@ -34,6 +35,7 @@
3435
import java.util.concurrent.Executors;
3536
import java.util.zip.ZipEntry;
3637
import java.util.zip.ZipInputStream;
38+
import java.util.zip.ZipOutputStream;
3739

3840
import javax.xml.parsers.ParserConfigurationException;
3941

@@ -292,7 +294,7 @@ protected String checkOptions(File file, String options) throws IOException {
292294

293295

294296
static final String[] loadExtensions = { "csv", "tsv", "ods", "bin" };
295-
static final String[] saveExtensions = { "csv", "tsv", "html", "bin" };
297+
static final String[] saveExtensions = { "csv", "tsv", "ods", "bin", "html" };
296298

297299
static public String extensionOptions(boolean loading, String filename, String options) {
298300
String extension = PApplet.checkExtension(filename);
@@ -971,6 +973,13 @@ public boolean save(OutputStream output, String options) {
971973
writeCSV(writer);
972974
} else if (extension.equals("tsv")) {
973975
writeTSV(writer);
976+
} else if (extension.equals("ods")) {
977+
try {
978+
saveODS(output);
979+
} catch (IOException e) {
980+
e.printStackTrace();
981+
return false;
982+
}
974983
} else if (extension.equals("html")) {
975984
writeHTML(writer);
976985
} else if (extension.equals("bin")) {
@@ -1140,6 +1149,205 @@ protected void writeEntryHTML(PrintWriter writer, String entry) {
11401149
}
11411150

11421151

1152+
protected void saveODS(OutputStream os) throws IOException {
1153+
ZipOutputStream zos = new ZipOutputStream(os);
1154+
1155+
final String xmlHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
1156+
1157+
ZipEntry entry = new ZipEntry("META-INF/manifest.xml");
1158+
String[] lines = new String[] {
1159+
xmlHeader,
1160+
"<manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\">",
1161+
" <manifest:file-entry manifest:media-type=\"application/vnd.oasis.opendocument.spreadsheet\" manifest:version=\"1.2\" manifest:full-path=\"/\"/>",
1162+
" <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"content.xml\"/>",
1163+
" <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"styles.xml\"/>",
1164+
" <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"meta.xml\"/>",
1165+
" <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"settings.xml\"/>",
1166+
"</manifest:manifest>"
1167+
};
1168+
zos.putNextEntry(entry);
1169+
zos.write(PApplet.join(lines, "\n").getBytes());
1170+
zos.closeEntry();
1171+
1172+
/*
1173+
entry = new ZipEntry("meta.xml");
1174+
lines = new String[] {
1175+
xmlHeader,
1176+
"<office:document-meta office:version=\"1.0\"" +
1177+
" xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" />"
1178+
};
1179+
zos.putNextEntry(entry);
1180+
zos.write(PApplet.join(lines, "\n").getBytes());
1181+
zos.closeEntry();
1182+
1183+
entry = new ZipEntry("meta.xml");
1184+
lines = new String[] {
1185+
xmlHeader,
1186+
"<office:document-settings office:version=\"1.0\"" +
1187+
" xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\"" +
1188+
" xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"" +
1189+
" xmlns:ooo=\"http://openoffice.org/2004/office\"" +
1190+
" xmlns:xlink=\"http://www.w3.org/1999/xlink\" />"
1191+
};
1192+
zos.putNextEntry(entry);
1193+
zos.write(PApplet.join(lines, "\n").getBytes());
1194+
zos.closeEntry();
1195+
1196+
entry = new ZipEntry("settings.xml");
1197+
lines = new String[] {
1198+
xmlHeader,
1199+
"<office:document-settings office:version=\"1.0\"" +
1200+
" xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\"" +
1201+
" xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"" +
1202+
" xmlns:ooo=\"http://openoffice.org/2004/office\"" +
1203+
" xmlns:xlink=\"http://www.w3.org/1999/xlink\" />"
1204+
};
1205+
zos.putNextEntry(entry);
1206+
zos.write(PApplet.join(lines, "\n").getBytes());
1207+
zos.closeEntry();
1208+
1209+
entry = new ZipEntry("styles.xml");
1210+
lines = new String[] {
1211+
xmlHeader,
1212+
"<office:document-styles office:version=\"1.0\"" +
1213+
" xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" />"
1214+
};
1215+
zos.putNextEntry(entry);
1216+
zos.write(PApplet.join(lines, "\n").getBytes());
1217+
zos.closeEntry();
1218+
*/
1219+
1220+
final String[] dummyFiles = new String[] {
1221+
"meta.xml", "settings.xml", "styles.xml"
1222+
};
1223+
lines = new String[] {
1224+
xmlHeader,
1225+
"<office:document-meta office:version=\"1.0\"" +
1226+
" xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" />"
1227+
};
1228+
byte[] dummyBytes = PApplet.join(lines, "\n").getBytes();
1229+
for (String filename : dummyFiles) {
1230+
entry = new ZipEntry(filename);
1231+
zos.putNextEntry(entry);
1232+
zos.write(dummyBytes);
1233+
zos.closeEntry();
1234+
}
1235+
1236+
//
1237+
1238+
entry = new ZipEntry("mimetype");
1239+
zos.putNextEntry(entry);
1240+
zos.write("application/vnd.oasis.opendocument.spreadsheet".getBytes());
1241+
zos.closeEntry();
1242+
1243+
//
1244+
1245+
entry = new ZipEntry("content.xml");
1246+
zos.putNextEntry(entry);
1247+
//lines = new String[] {
1248+
writeUTF(zos, new String[] {
1249+
xmlHeader,
1250+
"<office:document-content" +
1251+
" xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"" +
1252+
" xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\"" +
1253+
" xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\"" +
1254+
" office:version=\"1.2\">",
1255+
" <office:body>",
1256+
" <office:spreadsheet>",
1257+
" <table:table table:name=\"Sheet1\" table:print=\"false\">"
1258+
});
1259+
//zos.write(PApplet.join(lines, "\n").getBytes());
1260+
1261+
byte[] rowStart = " <table:table-row>\n".getBytes();
1262+
byte[] rowStop = " </table:table-row>\n".getBytes();
1263+
1264+
if (hasColumnTitles()) {
1265+
zos.write(rowStart);
1266+
for (int i = 0; i < getColumnCount(); i++) {
1267+
saveStringODS(zos, columnTitles[i]);
1268+
}
1269+
zos.write(rowStop);
1270+
}
1271+
1272+
for (TableRow row : rows()) {
1273+
zos.write(rowStart);
1274+
for (int i = 0; i < getColumnCount(); i++) {
1275+
if (columnTypes[i] == STRING || columnTypes[i] == CATEGORY) {
1276+
saveStringODS(zos, row.getString(i));
1277+
} else {
1278+
saveNumberODS(zos, row.getString(i));
1279+
}
1280+
}
1281+
zos.write(rowStop);
1282+
}
1283+
1284+
//lines = new String[] {
1285+
writeUTF(zos, new String[] {
1286+
" </table:table>",
1287+
" </office:spreadsheet>",
1288+
" </office:body>",
1289+
"</office:document-content>"
1290+
});
1291+
//zos.write(PApplet.join(lines, "\n").getBytes());
1292+
zos.closeEntry();
1293+
1294+
zos.flush();
1295+
zos.close();
1296+
}
1297+
1298+
1299+
void saveStringODS(OutputStream output, String text) throws IOException {
1300+
// At this point, I should have just used the XML library. But this does
1301+
// save us from having to create the entire document in memory again before
1302+
// writing to the file. So while it's dorky, the outcome is still useful.
1303+
StringBuilder sanitized = new StringBuilder();
1304+
char[] array = text.toCharArray();
1305+
for (char c : array) {
1306+
if (c == '&') {
1307+
sanitized.append("&amp;");
1308+
} else if (c == '\'') {
1309+
sanitized.append("&apos;");
1310+
} else if (c == '"') {
1311+
sanitized.append("&quot;");
1312+
} else if (c == '<') {
1313+
sanitized.append("&lt;");
1314+
} else if (c == '>') {
1315+
sanitized.append("&rt;");
1316+
} else if (c < 32 || c > 127) {
1317+
sanitized.append("&#" + ((int) c) + ";");
1318+
} else {
1319+
sanitized.append(c);
1320+
}
1321+
}
1322+
1323+
writeUTF(output,
1324+
" <table:table-cell office:value-type=\"string\">",
1325+
" <text:p>" + sanitized + "</text:p>",
1326+
" </table:table-cell>");
1327+
}
1328+
1329+
1330+
void saveNumberODS(OutputStream output, String text) throws IOException {
1331+
writeUTF(output,
1332+
" <table:table-cell office:value-type=\"float\" office:value=\"" + text + "\">",
1333+
" <text:p>" + text + "</text:p>",
1334+
" </table:table-cell>");
1335+
}
1336+
1337+
1338+
static Charset utf8;
1339+
1340+
static void writeUTF(OutputStream output, String... lines) throws IOException {
1341+
if (utf8 == null) {
1342+
utf8 = Charset.forName("UTF-8");
1343+
}
1344+
for (String str : lines) {
1345+
output.write(str.getBytes(utf8));
1346+
output.write('\n');
1347+
}
1348+
}
1349+
1350+
11431351
protected void saveBinary(OutputStream os) throws IOException {
11441352
DataOutputStream output = new DataOutputStream(new BufferedOutputStream(os));
11451353
output.writeInt(0x9007AB1E); // version

0 commit comments

Comments
 (0)