/src/dcmtk/oficonv/libsrc/citrus_mapper_zone.c
Line | Count | Source |
1 | | /*- |
2 | | * Copyright (c)2003 Citrus Project, |
3 | | * All rights reserved. |
4 | | * |
5 | | * Redistribution and use in source and binary forms, with or without |
6 | | * modification, are permitted provided that the following conditions |
7 | | * are met: |
8 | | * 1. Redistributions of source code must retain the above copyright |
9 | | * notice, this list of conditions and the following disclaimer. |
10 | | * 2. Redistributions in binary form must reproduce the above copyright |
11 | | * notice, this list of conditions and the following disclaimer in the |
12 | | * documentation and/or other materials provided with the distribution. |
13 | | * |
14 | | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
15 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
16 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
17 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
18 | | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
19 | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
20 | | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
21 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
22 | | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
23 | | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
24 | | * SUCH DAMAGE. |
25 | | */ |
26 | | |
27 | | #include "dcmtk/config/osconfig.h" |
28 | | #include "citrus_mapper_zone.h" |
29 | | |
30 | | #ifdef HAVE_SYS_QUEUE_H |
31 | | #include <sys/queue.h> |
32 | | #else |
33 | | #include "dcmtk/oficonv/queue.h" |
34 | | #endif |
35 | | |
36 | | #include <errno.h> |
37 | | #include <stdio.h> |
38 | | #include <stdlib.h> |
39 | | #include <string.h> |
40 | | |
41 | | #include "citrus_bcs.h" |
42 | | #include "citrus_types.h" |
43 | | #include "citrus_module.h" |
44 | | #include "citrus_region.h" |
45 | | #include "citrus_memstream.h" |
46 | | #include "citrus_mmap.h" |
47 | | #include "citrus_hash.h" |
48 | | #include "citrus_mapper.h" |
49 | | |
50 | | /* ---------------------------------------------------------------------- */ |
51 | | |
52 | | _CITRUS_MAPPER_DECLS(mapper_zone); |
53 | | _CITRUS_MAPPER_DEF_OPS(mapper_zone); |
54 | | |
55 | | |
56 | | /* ---------------------------------------------------------------------- */ |
57 | | |
58 | | struct _zone { |
59 | | uint32_t z_begin; |
60 | | uint32_t z_end; |
61 | | }; |
62 | | |
63 | | struct _citrus_mapper_zone { |
64 | | struct _zone mz_col; |
65 | | struct _zone mz_row; |
66 | | int32_t mz_col_offset; |
67 | | int32_t mz_row_offset; |
68 | | int mz_col_bits; |
69 | | }; |
70 | | |
71 | | struct _parse_state { |
72 | | enum { S_BEGIN, S_OFFSET } ps_state; |
73 | | union { |
74 | | uint32_t u_imm; |
75 | | int32_t s_imm; |
76 | | struct _zone zone; |
77 | | } u; |
78 | 0 | #define ps_u_imm u.u_imm |
79 | 0 | #define ps_s_imm u.s_imm |
80 | | #define ps_zone u.zone |
81 | | int ps_top; |
82 | | }; |
83 | | |
84 | | int |
85 | | _citrus_mapper_zone_mapper_getops(struct _citrus_mapper_ops *ops) |
86 | 0 | { |
87 | |
|
88 | 0 | memcpy(ops, &_citrus_mapper_zone_mapper_ops, |
89 | 0 | sizeof(_citrus_mapper_zone_mapper_ops)); |
90 | |
|
91 | 0 | return (0); |
92 | 0 | } |
93 | | |
94 | 0 | #define BUFSIZE 20 |
95 | 0 | #define T_ERR 0x100 |
96 | 0 | #define T_IMM 0x101 |
97 | | |
98 | | static int |
99 | | get_imm(struct _citrus_memory_stream *ms, struct _parse_state *ps) |
100 | 0 | { |
101 | 0 | int c, i, sign = 0; |
102 | 0 | char buf[BUFSIZE + 1]; |
103 | 0 | char *p; |
104 | |
|
105 | 0 | for (i = 0; i < BUFSIZE; i++) { |
106 | 0 | retry: |
107 | 0 | c = _citrus_memory_stream_peek(ms); |
108 | 0 | if (i == 0) { |
109 | 0 | if (sign == 0 && (c == '+' || c == '-')) { |
110 | 0 | sign = c; |
111 | 0 | _citrus_memory_stream_getc(ms); |
112 | 0 | goto retry; |
113 | 0 | } else if (!_citrus_bcs_isdigit((uint8_t)c)) |
114 | 0 | break; |
115 | 0 | } else if (!_citrus_bcs_isxdigit((uint8_t)c)) |
116 | 0 | if (!(i == 1 && c == 'x')) |
117 | 0 | break; |
118 | 0 | buf[i] = (char) _citrus_memory_stream_getc(ms); |
119 | 0 | } |
120 | 0 | buf[i] = '\0'; |
121 | 0 | ps->ps_u_imm = strtoul(buf, &p, 0); |
122 | 0 | if ((p - buf) != i) |
123 | 0 | return (T_ERR); |
124 | 0 | if (sign == '-') |
125 | 0 | ps->ps_u_imm = (unsigned long)-(long)ps->ps_u_imm; |
126 | 0 | return (T_IMM); |
127 | 0 | } |
128 | | |
129 | | static int |
130 | | get_tok(struct _citrus_memory_stream *ms, struct _parse_state *ps) |
131 | 0 | { |
132 | 0 | int c; |
133 | |
|
134 | 0 | loop: |
135 | 0 | c = _citrus_memory_stream_peek(ms); |
136 | 0 | if (c == 0x00) |
137 | 0 | return (EOF); |
138 | 0 | if (_citrus_bcs_isspace((uint8_t)c)) { |
139 | 0 | _citrus_memory_stream_getc(ms); |
140 | 0 | goto loop; |
141 | 0 | } |
142 | | |
143 | 0 | switch (ps->ps_state) { |
144 | 0 | case S_BEGIN: |
145 | 0 | switch (c) { |
146 | 0 | case ':': |
147 | 0 | case '-': |
148 | 0 | case '/': |
149 | 0 | _citrus_memory_stream_getc(ms); |
150 | 0 | return (c); |
151 | 0 | case '0': |
152 | 0 | case '1': |
153 | 0 | case '2': |
154 | 0 | case '3': |
155 | 0 | case '4': |
156 | 0 | case '5': |
157 | 0 | case '6': |
158 | 0 | case '7': |
159 | 0 | case '8': |
160 | 0 | case '9': |
161 | 0 | return (get_imm(ms, ps)); |
162 | 0 | } |
163 | 0 | break; |
164 | 0 | case S_OFFSET: |
165 | 0 | switch (c) { |
166 | 0 | case '/': |
167 | 0 | _citrus_memory_stream_getc(ms); |
168 | 0 | return (c); |
169 | 0 | case '+': |
170 | 0 | case '-': |
171 | 0 | case '0': |
172 | 0 | case '1': |
173 | 0 | case '2': |
174 | 0 | case '3': |
175 | 0 | case '4': |
176 | 0 | case '5': |
177 | 0 | case '6': |
178 | 0 | case '7': |
179 | 0 | case '8': |
180 | 0 | case '9': |
181 | 0 | return (get_imm(ms, ps)); |
182 | 0 | } |
183 | 0 | break; |
184 | 0 | } |
185 | 0 | return (T_ERR); |
186 | 0 | } |
187 | | |
188 | | static int |
189 | | parse_zone(struct _citrus_memory_stream *ms, struct _parse_state *ps, struct _zone *z) |
190 | 0 | { |
191 | |
|
192 | 0 | if (get_tok(ms, ps) != T_IMM) |
193 | 0 | return (-1); |
194 | 0 | z->z_begin = ps->ps_u_imm; |
195 | 0 | if (get_tok(ms, ps) != '-') |
196 | 0 | return (-1); |
197 | 0 | if (get_tok(ms, ps) != T_IMM) |
198 | 0 | return (-1); |
199 | 0 | z->z_end = ps->ps_u_imm; |
200 | |
|
201 | 0 | if (z->z_begin > z->z_end) |
202 | 0 | return (-1); |
203 | | |
204 | 0 | return (0); |
205 | 0 | } |
206 | | |
207 | | static int |
208 | | check_rowcol(struct _zone *z, int32_t ofs, uint32_t maxval) |
209 | 0 | { |
210 | 0 | uint32_t remain; |
211 | |
|
212 | 0 | if (maxval != 0 && z->z_end >= maxval) |
213 | 0 | return (-1); |
214 | | |
215 | 0 | if (ofs > 0) { |
216 | 0 | if (maxval == 0) |
217 | | /* this should 0x100000000 - z->z_end */ |
218 | 0 | remain = (z->z_end == 0) ? 0xFFFFFFFF : |
219 | 0 | 0xFFFFFFFF - z->z_end + 1; |
220 | 0 | else |
221 | 0 | remain = maxval - z->z_end; |
222 | 0 | if ((uint32_t)ofs > remain) |
223 | 0 | return (-1); |
224 | 0 | } else if (ofs < 0) { |
225 | 0 | if (z->z_begin < (uint32_t)-ofs) |
226 | 0 | return (-1); |
227 | 0 | } |
228 | | |
229 | 0 | return (0); |
230 | 0 | } |
231 | | |
232 | | static int |
233 | | parse_var(struct _citrus_mapper_zone *mz, struct _citrus_memory_stream *ms) |
234 | 0 | { |
235 | 0 | struct _parse_state ps; |
236 | 0 | uint32_t colmax, rowmax; |
237 | 0 | int isrc, ret; |
238 | |
|
239 | 0 | ps.ps_state = S_BEGIN; |
240 | |
|
241 | 0 | if (parse_zone(ms, &ps, &mz->mz_col)) |
242 | 0 | return (-1); |
243 | | |
244 | 0 | ret = get_tok(ms, &ps); |
245 | 0 | if (ret == '/') { |
246 | | /* rowzone / colzone / bits */ |
247 | 0 | isrc = 1; |
248 | 0 | mz->mz_row = mz->mz_col; |
249 | |
|
250 | 0 | if (parse_zone(ms, &ps, &mz->mz_col)) |
251 | 0 | return (-1); |
252 | 0 | if (get_tok(ms, &ps) != '/') |
253 | 0 | return (-1); |
254 | 0 | if (get_tok(ms, &ps) != T_IMM) |
255 | 0 | return (-1); |
256 | 0 | mz->mz_col_bits = ps.ps_u_imm; |
257 | 0 | if (mz->mz_col_bits < 0 || mz->mz_col_bits > 32) |
258 | 0 | return (-1); |
259 | 0 | ret = get_tok(ms, &ps); |
260 | 0 | } else { |
261 | | /* colzone */ |
262 | 0 | isrc = 0; |
263 | 0 | mz->mz_col_bits = 32; |
264 | 0 | mz->mz_row.z_begin = mz->mz_row.z_end = 0; |
265 | 0 | } |
266 | 0 | if (ret == ':') { |
267 | | /* offset */ |
268 | 0 | ps.ps_state = S_OFFSET; |
269 | 0 | if (get_tok(ms, &ps) != T_IMM) |
270 | 0 | return (-1); |
271 | 0 | mz->mz_col_offset = ps.ps_s_imm; |
272 | 0 | if (isrc) { |
273 | | /* row/col */ |
274 | 0 | mz->mz_row_offset = mz->mz_col_offset; |
275 | 0 | if (get_tok(ms, &ps) != '/') |
276 | 0 | return (-1); |
277 | 0 | if (get_tok(ms, &ps) != T_IMM) |
278 | 0 | return (-1); |
279 | 0 | mz->mz_col_offset = ps.ps_s_imm; |
280 | 0 | } else |
281 | 0 | mz->mz_row_offset = 0; |
282 | 0 | ret = get_tok(ms, &ps); |
283 | 0 | } |
284 | 0 | if (ret != EOF) |
285 | 0 | return (-1); |
286 | | |
287 | | /* sanity check */ |
288 | 0 | colmax = (mz->mz_col_bits == 32) ? 0 : 1 << mz->mz_col_bits; |
289 | 0 | rowmax = (mz->mz_col_bits == 0) ? 0 : 1 << (32-mz->mz_col_bits); |
290 | 0 | if (check_rowcol(&mz->mz_col, mz->mz_col_offset, colmax)) |
291 | 0 | return (-1); |
292 | 0 | if (check_rowcol(&mz->mz_row, mz->mz_row_offset, rowmax)) |
293 | 0 | return (-1); |
294 | | |
295 | 0 | return (0); |
296 | 0 | } |
297 | | |
298 | | static int |
299 | | /*ARGSUSED*/ |
300 | | _citrus_mapper_zone_mapper_init(struct _citrus_mapper_area * ma , |
301 | | struct _citrus_csmapper * cm, const char * dir , |
302 | | const void * var, size_t lenvar, |
303 | | struct _citrus_mapper_traits * mt, size_t lenmt) |
304 | 0 | { |
305 | 0 | struct _citrus_mapper_zone *mz; |
306 | 0 | struct _citrus_memory_stream ms; |
307 | 0 | struct _citrus_region r; |
308 | 0 | (void) ma; |
309 | 0 | (void) dir; |
310 | |
|
311 | 0 | if (lenmt < sizeof(*mt)) |
312 | 0 | return (EINVAL); |
313 | | |
314 | 0 | mz = malloc(sizeof(*mz)); |
315 | 0 | if (mz == NULL) |
316 | 0 | return (errno); |
317 | | |
318 | 0 | mz->mz_col.z_begin = mz->mz_col.z_end = 0; |
319 | 0 | mz->mz_row.z_begin = mz->mz_row.z_end = 0; |
320 | 0 | mz->mz_col_bits = 0; |
321 | 0 | mz->mz_row_offset = 0; |
322 | 0 | mz->mz_col_offset = 0; |
323 | |
|
324 | 0 | _citrus_region_init(&r, CITRUS_DECONST(void *, var), lenvar); |
325 | 0 | _citrus_memory_stream_bind(&ms, &r); |
326 | 0 | if (parse_var(mz, &ms)) { |
327 | 0 | free(mz); |
328 | 0 | return (EINVAL); |
329 | 0 | } |
330 | 0 | cm->cm_closure = mz; |
331 | 0 | mt->mt_src_max = mt->mt_dst_max = 1; /* 1:1 converter */ |
332 | 0 | mt->mt_state_size = 0; /* stateless */ |
333 | |
|
334 | 0 | return (0); |
335 | 0 | } |
336 | | |
337 | | static void |
338 | | /*ARGSUSED*/ |
339 | | _citrus_mapper_zone_mapper_uninit(struct _citrus_csmapper *cm ) |
340 | 0 | { |
341 | 0 | if (cm && cm->cm_closure) |
342 | 0 | free(cm->cm_closure); |
343 | 0 | } |
344 | | |
345 | | static int |
346 | | /*ARGSUSED*/ |
347 | | _citrus_mapper_zone_mapper_convert(struct _citrus_csmapper * cm, |
348 | | _citrus_index_t * dst, _citrus_index_t src, |
349 | | void * ps ) |
350 | 0 | { |
351 | 0 | struct _citrus_mapper_zone *mz = cm->cm_closure; |
352 | 0 | uint32_t col, row; |
353 | 0 | (void) ps; |
354 | |
|
355 | 0 | if (mz->mz_col_bits == 32) { |
356 | 0 | col = src; |
357 | 0 | row = 0; |
358 | 0 | if (col < mz->mz_col.z_begin || col > mz->mz_col.z_end) |
359 | 0 | return (_CITRUS_MAPPER_CONVERT_NONIDENTICAL); |
360 | 0 | if (mz->mz_col_offset > 0) |
361 | 0 | col += (uint32_t)mz->mz_col_offset; |
362 | 0 | else |
363 | 0 | col -= (uint32_t)-mz->mz_col_offset; |
364 | 0 | *dst = col; |
365 | 0 | } else { |
366 | 0 | col = src & (((uint32_t)1 << mz->mz_col_bits) - 1); |
367 | 0 | row = src >> mz->mz_col_bits; |
368 | 0 | if (row < mz->mz_row.z_begin || row > mz->mz_row.z_end || |
369 | 0 | col < mz->mz_col.z_begin || col > mz->mz_col.z_end) |
370 | 0 | return (_CITRUS_MAPPER_CONVERT_NONIDENTICAL); |
371 | 0 | if (mz->mz_col_offset > 0) |
372 | 0 | col += (uint32_t)mz->mz_col_offset; |
373 | 0 | else |
374 | 0 | col -= (uint32_t)-mz->mz_col_offset; |
375 | 0 | if (mz->mz_row_offset > 0) |
376 | 0 | row += (uint32_t)mz->mz_row_offset; |
377 | 0 | else |
378 | 0 | row -= (uint32_t)-mz->mz_row_offset; |
379 | 0 | *dst = col | (row << mz->mz_col_bits); |
380 | 0 | } |
381 | 0 | return (_CITRUS_MAPPER_CONVERT_SUCCESS); |
382 | 0 | } |
383 | | |
384 | | static void |
385 | | /*ARGSUSED*/ |
386 | | _citrus_mapper_zone_mapper_init_state(void) |
387 | 0 | { |
388 | |
|
389 | 0 | } |