DEADSOFTWARE

Clean up and unify encoding conversions
[odcread.git] / odcread.cc
1 #include <iostream>
2 #include <fstream>
3 #include <string>
4 #include <stack>
6 #include <oberon.h>
7 #include <reader.h>
8 #include <store.h>
9 #include <textmodel.h>
10 #include <visitor.h>
12 // Character encoding conversions
13 #include <langinfo.h> // determine the current charset
14 #include <locale.h> // locale support
15 #include <iconv.h> // charset conversions
16 #include <errno.h> // error codes
17 #include <string.h> // string descriptions of error codes
19 namespace odc {
20 class Context {
21 public:
22 virtual void addPiece(std::string &piece) = 0;
23 virtual std::string getPlainText() const = 0;
24 };
25 class PartContext : public Context {
26 private:
27 std::string d_text;
28 public:
29 virtual void addPiece(std::string &piece) {
30 d_text += piece;
31 }
32 virtual std::string getPlainText() const {
33 return d_text;
34 }
35 };
36 class FoldContext : public Context {
37 private:
38 bool d_collapsed;
39 bool d_haveFirst; // flag that first part has been set
40 std::string d_firstPart;
41 std::string d_remainder;
42 public:
43 FoldContext(bool collapsed) : d_collapsed(collapsed), d_haveFirst(false) {}
44 virtual void addPiece(std::string &piece) {
45 if (!d_haveFirst) {
46 d_haveFirst = true;
47 d_firstPart = piece;
48 } else {
49 d_remainder += piece;
50 }
51 }
52 virtual std::string getPlainText() const {
53 if (d_collapsed) {
54 return std::string("##=>") + d_remainder + "\n" + d_firstPart +"##<=";
55 } else {
56 return std::string("##=>") + d_firstPart + "\n" + d_remainder +"##<=";
57 }
58 }
59 };
61 class MyVisitor : public Visitor {
62 private:
63 std::stack<Context*> d_context;
65 void terminateContext() {
66 Context *c = d_context.top();
67 d_context.pop();
68 if (d_context.empty()) {
69 std::cout << c->getPlainText() << std::endl;
70 } else {
71 std::string text = c->getPlainText();
72 d_context.top()->addPiece(text);
73 }
74 delete c;
75 }
77 public:
78 virtual void partStart() {
79 d_context.push(new PartContext());
80 }
81 virtual void partEnd() {
82 terminateContext();
83 }
84 virtual void foldLeft(bool collapsed) {
85 d_context.push(new FoldContext(collapsed));
86 }
87 virtual void foldRight() {
88 terminateContext();
89 }
90 char *getCharSet() {
91 return nl_langinfo(CODESET);
92 }
93 virtual void textShortPiece(const ShortPiece *piece) {
94 std::string str = convert((char *)piece->getBuffer(), piece->size() + 1, (char *)"ISO-8859-1", 1);
95 d_context.top()->addPiece(str);
96 }
97 virtual void textLongPiece(const LongPiece *piece) {
98 std::string str = convert((char *)piece->getBuffer(), piece->size() + 2, (char *)"UCS-2", 2);
99 d_context.top()->addPiece(str);
102 /**
103 * Convert an input character buffer in the given encoding to the
104 * locale's encoding.
105 */
106 std::string convert(char *in, size_t bytesIn, char *encodingIn, size_t inBytesPerChar) {
107 // Convert from the input encoding to the locale's encoding
108 iconv_t conv = iconv_open(getCharSet(), encodingIn);
110 // Handle errors by throwing a readable message
111 if (conv == (iconv_t)-1) {
112 std::string str("iconv initialization error: ");
113 str += strerror(errno);
114 throw str.c_str();
117 // Assume at most 4 bytes per character are needed
118 size_t bytesOut = 4 * bytesIn / inBytesPerChar;
120 // Allocate the output buffer
121 char *out = new char[bytesOut];
122 char *outPtr = out;
124 // Perform conversion
125 size_t rval = iconv(conv, &in, &bytesIn, &outPtr, &bytesOut);
126 if (rval == (size_t)-1) {
127 std::string str("iconv error: ");
128 str += strerror(errno);
129 throw str.c_str();
132 // Free the iconv state
133 iconv_close(conv);
135 // Copy result into a std::string
136 std::string str(out);
137 delete out;
139 // Convert newlines
140 for (std::string::iterator it = str.begin(); it < str.end(); ++it) {
141 if (*it == '\r') *it = '\n';
144 return str;
146 };
148 Store* importDocument(std::istream &is) {
149 const INTEGER docTag = 0x6F4F4443;
150 const INTEGER docVersion = 0;
151 Reader r(is);
152 INTEGER tag = r.readInt();
153 if (tag == docTag) {
154 INTEGER version = r.readInt();
155 if (version != docVersion) {
156 throw 100;
158 Store *s = r.readStore();
159 return s;
161 return 0;
165 int main(int argc, char *argv[]) {
166 if (argc < 2) {
167 return 1;
170 // Set the locale according to the terminal's environment
171 setlocale(LC_ALL, "");
173 std::ifstream in(argv[1], std::ios::in | std::ios::binary);
175 odc::Store* s;
176 try {
177 s = odc::importDocument(in);
178 } catch (int trap) {
179 std::cerr << "Exception in parsing file: BlackBox trap no. " << trap << std::endl;
180 return 2;
181 } catch (const char * exception) {
182 std::cerr << "Exception in parsing file: " << exception << std::endl;
183 return 2;
185 // std::cout << s->toPlainText() << std::endl;
186 // std::cout << std::endl << std::endl;
188 try {
189 odc::MyVisitor visitor;
190 s->accept(visitor);
191 } catch (const char * exception) {
192 std::cerr << "Exception in processing document: " << exception << std::endl;
193 return 3;
195 // std::cout << s->toString() << std::endl;
196 // std::cout << in.tellg() << " " << in.eof() << std::endl;
198 // odc::TypePath path;
199 // odc::ContainerModel(0).getTypePath(&path);
200 // std::cout << path.toString() << std::endl;
201 return 0;