source: trunk/src/xmlbuffer.c @ 35

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

Charset Architecture: Byteplexing Buffer Factory

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