Mercurial > cgi-bin > hgweb.cgi > ClipMan
annotate src/name/blackcap/clipman/RtfToHtml.kt @ 54:a9d5c94a177c
Add README file.
author | David Barts <n5jrn@me.com> |
---|---|
date | Tue, 13 Apr 2021 10:33:33 -0700 |
parents | 0c6c18a733b7 |
children |
rev | line source |
---|---|
0
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
1 /* |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
2 * Because Java (and by implication Kotlin) sucks at processing RTF data, |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
3 * we deal with such data by invoking an external program to convert it |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
4 * to HTML. |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
5 */ |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
6 package name.blackcap.clipman |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
7 |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
8 import java.io.BufferedInputStream |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
9 import java.io.BufferedOutputStream |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
10 import java.io.ByteArrayOutputStream |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
11 import java.io.IOException |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
12 import java.io.InputStream |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
13 import java.io.OutputStream |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
14 import java.io.UnsupportedEncodingException |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
15 |
31 | 16 private val RTF_CHARSET_NAME = CHARSET_NAME |
0
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
17 private val LANG = "en_US." + RTF_CHARSET_NAME |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
18 private val UNRTF = System.getenv("UNRTF") |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
19 |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
20 private class Consumer(val source: InputStream): Thread() { |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
21 val target = ByteArrayOutputStream() |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
22 |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
23 override fun run() { |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
24 source.use { it.copyTo(target) } |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
25 } |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
26 |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
27 val output: String |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
28 @Synchronized get() { |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
29 if (isAlive()) { |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
30 throw IllegalThreadStateException("consumer not finished!") |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
31 } else { |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
32 return target.toString(RTF_CHARSET_NAME) |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
33 } |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
34 } |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
35 } |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
36 |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
37 /** |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
38 * Convert an InputStream of RTF bytes to a String containing an HTML |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
39 * document. |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
40 * @param rtfStream stream containing the RTF document |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
41 * @return a Pair. On success, the first element contains the HTML and |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
42 * the second is null. On failure, the first is null and the |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
43 * second contains an error message. |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
44 */ |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
45 public fun rtfToHtml(rtfStream: InputStream): Pair<String?, String?> { |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
46 if (OS.type == OS.MAC && UNRTF == null) { |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
47 return _rtfToHtml(rtfStream, ProcessBuilder("textutil", "-format", |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
48 "rtf", "-convert", "html", "-stdin", "-stdout")) |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
49 } else { |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
50 return _rtfToHtml(rtfStream, ProcessBuilder( |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
51 if (UNRTF == null) { "unrtf" } else { UNRTF }, |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
52 "--html", "--nopict")) |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
53 } |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
54 } |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
55 |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
56 private fun _rtfToHtml(rtfStream: InputStream, pb: ProcessBuilder): Pair<String?, String?> { |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
57 var job: Process? = null |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
58 try { |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
59 /* set the Posix locale to force UTF-8 I/O */ |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
60 pb.environment().run { |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
61 put("LANG", LANG) |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
62 put("LC_ALL", LANG) |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
63 } |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
64 |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
65 /* start the process */ |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
66 job = pb.start() |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
67 |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
68 /* start consuming its output and error streams */ |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
69 val outputConsumer = Consumer(job.inputStream).apply { start() } |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
70 val errorConsumer = Consumer(job.errorStream).apply { start() } |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
71 |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
72 /* feed it input */ |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
73 job.outputStream.use { rtfStream.copyTo(it) } |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
74 |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
75 /* wait for it to exit */ |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
76 val exitStatus = job.waitFor() |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
77 |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
78 /* after it exits, wait for our data consumers to exit */ |
27 | 79 outputConsumer.join() |
80 errorConsumer.join() | |
0
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
81 |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
82 /* if it barfed, return an error, else return the HTML */ |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
83 if (exitStatus != 0) { |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
84 val errors = errorConsumer.output |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
85 if (errors.isEmpty()) { |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
86 return Pair(null, "converter exited with status " + exitStatus) |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
87 } else { |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
88 return Pair(null, errors) |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
89 } |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
90 } |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
91 return Pair(outputConsumer.output, null) |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
92 } catch (e: IOException) { |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
93 return barfed(e) |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
94 } catch (e: InterruptedException) { |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
95 if (job != null && job.isAlive()) { |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
96 job.destroy() |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
97 job.waitFor() |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
98 } |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
99 return barfed(e) |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
100 } |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
101 } |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
102 |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
103 private fun barfed(e: Exception): Pair<String?, String?> { |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
104 val sb = StringBuilder(e::class.simpleName) |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
105 val message = e.message ?: "" |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
106 if (!message.isEmpty()) { |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
107 sb.append(": ") |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
108 sb.append(e.message) |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
109 } |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
110 return Pair(null, sb.toString()) |
be282c48010a
Incomplete; checking it in as a backup.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
111 } |