~ubuntu-branches/ubuntu/precise/xom/precise

« back to all changes in this revision

Viewing changes to src/nu/xom/UnicodeWriter.java

  • Committer: Bazaar Package Importer
  • Author(s): Varun Hiremath
  • Date: 2007-11-25 15:50:40 UTC
  • Revision ID: james.westby@ubuntu.com-20071125155040-r75ikcqf1vu0cei7
Tags: upstream-1.1
ImportĀ upstreamĀ versionĀ 1.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright 2002, 2003, 2005 Elliotte Rusty Harold
 
2
   
 
3
   This library is free software; you can redistribute it and/or modify
 
4
   it under the terms of version 2.1 of the GNU Lesser General Public 
 
5
   License as published by the Free Software Foundation.
 
6
   
 
7
   This library is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 
10
   GNU Lesser General Public License for more details.
 
11
   
 
12
   You should have received a copy of the GNU Lesser General Public
 
13
   License along with this library; if not, write to the 
 
14
   Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
 
15
   Boston, MA 02111-1307  USA
 
16
   
 
17
   You can contact Elliotte Rusty Harold by sending e-mail to
 
18
   elharo@metalab.unc.edu. Please include the word "XOM" in the
 
19
   subject line. The XOM home page is located at http://www.xom.nu/
 
20
*/
 
21
 
 
22
package nu.xom;
 
23
 
 
24
import java.io.IOException;
 
25
import java.io.Writer;
 
26
 
 
27
/**
 
28
 * @author Elliotte Rusty Harold
 
29
 * @version 1.1b4
 
30
 *
 
31
 */
 
