source: trunk/src/xmlbuffer.c @ 52

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

Destructors

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