source: trunk/src/xmlbuffer.c @ 44

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

lib_simd: refactored allocation, bitstream_scan

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