Link with C++ linker
[oweals/cde.git] / cde / programs / nsgmls / UnicodeCodingSystem.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: UnicodeCodingSystem.C /main/1 1996/07/29 17:07:33 cde-hp $ */
24 // Copyright (c) 1994 James Clark
25 // See the file COPYING for copying permission.
26
27 #include "splib.h"
28
29 #ifdef SP_MULTI_BYTE
30
31 #include "UnicodeCodingSystem.h"
32 #include "macros.h"
33 #include "Owner.h"
34
35 #include <stddef.h>
36 #include <string.h>
37 #ifdef DECLARE_MEMMOVE
38 extern "C" {
39   void *memmove(void *, const void *, size_t);
40 }
41 #endif
42 #include <iostream.h>
43
44 #ifdef SP_NAMESPACE
45 namespace SP_NAMESPACE {
46 #endif
47
48 const unsigned short byteOrderMark = 0xfeff;
49 const unsigned short swappedByteOrderMark = 0xfffe;
50
51 class UnicodeDecoder : public Decoder {
52 public:
53   UnicodeDecoder(const InputCodingSystem *sub);
54   size_t decode(Char *to, const char *from, size_t fromLen,
55                 const char **rest);
56   Boolean convertOffset(unsigned long &offset) const;
57 private:
58   PackedBoolean hadFirstChar_;
59   PackedBoolean hadByteOrderMark_;
60   PackedBoolean swapBytes_;
61   Owner<Decoder> subDecoder_;
62   const InputCodingSystem *subCodingSystem_;
63 };
64
65 class UnicodeEncoder : public Encoder {
66 public:
67   UnicodeEncoder();
68   ~UnicodeEncoder();
69   void output(Char *, size_t, streambuf *);
70   void output(const Char *, size_t, streambuf *);
71   void startFile(streambuf *);
72 private:
73   void allocBuf(size_t);
74   unsigned short *buf_;
75   size_t bufSize_;
76 };
77
78 UnicodeCodingSystem::UnicodeCodingSystem(const InputCodingSystem *sub)
79 : sub_(sub)
80 {
81 }
82
83 Decoder *UnicodeCodingSystem::makeDecoder() const
84 {
85   return new UnicodeDecoder(sub_);
86 }
87
88 Encoder *UnicodeCodingSystem::makeEncoder() const
89 {
90   return new UnicodeEncoder;
91 }
92
93 unsigned UnicodeCodingSystem::fixedBytesPerChar() const
94 {
95   return 2;
96 }
97
98 UnicodeDecoder::UnicodeDecoder(const InputCodingSystem *subCodingSystem)
99 : Decoder(subCodingSystem ? 1 : 2), subCodingSystem_(subCodingSystem),
100   hadByteOrderMark_(0), hadFirstChar_(0), swapBytes_(0)
101 {
102 }
103
104
105 size_t UnicodeDecoder::decode(Char *to, const char *from, size_t fromLen,
106                               const char **rest)
107 {
108   union U {
109     unsigned short word;
110     char bytes[2];
111   };
112     
113   if (subDecoder_)
114     return subDecoder_->decode(to, from, fromLen, rest);
115   if (!hadFirstChar_) {
116     hadFirstChar_ = 1;
117     minBytesPerChar_ = 2;
118     if (fromLen < 2) {
119       *rest = from;
120       return 0;
121     }
122     U u;
123     u.bytes[0] = from[0];
124     u.bytes[1] = from[1];
125     if (u.word == byteOrderMark) {
126       hadByteOrderMark_ = 1;
127       from += 2;
128       fromLen -= 2;
129     }
130     else if (u.word == swappedByteOrderMark) {
131       hadByteOrderMark_ = 1;
132       from += 2;
133       fromLen -= 2;
134       swapBytes_ = 1;
135     }
136     else if (subCodingSystem_) {
137       subDecoder_ = subCodingSystem_->makeDecoder();
138       minBytesPerChar_ = subDecoder_->minBytesPerChar();
139       return subDecoder_->decode(to, from, fromLen, rest);
140     }
141   }
142   fromLen &= ~1;
143   *rest = from + fromLen;
144   if (sizeof(Char) == 2) {
145     if (!swapBytes_) {
146       if (from != (char *)to)
147         memmove(to, from, fromLen);
148       return fromLen/2;
149     }
150   }
151   if (swapBytes_) {
152     for (size_t n = fromLen; n > 0; n -= 2) {
153       U u;
154       u.bytes[1] = *from++;
155       u.bytes[0] = *from++;
156       *to++ = u.word;
157     }
158   }
159   else  {
160     for (size_t n = fromLen; n > 0; n -= 2) {
161       U u;
162       u.bytes[0] = *from++;
163       u.bytes[1] = *from++;
164       *to++ = u.word;
165     }
166   }
167   return fromLen/2;
168 }
169
170 Boolean UnicodeDecoder::convertOffset(unsigned long &n) const
171 {
172   if (subDecoder_)
173     return subDecoder_->convertOffset(n);
174   n *= 2;
175   if (hadByteOrderMark_)
176     n += 1;
177   return true;
178 }
179
180 UnicodeEncoder::UnicodeEncoder()
181 : buf_(0), bufSize_(0)
182 {
183 }
184
185 UnicodeEncoder::~UnicodeEncoder()
186 {
187   delete [] buf_;
188 }
189
190 void UnicodeEncoder::allocBuf(size_t n)
191 {
192   if (bufSize_ < n) {
193     delete [] buf_;
194     buf_ = new unsigned short[bufSize_ = n];
195   }
196 }
197
198 void UnicodeEncoder::startFile(streambuf *sb)
199 {
200   const unsigned short n = byteOrderMark;
201   sb->sputn((char *)&n, 2);
202 }
203
204 // FIXME handle errors from streambuf::sputn
205
206 void UnicodeEncoder::output(Char *s, size_t n, streambuf *sb)
207 {
208   if (sizeof(Char) == 2) {
209     sb->sputn((char *)s, n*2);
210     return;
211   }
212   ASSERT(sizeof(Char) >= 2);
213   unsigned short *p = (unsigned short *)s;
214   for (size_t i = 0; i < n; i++)
215     p[i] = s[i] & 0xffff;
216   sb->sputn((char *)s, n*2);
217 }
218
219 void UnicodeEncoder::output(const Char *s, size_t n, streambuf *sb)
220 {
221   if (sizeof(Char) == 2) {
222     sb->sputn((char *)s, n*2);
223     return;
224   }
225   allocBuf(n);
226   for (size_t i = 0; i < n; i++)
227     buf_[i] = s[i] & 0xffff;
228   sb->sputn((char *)buf_, n*2);
229 }
230
231 #ifdef SP_NAMESPACE
232 }
233 #endif
234
235 #else /* not SP_MULTI_BYTE */
236
237 #ifndef __GNUG__
238 static char non_empty_translation_unit; // sigh
239 #endif
240
241 #endif /* not SP_MULTI_BYTE */