1 // Copyright (c) 1997 James Clark
2 // See the file COPYING for copying permission.
3 #pragma ident	"%Z%%M%	%I%	%E% SMI"
4 
5 #include "splib.h"
6 
7 #include "TranslateCodingSystem.h"
8 #include "types.h"
9 #include "Owner.h"
10 
11 #ifdef SP_NAMESPACE
12 namespace SP_NAMESPACE {
13 #endif
14 
15 class TranslateDecoder : public Decoder {
16 public:
17   TranslateDecoder(Decoder *, const ConstPtr<CharMapResource<Char> > &);
18   size_t decode(Char *, const char *, size_t, const char **);
19   Boolean convertOffset(unsigned long &offset) const;
20 private:
21   Owner<Decoder> decoder_;
22   ConstPtr<CharMapResource<Char> > map_;
23 };
24 
TranslateDecoder(Decoder * decoder,const ConstPtr<CharMapResource<Char>> & map)25 TranslateDecoder::TranslateDecoder(Decoder *decoder,
26 				   const ConstPtr<CharMapResource<Char> > &map)
27 : Decoder(decoder->minBytesPerChar()), decoder_(decoder), map_(map)
28 {
29 }
30 
31 
convertOffset(unsigned long & offset) const32 Boolean TranslateDecoder::convertOffset(unsigned long &offset) const
33 {
34   return decoder_->convertOffset(offset);
35 }
36 
decode(Char * to,const char * s,size_t slen,const char ** rest)37 size_t TranslateDecoder::decode(Char *to, const char *s,
38 				size_t slen, const char **rest)
39 {
40   size_t n = decoder_->decode(to, s, slen, rest);
41   for (size_t i = 0; i < n; i++)
42     to[i] = (*map_)[to[i]];
43   return n;
44 }
45 
46 // FIXME set unencodeable handler for underlying encoder
47 
48 class TranslateEncoder : public RecoveringEncoder {
49 public:
50   TranslateEncoder(Encoder *, const ConstPtr<CharMapResource<Char> > &map,
51 		   Char illegalChar);
52   void output(const Char *, size_t, OutputByteStream *);
53   void output(Char *, size_t, OutputByteStream *);
54   void startFile(OutputByteStream *);
55 private:
56   Owner<Encoder> encoder_;
57   ConstPtr<CharMapResource<Char> > map_;
58   Char illegalChar_;
59   enum { bufSize = 256 };
60   Char buf_[bufSize];
61 };
62 
TranslateEncoder(Encoder * encoder,const ConstPtr<CharMapResource<Char>> & map,Char illegalChar)63 TranslateEncoder::TranslateEncoder(Encoder *encoder,
64 				   const ConstPtr<CharMapResource<Char> > &map,
65 				   Char illegalChar)
66 : encoder_(encoder), map_(map), illegalChar_(illegalChar)
67 {
68 }
69 
startFile(OutputByteStream * sbuf)70 void TranslateEncoder::startFile(OutputByteStream *sbuf)
71 {
72   encoder_->startFile(sbuf);
73 }
74 
output(const Char * s,size_t n,OutputByteStream * sbuf)75 void TranslateEncoder::output(const Char *s, size_t n, OutputByteStream *sbuf)
76 {
77   size_t j = 0;
78   for (; n > 0; s++, n--) {
79     Char c = (*map_)[*s];
80     if (c == illegalChar_) {
81       if (j > 0) {
82 	encoder_->output(buf_, j, sbuf);
83 	j = 0;
84       }
85       handleUnencodable(*s, sbuf);
86     }
87     else {
88       if (j >= bufSize) {
89 	encoder_->output(buf_, j, sbuf);
90 	j = 0;
91       }
92       buf_[j++] = c;
93     }
94   }
95   if (j > 0)
96     encoder_->output(buf_, j, sbuf);
97 }
98 
output(Char * s,size_t n,OutputByteStream * sbuf)99 void TranslateEncoder::output(Char *s, size_t n, OutputByteStream *sbuf)
100 {
101   size_t i = 0;
102   for (;;) {
103     if (i == n) {
104       if (n > 0)
105 	encoder_->output(s, n, sbuf);
106       break;
107     }
108     Char c = (*map_)[s[i]];
109     if (c == illegalChar_) {
110       if (i > 0)
111 	encoder_->output(s, i, sbuf);
112       handleUnencodable(s[i], sbuf);
113       i++;
114       s += i;
115       n -= i;
116       i = 0;
117     }
118     else
119       s[i++] = c;
120   }
121 }
122 
TranslateCodingSystem(const CodingSystem * sub,const Desc * desc,const CharsetInfo * charset,Char illegalChar,Char replacementChar)123 TranslateCodingSystem::TranslateCodingSystem(const CodingSystem *sub,
124 					     const Desc *desc,
125 					     const CharsetInfo *charset,
126 					     Char illegalChar,
127 					     Char replacementChar)
128 : sub_(sub),
129   desc_(desc),
130   charset_(charset),
131   illegalChar_(illegalChar),
132   replacementChar_(replacementChar)
133 {
134 }
135 
makeDecoder() const136 Decoder *TranslateCodingSystem::makeDecoder() const
137 {
138   if (decodeMap_.isNull()) {
139     CharMapResource<Char> *map = new CharMapResource<Char>(replacementChar_);
140     *(ConstPtr<CharMapResource<Char> > *)&decodeMap_ = map;
141     for (const Desc *d = desc_; d->number != CharsetRegistry::UNREGISTERED; d++) {
142       Owner<CharsetRegistry::Iter> iter(CharsetRegistry::makeIter(d->number));
143       if (iter) {
144 	WideChar min;
145 	WideChar max;
146 	UnivChar univ;
147 	while (iter->next(min, max, univ)) {
148 	  do {
149 	    ISet<WideChar> set;
150 	    WideChar sysChar;
151 	    WideChar count;
152 	    int n = charset_->univToDesc(univ, sysChar, set, count);
153 	    if (count > (max - min) + 1)
154 	      count = (max - min) + 1;
155 	    if (n) {
156 	      for (WideChar i = 0; i < count; i++)
157 		map->setChar(min + d->add + i, sysChar + i);
158 	    }
159 	    min += count - 1;
160 	    univ += count;
161 	  } while (min++ != max);
162 	}
163       }
164     }
165   }
166   return new TranslateDecoder(sub_->makeDecoder(), decodeMap_);
167 }
168 
makeEncoder() const169 Encoder *TranslateCodingSystem::makeEncoder() const
170 {
171   if (encodeMap_.isNull()) {
172     CharMapResource<Char> *map = new CharMapResource<Char>(illegalChar_);
173     *(ConstPtr<CharMapResource<Char> > *)&encodeMap_ = map;
174     for (const Desc *d = desc_; d->number != CharsetRegistry::UNREGISTERED; d++) {
175       Owner<CharsetRegistry::Iter> iter(CharsetRegistry::makeIter(d->number));
176       if (iter) {
177 	WideChar min;
178 	WideChar max;
179 	UnivChar univ;
180 	while (iter->next(min, max, univ)) {
181 	  do {
182 	    ISet<WideChar> set;
183 	    WideChar sysChar;
184 	    WideChar count;
185 	    int n = charset_->univToDesc(univ, sysChar, set, count);
186 	    if (count > (max - min) + 1)
187 	      count = (max - min) + 1;
188 	    if (n) {
189 	      for (WideChar i = 0; i < count; i++)
190 		map->setChar(sysChar + i, min + d->add + i);
191 	    }
192 	    min += count - 1;
193 	    univ += count;
194 	  } while (min++ != max);
195 	}
196       }
197     }
198   }
199   return new TranslateEncoder(sub_->makeEncoder(), encodeMap_, illegalChar_);
200 }
201 
fixedBytesPerChar() const202 unsigned TranslateCodingSystem::fixedBytesPerChar() const
203 {
204   return sub_->fixedBytesPerChar();
205 }
206 
207 #ifdef SP_NAMESPACE
208 }
209 #endif
210 
211