source: trunk/src/xmlbuffer.c @ 46

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

Replace stat(filename) with fstat(fileno(infile)).

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