source: subversion/applications/utils/planetdiff/UTF8sanitizer.c @ 3718

Last change on this file since 3718 was 2536, checked in by jonb, 12 years ago

planetdiff - introduce an input buffer. Hide UTF8 error messages and remove some dead code

File size: 4.8 KB
Line 
1#include <stdio.h>
2#include <malloc.h>
3#include <string.h>
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <fcntl.h>
7#include <zlib.h>
8#include <bzlib.h>
9
10#include "sanitizer.h"
11#include "input.h"
12
13int sanitizerClose(void *context);
14int sanitizerProcess(void *context, char *buffer, int len);
15
16
17/* UTF8sanitizer algorithm has some nasty edge cases when trying to operate
18 * in a 'block at a time' mode. For example, in the following scenario:
19 *
20 * INPUT sequence is 2 buffers with a 6 byte char starting at X1
21 *
22 * [   len = 5   ]   [len = 1]
23 * X1 X2 X3 X4 X5   X6
24 *
25 * OUTPUT: nothing is generated for first buffer
26 * This will itself cause caller to assume EOF (hopefully normal reader will read >> 5 bytes).
27 * subsequent read of len=1 whille return all 6 bytes potentially causing output buffer overflow (and overwriting input data)
28 *
29 * The solution to this is to provide an elastic ring buffer which is used like a pipe
30 *
31 */
32
33
34struct Context {
35    long long line;
36    long long chars1, chars2, chars3, chars4, chars5, chars6;
37    int state, current_size;
38    int long_char[6];
39    int out_char[10];
40    int pend;
41    int verbose;
42    void *file;
43};
44
45
46int sanitizerClose(void *context)
47{
48    struct Context *ctx = context;
49    int r = inputClose(ctx->file);
50
51    if (ctx->verbose) {
52        fprintf(stderr, "Summary:\n");
53        fprintf(stderr, "chars1: %lld\n", ctx->chars1);
54        fprintf(stderr, "chars2: %lld\n", ctx->chars2);
55        fprintf(stderr, "chars3: %lld\n", ctx->chars3);
56        fprintf(stderr, "chars4: %lld\n", ctx->chars4);
57        fprintf(stderr, "chars5: %lld\n", ctx->chars5);
58        fprintf(stderr, "chars6: %lld\n", ctx->chars6);
59        fprintf(stderr, "lines : %lld\n", ctx->line);
60    }
61
62    free(ctx);
63    return r;
64}
65
66xmlTextReaderPtr sanitizerOpen(const char *name)
67{
68    struct Context *ctx = malloc (sizeof(*ctx));
69
70    if (!ctx)
71        return NULL;
72
73    memset(ctx, 0, sizeof(*ctx));
74    ctx->verbose = 0;
75    ctx->state = 1;
76    ctx->pend = 0;
77
78    ctx->file = inputOpen(name);
79    if (!ctx->file) {
80        fprintf(stderr, "Input reader create failed\n");
81        return NULL;
82    }
83
84    return xmlReaderForIO(sanitizerProcess, sanitizerClose, (void *)ctx, NULL, NULL, 0);
85}
86
87
88int sanitizerProcess(void *context, char *buffer, int len) 
89{
90  struct Context *ctx = context;
91  int current_char, i, out = 0;
92
93  while (out < len) {
94      if (ctx->pend) {
95          buffer[out++] = ctx->out_char[--ctx->pend];
96          continue;
97      }
98
99      current_char=inputGetChar(ctx->file);
100      if (inputEof(ctx->file))
101          break;
102 
103      if ((current_char & 128) == 0) {
104          //Handle_ASCII_char();
105          if (current_char == '\n') 
106              ctx->line++;
107          else
108              ctx->chars1++;
109          if (ctx->state != 1) {
110              if (ctx->verbose)
111                  fprintf(stderr, "Error at line %lld\n", ctx->line);
112              buffer[out++] = '_';
113              ctx->state = 1;
114          } 
115          //  buffer[out++] = current_char;
116          ctx->out_char[ctx->pend++] = current_char;
117      } else if ((current_char & (128+64)) == 128) {
118          // Handle_continue_char();
119          if(ctx->state > 1) {
120              ctx->state--;
121              if(ctx->state==1) {
122                  // long char finished
123                  //for(i=1; i<ctx->current_size; i++) {
124                  //  buffer[out++] = ctx->long_char[i-1];
125                  //}
126                  //buffer[out++] = current_char;
127                  ctx->out_char[ctx->pend++] = current_char;
128                  for(i=ctx->current_size-1; i>0; i--) {
129                      ctx->out_char[ctx->pend++] = ctx->long_char[i-1];
130                  }
131              }
132          } else {
133              if (ctx->verbose)
134                  fprintf(stderr, "Error at line %lld\n", ctx->line);
135              buffer[out++] = '_';
136              ctx->state=1;
137          }
138      } else if ((current_char & (128+64+32)) == (128+64)) {
139          //Handle_two_bytes();
140          ctx->state=2;
141          ctx->chars2++;
142          ctx->current_size=2;
143      } else if ((current_char & (128+64+32+16)) == (128+64+32)) {
144          //Handle_three_bytes();
145          ctx->state=3;
146          ctx->chars3++;
147          ctx->current_size=3;
148      } else if ((current_char & (128+64+32+16+8)) == (128+64+32+16)) {
149          //Handle_four_bytes();
150          ctx->state=4;
151          ctx->chars4++;
152          ctx->current_size=4;
153      } else if ((current_char & (128+64+32+16+8+4)) == (128+64+32+16+8)) {
154          //Handle_five_bytes();
155          ctx->state=5;
156          ctx->chars5++;
157          ctx->current_size=5;
158      } else if ((current_char & (128+64+32+16+8+4+2)) == (128+64+32+16+8+4)) {
159          //Handle_six_bytes();
160          ctx->state=6;
161          ctx->chars6++;
162          ctx->current_size=6;
163      }
164      if(ctx->state>1) {
165          ctx->long_char[ctx->current_size-ctx->state]=current_char;
166      }
167  }
168  return out;
169}
Note: See TracBrowser for help on using the repository browser.