source: trunk/src/xmlbuffer.c @ 59

Last change on this file since 59 was 56, checked in by cameron, 11 years ago

content_start_pos if no XML/text decl

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        // Install null sentinels.
296        memset(&bytedata[chars_read], 0, BUFFER_PADDING);
297        uint16_t * XML_dbl_byte = (uint16_t *) src_data;
298        switch (XML_dbl_byte[0]) {
299                case x0000:
300                        switch (XML_dbl_byte[1]) {
301                                case xFEFF: return new U32BE_Buffer(src_data, chars_read, 1);
302                                case xFFFE: return new U32_2143_Buffer(src_data, chars_read, 1);
303                                case x3C00: return new U32_2143_Buffer(src_data, chars_read, 0);
304                                default: return new U32BE_Buffer(src_data, chars_read, 0);
305                        }
306                case xFEFF:
307                        if (XML_dbl_byte[1] == x0000) 
308                                return new U32_3412_Buffer(src_data, chars_read, 1);
309                        else return new U16BE_Buffer(src_data, chars_read, 1);
310                case xFFFE:
311                        if (XML_dbl_byte[1] == x0000) 
312                                return new U32LE_Buffer(src_data, chars_read, 1);
313                        else return new U16LE_Buffer(src_data, chars_read, 1);
314                case x003C:
315                        if (XML_dbl_byte[1] == x0000) 
316                                return new U32_3412_Buffer(src_data, chars_read, 0);
317                        else return new U16BE_Buffer(src_data, chars_read, 0);
318                case x3C00:
319                        if (XML_dbl_byte[1] == x0000) 
320                                return new U32LE_Buffer(src_data, chars_read, 0);
321                        else return new U16LE_Buffer(src_data, chars_read, 0);
322                case x4C6F:
323                        if (XML_dbl_byte[1] == xA794) 
324                                return new EBCDIC_Buffer(src_data, chars_read, 0);
325                        else return new Extended_ASCII_8_Buffer(src_data, chars_read, 0);
326                case xEFBE:
327                        if (bytedata[2] == 0xBF) 
328                                return new Extended_ASCII_8_Buffer(src_data, chars_read, 3);
329                        else return new Extended_ASCII_8_Buffer(src_data, chars_read, 0);
330                default:
331                        return new Extended_ASCII_8_Buffer(src_data, chars_read, 0);
332        }
333}
334
335
336XML_Buffer_Interface::~XML_Buffer_Interface() {
337  simd_delete(ByteBuffer);
338}
339
340int XML_Buffer_Interface::AvailableUnits(int pos) {
341        return (buffer_bytes/(int) code_unit_size) - pos;
342}
343
344
345
346template <CodeUnit_Base C>
347inline void XML_Buffer<C>::Scan_WS() {
348        while (at_WhiteSpace<XML_1_0, C>(cur())) Advance(1);
349}
350
351inline bool AtEOS(unsigned char * s) {
352        return s[0] == 0;
353}
354
355template <CodeUnit_Base C>
356inline void XML_Buffer<C>::ScanToQuote() {
357        while(!AtChar<ASCII,'<'>(cur()) && !AtChar<ASCII,'&'>(cur()) 
358                && !AtQuote<ASCII>(cur()) && !AtEOS(cur()))
359                Advance(1);
360}
361
362void DeclarationError(int pos) {
363        printf("Parsing error at position %i in XML or Text declaration.\n", pos);
364        exit(-1);
365}
366
367//
368// The following does not yet validate the syntax of EncNames.
369// EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
370// Future approach: first use lookup in EncNameTable,
371//           if not found, do case convert, try again,
372//             (avoids cost of case convert normally)
373//           if not found, validate syntax of EncNames,
374//           report error or EncName unknown.
375//
376template <CodeUnit_Base C>
377void XML_Buffer<C>::ReadXMLInfo() {
378        version = no_XML_version_value;
379        has_encoding_decl = false;
380        standalone = Standalone_no_value;
381        int decl_start = AbsPos();
382        // It is possible that there is no XML declaration.
383        if (!at_XmlDecl_start<C>(cur())) {
384                content_start_pos = AbsPos();
385                return;
386        }
387        // Otherwise, the XML declaration exists and must have
388        // at least version information.
389        Advance(6);
390        Scan_WS();
391        if (!at_version<C>(cur())) DeclarationError(AbsPos());
392        Advance(7);
393        Scan_WS();
394        if (!AtChar<C,'='>(cur())) DeclarationError(AbsPos());
395        Advance(1);
396        Scan_WS();
397        if (at_1_0<C>(cur())) version = XML_1_0;
398        else if (at_1_1<C>(cur())) version = XML_1_1;
399        else DeclarationError(AbsPos());
400        Advance(5);
401        if (at_PI_End<C>(cur())) {
402                Advance(2);
403                content_start_pos = AbsPos();
404                return;
405        }
406        if (!at_WhiteSpace<XML_1_0, ASCII>(cur())) DeclarationError(AbsPos());
407        Scan_WS();
408        if (at_encoding<C>(cur())) {
409                has_encoding_decl = true;
410                Advance(8);
411                Scan_WS();
412                if (!AtChar<C,'='>(cur())) DeclarationError(AbsPos());
413                Advance(1);
414                Scan_WS();
415                encoding_start_pos = AbsPos()+1;
416                if (AtQuote<C>(cur())) {
417                        unsigned char quoteCh = cur()[0];
418                        Advance(1);
419                        ScanToQuote();
420                        if (cur()[0] != quoteCh) DeclarationError(AbsPos());
421                }
422                else DeclarationError(AbsPos());
423                encoding_lgth = AbsPos()-encoding_start_pos;
424                Advance(1);
425                if (at_PI_End<C>(cur())) {
426                        Advance(2);
427                        content_start_pos = AbsPos();
428                        return;
429                }
430                if (!at_WhiteSpace<XML_1_0, ASCII>(cur())) DeclarationError(AbsPos());
431                Scan_WS();
432        }
433        if (at_standalone<C>(cur())) {
434                Advance(10);
435                Scan_WS();
436                if (!AtChar<C,'='>(cur())) DeclarationError(AbsPos());
437                Advance(1);
438                Scan_WS();
439                if (at_yes<C>(cur())) {Advance(5); standalone = Standalone_yes;}
440                else if (at_no<C>(cur())) {Advance(4); standalone = Standalone_no;}
441                else DeclarationError(AbsPos());
442                Scan_WS();
443        }
444        if (!at_PI_End<C>(cur())) DeclarationError(AbsPos());
445        Advance(2);
446        content_start_pos = AbsPos();
447}
448
449// Similar to reading the XML_declaration of the document entity,
450// ReadTextDeclaration reads the text declaration of an external
451// parsed entity.  This is not really needed at present, for DTDless
452// processing.
453template <CodeUnit_Base C>
454void XML_Buffer<C>::ReadTextDeclaration() {
455        version = no_XML_version_value;
456        has_encoding_decl = false;
457        standalone = Standalone_no_value;
458        int decl_start = AbsPos();
459        // It is possible that there is no XML declaration.
460        if (!at_XmlDecl_start<C>(cur())) {
461                content_start_pos = AbsPos();
462                return;
463        }
464        // Otherwise, the text declaration exists and may have
465        // version information.
466        Advance(6);
467        Scan_WS();
468        if (at_version<C>(cur())) {
469                Advance(7);
470                Scan_WS();
471                if (!AtChar<C,'='>(cur())) DeclarationError(AbsPos());
472                Advance(1);
473                Scan_WS();
474                if (at_1_0<C>(cur())) version = XML_1_0;
475                else if (at_1_1<C>(cur())) version = XML_1_1;
476                else DeclarationError(AbsPos());
477                Advance(5);
478                // Must have whitespace character before declaration.
479                if (!at_WhiteSpace<XML_1_0, ASCII>(cur())) DeclarationError(AbsPos());
480                Scan_WS();
481        }
482        if (!at_encoding<C>(cur())) DeclarationError(AbsPos());
483        has_encoding_decl = true;
484        Advance(8);
485        Scan_WS();
486        if (!AtChar<C,'='>(cur())) DeclarationError(AbsPos());
487        Advance(1);
488        Scan_WS();
489        encoding_start_pos = AbsPos()+1;
490        if (AtQuote<C>(cur())) {
491                unsigned char quoteCh = cur()[0];
492                Advance(1);
493                ScanToQuote();
494                if (cur()[0] != quoteCh) DeclarationError(AbsPos());
495        }
496        else DeclarationError(AbsPos());
497        encoding_lgth = AbsPos()-encoding_start_pos;
498        Advance(1);
499        Scan_WS();
500        if (!at_PI_End<C>(cur())) DeclarationError(AbsPos());
501        Advance(2);
502        content_start_pos = AbsPos();
503}
504
505int XML_Buffer_Interface::ContentStartUnit() {
506        return content_start_pos;
507}
508
Note: See TracBrowser for help on using the repository browser.