32
final class UnicodeWriter extends TextWriter {
 
33
 
 
34
    UnicodeWriter(Writer out, String encoding) {
 
35
        super(out, encoding);
 
36
    }
 
37
 
 
38
    /**
 
39
     * @see nu.xom.TextWriter#needsEscaping(char)
 
40
     */
 
41
    boolean needsEscaping(char c) {
 
42
        return false;
 
43
    }
 
44
 
 
45
 
 
46
    void writeMarkup(String s) throws IOException {
 
47
 
 
48
         if (normalize) {
 
49
             s = normalize(s);
 
50
         }
 
51
         
 
52
         int unicodeStringLength = getUnicodeLengthForMarkup(s);
 
53
         if (unicodeStringLength >= 0) {
 
54
             out.write(s);
 
55
             if (unicodeStringLength > 0) {
 
56
                 column += unicodeStringLength;
 
57
                 lastCharacterWasSpace = false;
 
58
                 skipFollowingLinefeed = false;
 
59
                 justBroke=false;
 
60
             }
 
61
         }
 
62
         else { // write character by character
 
63
             int length = s.length();
 
64
             for (int i=0; i < length; i++) {
 
65
                 writeMarkup(s.charAt(i));
 
66
             }
 
67
         }
 
68
         
 
69
    }
 
70
 
 
71
    
 
72
    /*
 
73
     * This is tricky. This method is doing two things:
 
74
     * 
 
75
     * 1. It's counting the number of Unicode characters in s.
 
76
     * 2. It's checking to see if this text contains anything
 
77
     *    that might need to be escaped. 
 
78
     * 
 
79
     * If the latter it returns -1; otherwise it returns the number of characters.
 
80
     */
 
81
    private static int getUnicodeLengthForMarkup(String s) {
 
82
        
 
83
        int unicodeLength = 0;
 
84
        int javaLength = s.length();
 
85
        for (int i = 0; i < javaLength; i++) {
 
86
            char c = s.charAt(i);
 
87
            if (c <= ' ') { 
 
88
                // Really we're testing only for \t, \n, and space here.
 
89
                // However all other characters less than or equal to 32
 
90
                // can't appear in markup sections.
 
91
                // These characters cause an adjustment of 
 
92
                // lastCharacterWasSpace, skipFollowingLinefeed, and justBroke
 
93
                // They may need to be escaped but only in doctype declarations.
 
94
                // Should these have their own writeDoctypeDeclaration method????
 
95
                // Also an issue with spaces and such in PIs, XML declaration, comments
 
96
                return -1;
 
97
            }
 
98
            // Count the low surrogates but skip the high surrogates
 
99
            // so surrogate pairs aren't counted twice.
 
100
            else if (c < 0xD800 || c > 0xDBFF) unicodeLength++;
 
101
        }
 
102
        return unicodeLength;
 
103
        
 
104
    }
 
105
 
 
106
 
 
107
    void writeAttributeValue(String s) throws IOException {
 
108
 
 
109
         if (normalize) {
 
110
             s = normalize(s);
 
111
         }
 
112
         int unicodeStringLength = getUnicodeLengthForAttributeValue(s);
 
113
         if (unicodeStringLength >= 0) { 
 
114
             out.write(s);
 
115
             if (unicodeStringLength > 0) {
 
116
                 column += unicodeStringLength;
 
117
                 lastCharacterWasSpace = false;
 
118
                 skipFollowingLinefeed = false;
 
119
                 justBroke=false;
 
120
             }
 
121
         }
 
122
         else {
 
123
             int length = s.length();
 
124
             for (int i=0; i < length; i++) {
 
125
                 writeAttributeValue(s.charAt(i));
 
126
             }
 
127
         }
 
128
 
 
129
     }
 
130
 
 
131
    
 
132
    // All three getUnicodeLengthForFOO methods are very similar.
 
133
    // Could the code duplciation be eliminated efficiently somehow?
 
134
    private static int getUnicodeLengthForAttributeValue(String s) {
 
135
         
 
136
        int unicodeLength = 0;
 
137
        int javaLength = s.length();
 
138
        for (int i = 0; i < javaLength; i++) {
 
139
            char c = s.charAt(i);
 
140
            switch (c) {
 
141
                case '\t': return -1;
 
142
                case '\n': return -1;
 
143
                case   11: // unreachable
 
144
                case   12: throw new XMLException("Bad character snuck into document");
 
145
                case '\r': return -1;
 
146
                case 14: // unreachable
 
147
                case 15: // unreachable
 
148
                case 16: // unreachable
 
149
                case 17: // unreachable
 
150
                case 18: // unreachable
 
151
                case 19: // unreachable
 
152
                case 20: // unreachable
 
153
                case 21: // unreachable
 
154
                case 22: // unreachable
 
155
                case 23: // unreachable
 
156
                case 24: // unreachable
 
157
                case 25: // unreachable
 
158
                case 26: // unreachable
 
159
                case 27: // unreachable
 
160
                case 28: // unreachable
 
161
                case 29: // unreachable
 
162
                case 30: // unreachable
 
163
                case 31: // unreachable
 
164
                    throw new XMLException("Bad character snuck into document");
 
165
                case ' ':  return -1;
 
166
                case '!':
 
167
                    unicodeLength++;
 
168
                    break;
 
169
                case '"':
 
170
                    return -1;
 
171
                case '#':
 
172
                    unicodeLength++;
 
173
                    break;
 
174
                case '$':
 
175
                    unicodeLength++;
 
176
                    break;
 
177
                case '%':
 
178
                    unicodeLength++;
 
179
                    break;
 
180
                case '&':
 
181
                    return -1;
 
182
                case '\'':
 
183
                    unicodeLength++;
 
184
                    break;
 
185
                case '(':
 
186
                    unicodeLength++;
 
187
                    break;
 
188
                case ')':
 
189
                    unicodeLength++;
 
190
                    break;
 
191
                case '*':
 
192
                    unicodeLength++;
 
193
                    break;
 
194
                case '+':
 
195
                    unicodeLength++;
 
196
                    break;
 
197
                case ',':
 
198
                    unicodeLength++;
 
199
                    break;
 
200
                case '-':
 
201
                    unicodeLength++;
 
202
                    break;
 
203
                case '.':
 
204
                    unicodeLength++;
 
205
                    break;
 
206
                case '/':
 
207
                    unicodeLength++;
 
208
                    break;
 
209
                case '0':
 
210
                    unicodeLength++;
 
211
                    break;
 
212
                case '1':
 
213
                    unicodeLength++;
 
214
                    break;
 
215
                case '2':
 
216
                    unicodeLength++;
 
217
                    break;
 
218
                case '3':
 
219
                    unicodeLength++;
 
220
                    break;
 
221
                case '4':
 
222
                    unicodeLength++;
 
223
                    break;
 
224
                case '5':
 
225
                    unicodeLength++;
 
226
                    break;
 
227
                case '6':
 
228
                    unicodeLength++;
 
229
                    break;
 
230
                case '7':
 
231
                    unicodeLength++;
 
232
                    break;
 
233
                case '8':
 
234
                    unicodeLength++;
 
235
                    break;
 
236
                case '9':
 
237
                    unicodeLength++;
 
238
                    break;
 
239
                case ':':
 
240
                    unicodeLength++;
 
241
                    break;
 
242
                case ';':
 
243
                    unicodeLength++;
 
244
                    break;
 
245
                case '<':
 
246
                    return -1;
 
247
                case '=':
 
248
                    unicodeLength++;
 
249
                    break;
 
250
                case '>':
 
251
                    return -1;
 
252
                default:
 
253
                    if (c < 0xd800 || c > 0xDBFF) unicodeLength++;
 
254
            }
 
255
        }
 
256
        return unicodeLength;
 
257
        
 
258
     }
 
259
 
 
260
    
 
261
     void writePCDATA(String s) throws IOException {
 
262
 
 
263
         if (normalize) {
 
264
             s = normalize(s);
 
265
         }
 
266
         
 
267
         int unicodeStringLength = getUnicodeLengthForPCDATA(s);
 
268
         if (unicodeStringLength >= 0) {
 
269
             out.write(s);
 
270
             if (unicodeStringLength > 0) {
 
271
                 column += unicodeStringLength;
 
272
                 lastCharacterWasSpace = false;
 
273
                 skipFollowingLinefeed = false;
 
274
                 justBroke=false;
 
275
             }
 
276
         }
 
277
         else {
 
278
             int length = s.length();
 
279
             for (int i=0; i < length; i++) {
 
280
                 writePCDATA(s.charAt(i));
 
281
             }
 
282
         }
 
283
    
 
284
    }
 
285
    
 
286
 
 
287
    private static int getUnicodeLengthForPCDATA(String s) {
 
288
        
 
289
        int unicodeLength = 0;
 
290
        int javaLength = s.length();
 
291
        for (int i = 0; i < javaLength; i++) {
 
292
            char c = s.charAt(i);
 
293
            switch (c) {
 
294
                case '\t': return -1;
 
295
                case '\n': return -1;
 
296
                case   11: // unreachable
 
297
                case   12: throw new XMLException("Bad character snuck into document");
 
298
                case '\r': return -1;
 
299
                case 14: // unreachable
 
300
                case 15: // unreachable
 
301
                case 16: // unreachable
 
302
                case 17: // unreachable
 
303
                case 18: // unreachable
 
304
                case 19: // unreachable
 
305
                case 20: // unreachable
 
306
                case 21: // unreachable
 
307
                case 22: // unreachable
 
308
                case 23: // unreachable
 
309
                case 24: // unreachable
 
310
                case 25: // unreachable
 
311
                case 26: // unreachable
 
312
                case 27: // unreachable
 
313
                case 28: // unreachable
 
314
                case 29: // unreachable
 
315
                case 30: // unreachable
 
316
                case 31: // unreachable
 
317
                    throw new XMLException("Bad character snuck into document");
 
318
                case ' ':  return -1;
 
319
                case '!':
 
320
                    unicodeLength++;
 
321
                    break;
 
322
                case '"':
 
323
                    unicodeLength++;
 
324
                    break;
 
325
                case '#':
 
326
                    unicodeLength++;
 
327
                    break;
 
328
                case '$':
 
329
                    unicodeLength++;
 
330
                    break;
 
331
                case '%':
 
332
                    unicodeLength++;
 
333
                    break;
 
334
                case '&':
 
335
                    return -1;
 
336
                case '\'':
 
337
                    unicodeLength++;
 
338
                    break;
 
339
                case '(':
 
340
                    unicodeLength++;
 
341
                    break;
 
342
                case ')':
 
343
                    unicodeLength++;
 
344
                    break;
 
345
                case '*':
 
346
                    unicodeLength++;
 
347
                    break;
 
348
                case '+':
 
349
                    unicodeLength++;
 
350
                    break;
 
351
                case ',':
 
352
                    unicodeLength++;
 
353
                    break;
 
354
                case '-':
 
355
                    unicodeLength++;
 
356
                    break;
 
357
                case '.':
 
358
                    unicodeLength++;
 
359
                    break;
 
360
                case '/':
 
361
                    unicodeLength++;
 
362
                    break;
 
363
                case '0':
 
364
                    unicodeLength++;
 
365
                    break;
 
366
                case '1':
 
367
                    unicodeLength++;
 
368
                    break;
 
369
                case '2':
 
370
                    unicodeLength++;
 
371
                    break;
 
372
                case '3':
 
373
                    unicodeLength++;
 
374
                    break;
 
375
                case '4':
 
376
                    unicodeLength++;
 
377
                    break;
 
378
                case '5':
 
379
                    unicodeLength++;
 
380
                    break;
 
381
                case '6':
 
382
                    unicodeLength++;
 
383
                    break;
 
384
                case '7':
 
385
                    unicodeLength++;
 
386
                    break;
 
387
                case '8':
 
388
                    unicodeLength++;
 
389
                    break;
 
390
                case '9':
 
391
                    unicodeLength++;
 
392
                    break;
 
393
                case ':':
 
394
                    unicodeLength++;
 
395
                    break;
 
396
                case ';':
 
397
                    unicodeLength++;
 
398
                    break;
 
399
                case '<':
 
400
                    return -1;
 
401
                case '=':
 
402
                    unicodeLength++;
 
403
                    break;
 
404
                case '>':
 
405
                    return -1;
 
406
                default:
 
407
                    if (c < 0xd800 || c > 0xDBFF) unicodeLength++;
 
408
            }
 
409
        }
 
410
        return unicodeLength;
 
411
 
 
412
    }
 
413
    
 
414
}