source: subversion/applications/utils/export/osm2pgsql-64/UTF8sanitizer.c @ 26020

Last change on this file since 26020 was 2827, checked in by jonb, 13 years ago

osm2pgsql - make experimental version current, move previous implementation to legacy

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