source: trunk/src/xmlbuffer.c @ 61

Last change on this file since 61 was 61, checked in by ksherdy, 11 years ago

Close the input file after the data read is complete.

File size: 14.8 KB
Line 
1/*  xmlbuffer.c - Input buffering for XML entities.
2    Copyright (c) 2007, 2008, Robert D. Cameron.
3    Licensed to the public under the Open Software License 3.0.
4    Licensed to International Characters, Inc., under the Academic
5    Free License 3.0.
6
7*/
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <errno.h>
12#include <sys/types.h>
13#include <sys/stat.h>
14#include "xmlbuffer.h"
15#include "multiliteral.h"
16#include "bytelex.h"
17
18XML_Buffer_Interface::XML_Buffer_Interface() {}
19
20template <CodeUnit_Base C>
21XML_Buffer<C>::XML_Buffer(BytePack * src, int lgth, int BOM)
22        : XML_Buffer_Interface() {
23        ByteBuffer = src;
24        buffer_bytes = lgth;
25        BOM_units = BOM;
26        code_unit_base = C;
27        current_unit = BOM_units; /* skip the BOM for parsing.*/
28}
29
30Extended_ASCII_8_Buffer::Extended_ASCII_8_Buffer(BytePack * src, int lgth, int BOM)
31        : XML_Buffer<ASCII>(src, lgth, BOM) {
32        code_unit_size = SingleByte;
33        total_blocks = (buffer_bytes + BLOCKSIZE - 1)/BLOCKSIZE;
34        byte_order = BigEndian;  /* dummy value; byte order irrelevant for single-byte units.*/
35}
36
37EBCDIC_Buffer::EBCDIC_Buffer(BytePack * src, int lgth, int BOM)
38        : XML_Buffer<EBCDIC>(src, lgth, BOM) {
39        code_unit_size = SingleByte;
40        total_blocks = (buffer_bytes + BLOCKSIZE - 1)/BLOCKSIZE;
41        byte_order = BigEndian;
42}
43
44const int LOOKAHEAD_PACKS = (LOOKAHEAD_POSITIONS - 1)/PACKSIZE + 1;
45
46U16_Buffer::U16_Buffer(BytePack * src, int lgth, int BOM)
47        : XML_Buffer<ASCII>(src, lgth, BOM) {
48        code_unit_size = DoubleByte;
49        total_blocks = (buffer_bytes/2 + BLOCKSIZE - 1)/BLOCKSIZE;
50        if (buffer_bytes % 2 != 0) {
51                printf("Error: Incomplete code unit at end of file.\n");
52                exit(-1);
53        }
54        x16hi = simd_new(8*total_blocks+LOOKAHEAD_PACKS);
55        x16lo = simd_new(8*total_blocks+LOOKAHEAD_PACKS);
56}
57
58U16_Buffer::~U16_Buffer() {
59  simd_delete((SIMD_type *) x16hi);
60  simd_delete((SIMD_type *) x16lo);
61  simd_delete((SIMD_type *) x8data);
62}
63
64U16LE_Buffer::U16LE_Buffer(BytePack * src, int lgth, int BOM)
65        : U16_Buffer(src, lgth, BOM) {
66        byte_order = LittleEndian;
67}
68
69U16BE_Buffer::U16BE_Buffer(BytePack * src, int lgth, int BOM)
70        : U16_Buffer(src, lgth, BOM) {
71        byte_order = BigEndian;
72}
73
74U32_Buffer::U32_Buffer(BytePack * src, int lgth, int BOM)
75        : XML_Buffer<ASCII>(src, lgth, BOM) {
76        code_unit_size = QuadByte;
77        total_blocks = (buffer_bytes/4 + BLOCKSIZE - 1)/BLOCKSIZE;
78        if (buffer_bytes % 4 != 0) {
79                printf("Error: Incomplete code unit at end of file.\n");
80                exit(-1);
81        }
82        x32hh = simd_new(8*total_blocks+LOOKAHEAD_PACKS);
83        x32hl = simd_new(8*total_blocks+LOOKAHEAD_PACKS);
84        x32lh = simd_new(8*total_blocks+LOOKAHEAD_PACKS);
85        x32ll = simd_new(8*total_blocks+LOOKAHEAD_PACKS);
86}
87
88U32_Buffer::~U32_Buffer() {
89  simd_delete((SIMD_type *) x32hh);
90  simd_delete((SIMD_type *) x32hl);
91  simd_delete((SIMD_type *) x32lh);
92  simd_delete((SIMD_type *) x32ll);
93  simd_delete((SIMD_type *) x8data);
94}
95
96U32LE_Buffer::U32LE_Buffer(BytePack * src, int lgth, int BOM)
97        : U32_Buffer(src, lgth, BOM) {
98        byte_order = LittleEndian;
99}
100
101U32BE_Buffer::U32BE_Buffer(BytePack * src, int lgth, int BOM)
102        : U32_Buffer(src, lgth, BOM) {
103        byte_order = BigEndian;
104}
105
106U32_2143_Buffer::U32_2143_Buffer(BytePack * src, int lgth, int BOM)
107        : U32_Buffer(src, lgth, BOM) {
108        byte_order = Unusual_2143;
109}
110
111U32_3412_Buffer::U32_3412_Buffer(BytePack * src, int lgth, int BOM)
112        : U32_Buffer(src, lgth, BOM) {
113        byte_order = Unusual_3412;
114}
115
116
117/* Byteplex methods.
118
119   No byteplexing is required for 8-bit code units; byteplex methods are no-ops.
120
121*/
122
123void Extended_ASCII_8_Buffer::DoByteplex() {}
124
125void EBCDIC_Buffer::DoByteplex() {}
126
127
128inline void DoDuplex(BytePack * src_data, int total_blocks,
129                                         BytePack * p0, BytePack * p1) {
130        int total_packs = 8*total_blocks + LOOKAHEAD_PACKS;
131        for (int pk = 0; pk < total_packs; pk++) {
132                BytePack s0 = src_data[2*pk];
133                BytePack s1 = src_data[2*pk+1];
134#if (BYTE_ORDER == LITTLE_ENDIAN)
135                p0[pk] = simd_pack_16_ll(s1, s0);
136                p1[pk] = simd_pack_16_hh(s1, s0);
137#endif
138#if (BYTE_ORDER == BIG_ENDIAN)
139                p0[pk] = simd_pack_16_hh(s0, s1);
140                p1[pk] = simd_pack_16_ll(s0, s1);
141#endif
142        }
143}
144                                         
145void U16LE_Buffer::DoByteplex() {
146        DoDuplex(ByteBuffer, total_blocks, x16lo, x16hi);
147}
148
149void U16BE_Buffer::DoByteplex() {
150        DoDuplex(ByteBuffer, total_blocks, x16hi, x16lo);
151}
152
153inline void DoQuadplex(BytePack * src_data, int total_blocks,
154                                BytePack * p0, BytePack * p1, BytePack * p2, BytePack * p3) {
155        int total_packs = 8*total_blocks + LOOKAHEAD_PACKS;
156        for (int pk = 0; pk < total_packs; pk++) {
157                BytePack s0 = src_data[4*pk];
158                BytePack s1 = src_data[4*pk+1];
159                BytePack s2 = src_data[4*pk+2];
160                BytePack s3 = src_data[4*pk+3];
161#if (BYTE_ORDER == LITTLE_ENDIAN)
162                BytePack p02_0 = simd_pack_16_ll(s1, s0);
163                BytePack p13_0 = simd_pack_16_hh(s1, s0);
164                BytePack p02_1 = simd_pack_16_ll(s3, s2);
165                BytePack p13_1 = simd_pack_16_hh(s3, s2);
166                p0[pk] = simd_pack_16_ll(p02_1, p02_0);
167                p1[pk] = simd_pack_16_ll(p13_1, p13_0);
168                p2[pk] = simd_pack_16_hh(p02_1, p02_0);
169                p3[pk] = simd_pack_16_hh(p13_1, p13_0);
170#endif
171#if (BYTE_ORDER == BIG_ENDIAN)
172                BytePack p02_0 = simd_pack_16_hh(s0, s1);
173                BytePack p13_0 = simd_pack_16_ll(s0, s1);
174                BytePack p02_1 = simd_pack_16_hh(s2, s3);
175                BytePack p13_1 = simd_pack_16_ll(s2, s3);
176                p0[pk] = simd_pack_16_hh(p02_0, p02_1);
177                p1[pk] = simd_pack_16_hh(p13_0, p13_1);
178                p2[pk] = simd_pack_16_ll(p02_0, p02_1);
179                p3[pk] = simd_pack_16_ll(p13_0, p13_1);
180#endif
181        }
182}
183
184void U32LE_Buffer::DoByteplex() {
185        DoQuadplex(ByteBuffer, total_blocks, x32ll, x32lh, x32hl, x32hh);
186}
187
188void U32BE_Buffer::DoByteplex() {
189        DoQuadplex(ByteBuffer, total_blocks, x32hh, x32hl, x32lh, x32ll);
190}
191
192void U32_2143_Buffer::DoByteplex() {
193        DoQuadplex(ByteBuffer, total_blocks, x32hl, x32hh, x32ll, x32lh);
194}
195
196void U32_3412_Buffer::DoByteplex() {
197        DoQuadplex(ByteBuffer, total_blocks, x32lh, x32ll, x32hh, x32hl);
198}
199
200
201/* Pseudo-ASCII stream methods */
202
203void Extended_ASCII_8_Buffer::PreparePseudoASCII_Stream() {
204        x8data = ByteBuffer;
205}
206
207void EBCDIC_Buffer::PreparePseudoASCII_Stream() {
208        x8data = ByteBuffer;
209}
210
211void U16_Buffer::PreparePseudoASCII_Stream() {
212        int total_packs = 8*(buffer_bytes/2 + BLOCKSIZE - 1)/BLOCKSIZE + LOOKAHEAD_PACKS;
213        x8data = simd_new(total_packs);
214        for (int pk = 0; pk < total_packs; pk++) {
215                x8data[pk] = simd_or(x16lo[pk], 
216                                     simd_andc(simd_const_8(0x80), 
217                                               simd_eq_8(x16hi[pk], simd_const_8(0))));
218        }
219}
220
221void U32_Buffer::PreparePseudoASCII_Stream() {
222        int total_packs = 8*(buffer_bytes/2 + BLOCKSIZE - 1)/BLOCKSIZE + LOOKAHEAD_PACKS;
223        x8data = simd_new(total_packs);
224        for (int pk = 0; pk < total_packs; pk++) {
225                BytePack hi = simd_or(simd_or(x32hh[pk], x32hl[pk]), x32lh[pk]);
226                x8data[pk] = simd_or(x32ll[pk], 
227                                     simd_andc(simd_const_8(0x80), 
228                                               simd_eq_8(hi, simd_const_8(0))));
229        }
230}
231
232
233template <CodeUnit_Base C>
234inline int XML_Buffer<C>::AbsPos() const {
235        return current_unit;
236}
237
238template <CodeUnit_Base C>
239inline unsigned char * XML_Buffer<C>::cur() const {
240        return &((unsigned char *) x8data)[current_unit];
241}
242
243template <CodeUnit_Base C>
244inline void XML_Buffer<C>::Advance(int n) {
245        current_unit += n;
246}
247
248
249/* To avoid any potential for a segmentation fault when loading
250   and processing the final block of input, the input buffer
251   is made one full block larger than required to handle the
252   input file plus sentinel. */
253
254const int MAX_CODE_UNIT_SIZE = 4;
255const int BUFFER_PADDING = MAX_CODE_UNIT_SIZE * BLOCKSIZE;
256
257
258/* Signature-based character set family detection in accord with
259   Appendix F of the XML 1.0 and 1.1 specifications. */
260
261/* These definitions use b2int16 to determine appropriate doublebyte
262   values based on endianness of the underlying architecture. */
263static const int x0000 = b2int16<0x00, 0x00>::value;
264static const int xFEFF = b2int16<0xFE, 0xFF>::value;
265static const int xFFFE = b2int16<0xFF, 0xFE>::value;
266static const int x003C = b2int16<0x00, 0x3C>::value;
267static const int x3C00 = b2int16<0x3C, 0x00>::value;
268static const int x4C6F = b2int16<0x4C, 0x6F>::value;
269static const int xA794 = b2int16<0xA7, 0x94>::value;
270static const int xEFBE = b2int16<0xEF, 0xBE>::value;
271
272
273XML_Buffer_Interface * XML_Buffer_Interface::BufferFactory(char* filename) {
274        int chars_read;
275        FILE *infile;
276        infile = fopen(filename, "rb");
277        if (!infile) {
278                fprintf(stderr, "Error: cannot open %s for input.\n", filename);
279                exit(-1);
280        }
281        struct stat fileinfo;
282        if(fstat(fileno(infile), &fileinfo)!=0) {
283                fprintf(stderr, "Error: cannot fstat %s for file size.\n", filename);
284                exit(-1);
285        }
286        int buffer_packs = (fileinfo.st_size + BUFFER_PADDING + PACKSIZE - 1)/PACKSIZE;
287        BytePack * src_data = simd_new(buffer_packs);
288        unsigned char * bytedata = (unsigned char *) src_data;
289        chars_read = fread(bytedata, 1, fileinfo.st_size, infile);
290        if (chars_read != fileinfo.st_size) {
291                fprintf(stderr, "Error: fread returned %i characters, expecting %i.\n",
292                        chars_read, fileinfo.st_size);
293                exit(-1);
294        }
295       
296    fclose(infile);
297       
298        // Install null sentinels.
299        memset(&bytedata[chars_read], 0, BUFFER_PADDING);
300        uint16_t * XML_dbl_byte = (uint16_t *) src_data;
301        switch (XML_dbl_byte[0]) {
302                case x0000:
303                        switch (XML_dbl_byte[1]) {
304                                case xFEFF: return new U32BE_Buffer(src_data, chars_read, 1);
305                                case xFFFE: return new U32_2143_Buffer(src_data, chars_read, 1);
306                                case x3C00: return new U32_2143_Buffer(src_data, chars_read, 0);
307                                default: return new U32BE_Buffer(src_data, chars_read, 0);
308                        }
309                case xFEFF:
310                        if (XML_dbl_byte[1] == x0000) 
311                                return new U32_3412_Buffer(src_data, chars_read, 1);
312                        else return new U16BE_Buffer(src_data, chars_read, 1);
313                case xFFFE:
314                        if (XML_dbl_byte[1] == x0000) 
315                                return new U32LE_Buffer(src_data, chars_read, 1);
316                        else return new U16LE_Buffer(src_data, chars_read, 1);
317                case x003C:
318                        if (XML_dbl_byte[1] == x0000) 
319                                return new U32_3412_Buffer(src_data, chars_read, 0);
320                        else return new U16BE_Buffer(src_data, chars_read, 0);
321                case x3C00:
322                        if (XML_dbl_byte[1] == x0000) 
323                                return new U32LE_Buffer(src_data, chars_read, 0);
324                        else return new U16LE_Buffer(src_data, chars_read, 0);
325                case x4C6F:
326                        if (XML_dbl_byte[1] == xA794) 
327                                return new EBCDIC_Buffer(src_data, chars_read, 0);
328                        else return new Extended_ASCII_8_Buffer(src_data, chars_read, 0);
329                case xEFBE:
330                        if (bytedata[2] == 0xBF) 
331                                return new Extended_ASCII_8_Buffer(src_data, chars_read, 3);
332                        else return new Extended_ASCII_8_Buffer(src_data, chars_read, 0);
333                default:
334                        return new Extended_ASCII_8_Buffer(src_data, chars_read, 0);
335        }
336}
337
338
339XML_Buffer_Interface::~XML_Buffer_Interface() {
340  simd_delete(ByteBuffer);
341}
342
343int XML_Buffer_Interface::AvailableUnits(int pos) {
344        return (buffer_bytes/(int) code_unit_size) - pos;
345}
346
347
348
349template <CodeUnit_Base C>
350inline void XML_Buffer<C>::Scan_WS() {
351        while (at_WhiteSpace<XML_1_0, C>(cur())) Advance(1);
352}
353
354inline bool AtEOS(unsigned char * s) {
355        return s[0] == 0;
356}
357
358template <CodeUnit_Base C>
359inline void XML_Buffer<C>::ScanToQuote() {
360        while(!AtChar<ASCII,'<'>(cur()) && !AtChar<ASCII,'&'>(cur()) 
361                && !AtQuote<ASCII>(cur()) && !AtEOS(cur()))
362                Advance(1);
363}
364
365void DeclarationError(int pos) {
366        printf("Parsing error at position %i in XML or Text declaration.\n", pos);
367        exit(-1);
368}
369
370//
371// The following does not yet validate the syntax of EncNames.
372// EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
373// Future approach: first use lookup in EncNameTable,
374//           if not found, do case convert, try again,
375//             (avoids cost of case convert normally)
376//           if not found, validate syntax of EncNames,
377//           report error or EncName unknown.
378//
379template <CodeUnit_Base C>
380void XML_Buffer<C>::ReadXMLInfo() {
381        version = no_XML_version_value;
382        has_encoding_decl = false;
383        standalone = Standalone_no_value;
384        int decl_start = AbsPos();
385        // It is possible that there is no XML declaration.
386        if (!at_XmlDecl_start<C>(cur())) {
387                content_start_pos = AbsPos();
388                return;
389        }
390        // Otherwise, the XML declaration exists and must have
391        // at least version information.
392        Advance(6);
393        Scan_WS();
394        if (!at_version<C>(cur())) DeclarationError(AbsPos());
395        Advance(7);
396        Scan_WS();
397        if (!AtChar<C,'='>(cur())) DeclarationError(AbsPos());
398        Advance(1);
399        Scan_WS();
400        if (at_1_0<C>(cur())) version = XML_1_0;
401        else if (at_1_1<C>(cur())) version = XML_1_1;
402        else DeclarationError(AbsPos());
403        Advance(5);
404        if (at_PI_End<C>(cur())) {
405                Advance(2);
406                content_start_pos = AbsPos();
407                return;
408        }
409        if (!at_WhiteSpace<XML_1_0, ASCII>(cur())) DeclarationError(AbsPos());
410        Scan_WS();
411        if (at_encoding<C>(cur())) {
412                has_encoding_decl = true;
413                Advance(8);
414                Scan_WS();
415                if (!AtChar<C,'='>(cur())) DeclarationError(AbsPos());
416                Advance(1);
417                Scan_WS();
418                encoding_start_pos = AbsPos()+1;
419                if (AtQuote<C>(cur())) {
420                        unsigned char quoteCh = cur()[0];
421                        Advance(1);
422                        ScanToQuote();
423                        if (cur()[0] != quoteCh) DeclarationError(AbsPos());
424                }
425                else DeclarationError(AbsPos());
426                encoding_lgth = AbsPos()-encoding_start_pos;
427                Advance(1);
428                if (at_PI_End<C>(cur())) {
429                        Advance(2);
430                        content_start_pos = AbsPos();
431                        return;
432                }
433                if (!at_WhiteSpace<XML_1_0, ASCII>(cur())) DeclarationError(AbsPos());
434                Scan_WS();
435        }
436        if (at_standalone<C>(cur())) {
437                Advance(10);
438                Scan_WS();
439                if (!AtChar<C,'='>(cur())) DeclarationError(AbsPos());
440                Advance(1);
441                Scan_WS();
442                if (at_yes<C>(cur())) {Advance(5); standalone = Standalone_yes;}
443                else if (at_no<C>(cur())) {Advance(4); standalone = Standalone_no;}
444                else DeclarationError(AbsPos());
445                Scan_WS();
446        }
447        if (!at_PI_End<C>(cur())) DeclarationError(AbsPos());
448        Advance(2);
449        content_start_pos = AbsPos();
450}
451
452// Similar to reading the XML_declaration of the document entity,
453// ReadTextDeclaration reads the text declaration of an external
454// parsed entity.  This is not really needed at present, for DTDless
455// processing.
456template <CodeUnit_Base C>
457void XML_Buffer<C>::ReadTextDeclaration() {
458        version = no_XML_version_value;
459        has_encoding_decl = false;
460        standalone = Standalone_no_value;
461        int decl_start = AbsPos();
462        // It is possible that there is no XML declaration.
463        if (!at_XmlDecl_start<C>(cur())) {
464                content_start_pos = AbsPos();
465                return;
466        }
467        // Otherwise, the text declaration exists and may have
468        // version information.
469        Advance(6);
470        Scan_WS();
471        if (at_version<C>(cur())) {
472                Advance(7);
473                Scan_WS();
474                if (!AtChar<C,'='>(cur())) DeclarationError(AbsPos());
475                Advance(1);
476                Scan_WS();
477                if (at_1_0<C>(cur())) version = XML_1_0;
478                else if (at_1_1<C>(cur())) version = XML_1_1;
479                else DeclarationError(AbsPos());
480                Advance(5);
481                // Must have whitespace character before declaration.
482                if (!at_WhiteSpace<XML_1_0, ASCII>(cur())) DeclarationError(AbsPos());
483                Scan_WS();
484        }
485        if (!at_encoding<C>(cur())) DeclarationError(AbsPos());
486        has_encoding_decl = true;
487        Advance(8);
488        Scan_WS();
489        if (!AtChar<C,'='>(cur())) DeclarationError(AbsPos());
490        Advance(1);
491        Scan_WS();
492        encoding_start_pos = AbsPos()+1;
493        if (AtQuote<C>(cur())) {
494                unsigned char quoteCh = cur()[0];
495                Advance(1);
496                ScanToQuote();
497                if (cur()[0] != quoteCh) DeclarationError(AbsPos());
498        }
499        else DeclarationError(AbsPos());
500        encoding_lgth = AbsPos()-encoding_start_pos;
501        Advance(1);
502        Scan_WS();
503        if (!at_PI_End<C>(cur())) DeclarationError(AbsPos());
504        Advance(2);
505        content_start_pos = AbsPos();
506}
507
508int XML_Buffer_Interface::ContentStartUnit() {
509        return content_start_pos;
510}
511
Note: See TracBrowser for help on using the repository browser.