1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_filter.hxx"
26
27 #include "ccidecom.hxx"
28
29 //=============================== Huffman-Tabellen ========================
30
31 //---------------------------- White-Run ------------------------------
32
33 #define CCIWhiteTableSize 105
34
35 const CCIHuffmanTableEntry CCIWhiteTable[CCIWhiteTableSize]={
36 { 0, 0x0035, 8 },
37 { 1, 0x0007, 6 },
38 { 2, 0x0007, 4 },
39 { 3, 0x0008, 4 },
40 { 4, 0x000b, 4 },
41 { 5, 0x000c, 4 },
42 { 6, 0x000e, 4 },
43 { 7, 0x000f, 4 },
44 { 8, 0x0013, 5 },
45 { 9, 0x0014, 5 },
46 { 10, 0x0007, 5 },
47 { 11, 0x0008, 5 },
48 { 12, 0x0008, 6 },
49 { 13, 0x0003, 6 },
50 { 14, 0x0034, 6 },
51 { 15, 0x0035, 6 },
52 { 16, 0x002a, 6 },
53 { 17, 0x002b, 6 },
54 { 18, 0x0027, 7 },
55 { 19, 0x000c, 7 },
56 { 20, 0x0008, 7 },
57 { 21, 0x0017, 7 },
58 { 22, 0x0003, 7 },
59 { 23, 0x0004, 7 },
60 { 24, 0x0028, 7 },
61 { 25, 0x002b, 7 },
62 { 26, 0x0013, 7 },
63 { 27, 0x0024, 7 },
64 { 28, 0x0018, 7 },
65 { 29, 0x0002, 8 },
66 { 30, 0x0003, 8 },
67 { 31, 0x001a, 8 },
68 { 32, 0x001b, 8 },
69 { 33, 0x0012, 8 },
70 { 34, 0x0013, 8 },
71 { 35, 0x0014, 8 },
72 { 36, 0x0015, 8 },
73 { 37, 0x0016, 8 },
74 { 38, 0x0017, 8 },
75 { 39, 0x0028, 8 },
76 { 40, 0x0029, 8 },
77 { 41, 0x002a, 8 },
78 { 42, 0x002b, 8 },
79 { 43, 0x002c, 8 },
80 { 44, 0x002d, 8 },
81 { 45, 0x0004, 8 },
82 { 46, 0x0005, 8 },
83 { 47, 0x000a, 8 },
84 { 48, 0x000b, 8 },
85 { 49, 0x0052, 8 },
86 { 50, 0x0053, 8 },
87 { 51, 0x0054, 8 },
88 { 52, 0x0055, 8 },
89 { 53, 0x0024, 8 },
90 { 54, 0x0025, 8 },
91 { 55, 0x0058, 8 },
92 { 56, 0x0059, 8 },
93 { 57, 0x005a, 8 },
94 { 58, 0x005b, 8 },
95 { 59, 0x004a, 8 },
96 { 60, 0x004b, 8 },
97 { 61, 0x0032, 8 },
98 { 62, 0x0033, 8 },
99 { 63, 0x0034, 8 },
100 { 64, 0x001b, 5 },
101 { 128, 0x0012, 5 },
102 { 192, 0x0017, 6 },
103 { 256, 0x0037, 7 },
104 { 320, 0x0036, 8 },
105 { 384, 0x0037, 8 },
106 { 448, 0x0064, 8 },
107 { 512, 0x0065, 8 },
108 { 576, 0x0068, 8 },
109 { 640, 0x0067, 8 },
110 { 704, 0x00cc, 9 },
111 { 768, 0x00cd, 9 },
112 { 832, 0x00d2, 9 },
113 { 896, 0x00d3, 9 },
114 { 960, 0x00d4, 9 },
115 { 1024, 0x00d5, 9 },
116 { 1088, 0x00d6, 9 },
117 { 1152, 0x00d7, 9 },
118 { 1216, 0x00d8, 9 },
119 { 1280, 0x00d9, 9 },
120 { 1344, 0x00da, 9 },
121 { 1408, 0x00db, 9 },
122 { 1472, 0x0098, 9 },
123 { 1536, 0x0099, 9 },
124 { 1600, 0x009a, 9 },
125 { 1664, 0x0018, 6 },
126 { 1728, 0x009b, 9 },
127 { 1792, 0x0008, 11 },
128 { 1856, 0x000c, 11 },
129 { 1920, 0x000d, 11 },
130 { 1984, 0x0012, 12 },
131 { 2048, 0x0013, 12 },
132 { 2112, 0x0014, 12 },
133 { 2176, 0x0015, 12 },
134 { 2240, 0x0016, 12 },
135 { 2304, 0x0017, 12 },
136 { 2368, 0x001c, 12 },
137 { 2432, 0x001d, 12 },
138 { 2496, 0x001e, 12 },
139 { 2560, 0x001f, 12 },
140 { 9999, 0x0001, 12 } // EOL
141 };
142
143 //---------------------------- Black-Run ------------------------------
144
145 #define CCIBlackTableSize 105
146
147 const CCIHuffmanTableEntry CCIBlackTable[CCIBlackTableSize]={
148 { 0, 0x0037, 10 },
149 { 1, 0x0002, 3 },
150 { 2, 0x0003, 2 },
151 { 3, 0x0002, 2 },
152 { 4, 0x0003, 3 },
153 { 5, 0x0003, 4 },
154 { 6, 0x0002, 4 },
155 { 7, 0x0003, 5 },
156 { 8, 0x0005, 6 },
157 { 9, 0x0004, 6 },
158 { 10, 0x0004, 7 },
159 { 11, 0x0005, 7 },
160 { 12, 0x0007, 7 },
161 { 13, 0x0004, 8 },
162 { 14, 0x0007, 8 },
163 { 15, 0x0018, 9 },
164 { 16, 0x0017, 10 },
165 { 17, 0x0018, 10 },
166 { 18, 0x0008, 10 },
167 { 19, 0x0067, 11 },
168 { 20, 0x0068, 11 },
169 { 21, 0x006c, 11 },
170 { 22, 0x0037, 11 },
171 { 23, 0x0028, 11 },
172 { 24, 0x0017, 11 },
173 { 25, 0x0018, 11 },
174 { 26, 0x00ca, 12 },
175 { 27, 0x00cb, 12 },
176 { 28, 0x00cc, 12 },
177 { 29, 0x00cd, 12 },
178 { 30, 0x0068, 12 },
179 { 31, 0x0069, 12 },
180 { 32, 0x006a, 12 },
181 { 33, 0x006b, 12 },
182 { 34, 0x00d2, 12 },
183 { 35, 0x00d3, 12 },
184 { 36, 0x00d4, 12 },
185 { 37, 0x00d5, 12 },
186 { 38, 0x00d6, 12 },
187 { 39, 0x00d7, 12 },
188 { 40, 0x006c, 12 },
189 { 41, 0x006d, 12 },
190 { 42, 0x00da, 12 },
191 { 43, 0x00db, 12 },
192 { 44, 0x0054, 12 },
193 { 45, 0x0055, 12 },
194 { 46, 0x0056, 12 },
195 { 47, 0x0057, 12 },
196 { 48, 0x0064, 12 },
197 { 49, 0x0065, 12 },
198 { 50, 0x0052, 12 },
199 { 51, 0x0053, 12 },
200 { 52, 0x0024, 12 },
201 { 53, 0x0037, 12 },
202 { 54, 0x0038, 12 },
203 { 55, 0x0027, 12 },
204 { 56, 0x0028, 12 },
205 { 57, 0x0058, 12 },
206 { 58, 0x0059, 12 },
207 { 59, 0x002b, 12 },
208 { 60, 0x002c, 12 },
209 { 61, 0x005a, 12 },
210 { 62, 0x0066, 12 },
211 { 63, 0x0067, 12 },
212 { 64, 0x000f, 10 },
213 { 128, 0x00c8, 12 },
214 { 192, 0x00c9, 12 },
215 { 256, 0x005b, 12 },
216 { 320, 0x0033, 12 },
217 { 384, 0x0034, 12 },
218 { 448, 0x0035, 12 },
219 { 512, 0x006c, 13 },
220 { 576, 0x006d, 13 },
221 { 640, 0x004a, 13 },
222 { 704, 0x004b, 13 },
223 { 768, 0x004c, 13 },
224 { 832, 0x004d, 13 },
225 { 896, 0x0072, 13 },
226 { 960, 0x0073, 13 },
227 { 1024, 0x0074, 13 },
228 { 1088, 0x0075, 13 },
229 { 1152, 0x0076, 13 },
230 { 1216, 0x0077, 13 },
231 { 1280, 0x0052, 13 },
232 { 1344, 0x0053, 13 },
233 { 1408, 0x0054, 13 },
234 { 1472, 0x0055, 13 },
235 { 1536, 0x005a, 13 },
236 { 1600, 0x005b, 13 },
237 { 1664, 0x0064, 13 },
238 { 1728, 0x0065, 13 },
239 { 1792, 0x0008, 11 },
240 { 1856, 0x000c, 11 },
241 { 1920, 0x000d, 11 },
242 { 1984, 0x0012, 12 },
243 { 2048, 0x0013, 12 },
244 { 2112, 0x0014, 12 },
245 { 2176, 0x0015, 12 },
246 { 2240, 0x0016, 12 },
247 { 2304, 0x0017, 12 },
248 { 2368, 0x001c, 12 },
249 { 2432, 0x001d, 12 },
250 { 2496, 0x001e, 12 },
251 { 2560, 0x001f, 12 },
252 { 9999, 0x0001, 12 } // EOL
253 };
254
255
256 //---------------------------- 2D-Mode --------------------------------
257
258 #define CCI2DMODE_UNCOMP 0
259 #define CCI2DMODE_PASS 1
260 #define CCI2DMODE_HORZ 2
261 #define CCI2DMODE_VERT_L3 3
262 #define CCI2DMODE_VERT_L2 4
263 #define CCI2DMODE_VERT_L1 5
264 #define CCI2DMODE_VERT_0 6
265 #define CCI2DMODE_VERT_R1 7
266 #define CCI2DMODE_VERT_R2 8
267 #define CCI2DMODE_VERT_R3 9
268
269 #define CCI2DModeTableSize 10
270
271 const CCIHuffmanTableEntry CCI2DModeTable[CCI2DModeTableSize]={
272 { CCI2DMODE_UNCOMP , 0x000f, 10 },
273 { CCI2DMODE_PASS , 0x0001, 4 },
274 { CCI2DMODE_HORZ , 0x0001, 3 },
275 { CCI2DMODE_VERT_L3, 0x0002, 7 },
276 { CCI2DMODE_VERT_L2, 0x0002, 6 },
277 { CCI2DMODE_VERT_L1, 0x0002, 3 },
278 { CCI2DMODE_VERT_0 , 0x0001, 1 },
279 { CCI2DMODE_VERT_R1, 0x0003, 3 },
280 { CCI2DMODE_VERT_R2, 0x0003, 6 },
281 { CCI2DMODE_VERT_R3, 0x0003, 7 }
282 };
283
284
285 //-------------------------- 2D-Uncompressed-Mode ----------------------
286
287 #define CCIUNCOMP_0White_1Black 0
288 #define CCIUNCOMP_1White_1Black 1
289 #define CCIUNCOMP_2White_1Black 2
290 #define CCIUNCOMP_3White_1Black 3
291 #define CCIUNCOMP_4White_1Black 4
292 #define CCIUNCOMP_5White 5
293 #define CCIUNCOMP_0White_End 6
294 #define CCIUNCOMP_1White_End 7
295 #define CCIUNCOMP_2White_End 8
296 #define CCIUNCOMP_3White_End 9
297 #define CCIUNCOMP_4White_End 10
298
299 #define CCIUncompTableSize 11
300
301 const CCIHuffmanTableEntry CCIUncompTable[CCIUncompTableSize]={
302 { CCIUNCOMP_0White_1Black, 0x0001, 1 },
303 { CCIUNCOMP_1White_1Black, 0x0001, 2 },
304 { CCIUNCOMP_2White_1Black, 0x0001, 3 },
305 { CCIUNCOMP_3White_1Black, 0x0001, 4 },
306 { CCIUNCOMP_4White_1Black, 0x0001, 5 },
307 { CCIUNCOMP_5White , 0x0001, 6 },
308 { CCIUNCOMP_0White_End , 0x0001, 7 },
309 { CCIUNCOMP_1White_End , 0x0001, 8 },
310 { CCIUNCOMP_2White_End , 0x0001, 9 },
311 { CCIUNCOMP_3White_End , 0x0001, 10 },
312 { CCIUNCOMP_4White_End , 0x0001, 11 }
313 };
314
315
316 //================== Sicherheitskopie der Huffman-Tabellen ================
317 // Um sicher zugehen, dass die Huffman-Tabellen keine Fehler enthalten,
318 // wurden sie zweimal von unterschiedlichen Quellen eingegeben (Uff) und
319 // verglichen.
320 // Da sich aber im Laufe der Pflege des Source-Codes mal ein Fehler
321 // einschleichen koennte (z.B. versehentlicher druck einer Taste im Editor)
322 // werden die Tablellen hier weiterhin zweimal aufgefuehrt und zur Laufzeit
323 // verglichen. (Wenn der Vergleich fehlschlaegt, liefert CCIDecompressor
324 // immer einen Fehler). Das Ganze mag etwas wahnsinnig erscheinen, aber ein Fehler
325 // in den Tabellen waere sonst sehr sehr schwer zu erkennen, zumal es
326 // unwahrscheinlich ist, dass eine oder mehere Beispieldateien alle Codes
327 // durchlaufen.
328
329 const CCIHuffmanTableEntry CCIWhiteTableSave[CCIWhiteTableSize]={
330 { 0, 0x0035, 8 },
331 { 1, 0x0007, 6 },
332 { 2, 0x0007, 4 },
333 { 3, 0x0008, 4 },
334 { 4, 0x000b, 4 },
335 { 5, 0x000c, 4 },
336 { 6, 0x000e, 4 },
337 { 7, 0x000f, 4 },
338 { 8, 0x0013, 5 },
339 { 9, 0x0014, 5 },
340 { 10, 0x0007, 5 },
341 { 11, 0x0008, 5 },
342 { 12, 0x0008, 6 },
343 { 13, 0x0003, 6 },
344 { 14, 0x0034, 6 },
345 { 15, 0x0035, 6 },
346 { 16, 0x002a, 6 },
347 { 17, 0x002b, 6 },
348 { 18, 0x0027, 7 },
349 { 19, 0x000c, 7 },
350 { 20, 0x0008, 7 },
351 { 21, 0x0017, 7 },
352 { 22, 0x0003, 7 },
353 { 23, 0x0004, 7 },
354 { 24, 0x0028, 7 },
355 { 25, 0x002b, 7 },
356 { 26, 0x0013, 7 },
357 { 27, 0x0024, 7 },
358 { 28, 0x0018, 7 },
359 { 29, 0x0002, 8 },
360 { 30, 0x0003, 8 },
361 { 31, 0x001a, 8 },
362 { 32, 0x001b, 8 },
363 { 33, 0x0012, 8 },
364 { 34, 0x0013, 8 },
365 { 35, 0x0014, 8 },
366 { 36, 0x0015, 8 },
367 { 37, 0x0016, 8 },
368 { 38, 0x0017, 8 },
369 { 39, 0x0028, 8 },
370 { 40, 0x0029, 8 },
371 { 41, 0x002a, 8 },
372 { 42, 0x002b, 8 },
373 { 43, 0x002c, 8 },
374 { 44, 0x002d, 8 },
375 { 45, 0x0004, 8 },
376 { 46, 0x0005, 8 },
377 { 47, 0x000a, 8 },
378 { 48, 0x000b, 8 },
379 { 49, 0x0052, 8 },
380 { 50, 0x0053, 8 },
381 { 51, 0x0054, 8 },
382 { 52, 0x0055, 8 },
383 { 53, 0x0024, 8 },
384 { 54, 0x0025, 8 },
385 { 55, 0x0058, 8 },
386 { 56, 0x0059, 8 },
387 { 57, 0x005a, 8 },
388 { 58, 0x005b, 8 },
389 { 59, 0x004a, 8 },
390 { 60, 0x004b, 8 },
391 { 61, 0x0032, 8 },
392 { 62, 0x0033, 8 },
393 { 63, 0x0034, 8 },
394 { 64, 0x001b, 5 },
395 { 128, 0x0012, 5 },
396 { 192, 0x0017, 6 },
397 { 256, 0x0037, 7 },
398 { 320, 0x0036, 8 },
399 { 384, 0x0037, 8 },
400 { 448, 0x0064, 8 },
401 { 512, 0x0065, 8 },
402 { 576, 0x0068, 8 },
403 { 640, 0x0067, 8 },
404 { 704, 0x00cc, 9 },
405 { 768, 0x00cd, 9 },
406 { 832, 0x00d2, 9 },
407 { 896, 0x00d3, 9 },
408 { 960, 0x00d4, 9 },
409 { 1024, 0x00d5, 9 },
410 { 1088, 0x00d6, 9 },
411 { 1152, 0x00d7, 9 },
412 { 1216, 0x00d8, 9 },
413 { 1280, 0x00d9, 9 },
414 { 1344, 0x00da, 9 },
415 { 1408, 0x00db, 9 },
416 { 1472, 0x0098, 9 },
417 { 1536, 0x0099, 9 },
418 { 1600, 0x009a, 9 },
419 { 1664, 0x0018, 6 },
420 { 1728, 0x009b, 9 },
421 { 1792, 0x0008, 11 },
422 { 1856, 0x000c, 11 },
423 { 1920, 0x000d, 11 },
424 { 1984, 0x0012, 12 },
425 { 2048, 0x0013, 12 },
426 { 2112, 0x0014, 12 },
427 { 2176, 0x0015, 12 },
428 { 2240, 0x0016, 12 },
429 { 2304, 0x0017, 12 },
430 { 2368, 0x001c, 12 },
431 { 2432, 0x001d, 12 },
432 { 2496, 0x001e, 12 },
433 { 2560, 0x001f, 12 },
434 { 9999, 0x0001, 12 } // EOL
435 };
436
437 const CCIHuffmanTableEntry CCIBlackTableSave[CCIBlackTableSize]={
438 { 0, 0x0037, 10 },
439 { 1, 0x0002, 3 },
440 { 2, 0x0003, 2 },
441 { 3, 0x0002, 2 },
442 { 4, 0x0003, 3 },
443 { 5, 0x0003, 4 },
444 { 6, 0x0002, 4 },
445 { 7, 0x0003, 5 },
446 { 8, 0x0005, 6 },
447 { 9, 0x0004, 6 },
448 { 10, 0x0004, 7 },
449 { 11, 0x0005, 7 },
450 { 12, 0x0007, 7 },
451 { 13, 0x0004, 8 },
452 { 14, 0x0007, 8 },
453 { 15, 0x0018, 9 },
454 { 16, 0x0017, 10 },
455 { 17, 0x0018, 10 },
456 { 18, 0x0008, 10 },
457 { 19, 0x0067, 11 },
458 { 20, 0x0068, 11 },
459 { 21, 0x006c, 11 },
460 { 22, 0x0037, 11 },
461 { 23, 0x0028, 11 },
462 { 24, 0x0017, 11 },
463 { 25, 0x0018, 11 },
464 { 26, 0x00ca, 12 },
465 { 27, 0x00cb, 12 },
466 { 28, 0x00cc, 12 },
467 { 29, 0x00cd, 12 },
468 { 30, 0x0068, 12 },
469 { 31, 0x0069, 12 },
470 { 32, 0x006a, 12 },
471 { 33, 0x006b, 12 },
472 { 34, 0x00d2, 12 },
473 { 35, 0x00d3, 12 },
474 { 36, 0x00d4, 12 },
475 { 37, 0x00d5, 12 },
476 { 38, 0x00d6, 12 },
477 { 39, 0x00d7, 12 },
478 { 40, 0x006c, 12 },
479 { 41, 0x006d, 12 },
480 { 42, 0x00da, 12 },
481 { 43, 0x00db, 12 },
482 { 44, 0x0054, 12 },
483 { 45, 0x0055, 12 },
484 { 46, 0x0056, 12 },
485 { 47, 0x0057, 12 },
486 { 48, 0x0064, 12 },
487 { 49, 0x0065, 12 },
488 { 50, 0x0052, 12 },
489 { 51, 0x0053, 12 },
490 { 52, 0x0024, 12 },
491 { 53, 0x0037, 12 },
492 { 54, 0x0038, 12 },
493 { 55, 0x0027, 12 },
494 { 56, 0x0028, 12 },
495 { 57, 0x0058, 12 },
496 { 58, 0x0059, 12 },
497 { 59, 0x002b, 12 },
498 { 60, 0x002c, 12 },
499 { 61, 0x005a, 12 },
500 { 62, 0x0066, 12 },
501 { 63, 0x0067, 12 },
502 { 64, 0x000f, 10 },
503 { 128, 0x00c8, 12 },
504 { 192, 0x00c9, 12 },
505 { 256, 0x005b, 12 },
506 { 320, 0x0033, 12 },
507 { 384, 0x0034, 12 },
508 { 448, 0x0035, 12 },
509 { 512, 0x006c, 13 },
510 { 576, 0x006d, 13 },
511 { 640, 0x004a, 13 },
512 { 704, 0x004b, 13 },
513 { 768, 0x004c, 13 },
514 { 832, 0x004d, 13 },
515 { 896, 0x0072, 13 },
516 { 960, 0x0073, 13 },
517 { 1024, 0x0074, 13 },
518 { 1088, 0x0075, 13 },
519 { 1152, 0x0076, 13 },
520 { 1216, 0x0077, 13 },
521 { 1280, 0x0052, 13 },
522 { 1344, 0x0053, 13 },
523 { 1408, 0x0054, 13 },
524 { 1472, 0x0055, 13 },
525 { 1536, 0x005a, 13 },
526 { 1600, 0x005b, 13 },
527 { 1664, 0x0064, 13 },
528 { 1728, 0x0065, 13 },
529 { 1792, 0x0008, 11 },
530 { 1856, 0x000c, 11 },
531 { 1920, 0x000d, 11 },
532 { 1984, 0x0012, 12 },
533 { 2048, 0x0013, 12 },
534 { 2112, 0x0014, 12 },
535 { 2176, 0x0015, 12 },
536 { 2240, 0x0016, 12 },
537 { 2304, 0x0017, 12 },
538 { 2368, 0x001c, 12 },
539 { 2432, 0x001d, 12 },
540 { 2496, 0x001e, 12 },
541 { 2560, 0x001f, 12 },
542 { 9999, 0x0001, 12 } // EOL
543 };
544
545
546 const CCIHuffmanTableEntry CCI2DModeTableSave[CCI2DModeTableSize]={
547 { CCI2DMODE_UNCOMP , 0x000f, 10 },
548 { CCI2DMODE_PASS , 0x0001, 4 },
549 { CCI2DMODE_HORZ , 0x0001, 3 },
550 { CCI2DMODE_VERT_L3, 0x0002, 7 },
551 { CCI2DMODE_VERT_L2, 0x0002, 6 },
552 { CCI2DMODE_VERT_L1, 0x0002, 3 },
553 { CCI2DMODE_VERT_0 , 0x0001, 1 },
554 { CCI2DMODE_VERT_R1, 0x0003, 3 },
555 { CCI2DMODE_VERT_R2, 0x0003, 6 },
556 { CCI2DMODE_VERT_R3, 0x0003, 7 }
557 };
558
559
560 const CCIHuffmanTableEntry CCIUncompTableSave[CCIUncompTableSize]={
561 { CCIUNCOMP_0White_1Black, 0x0001, 1 },
562 { CCIUNCOMP_1White_1Black, 0x0001, 2 },
563 { CCIUNCOMP_2White_1Black, 0x0001, 3 },
564 { CCIUNCOMP_3White_1Black, 0x0001, 4 },
565 { CCIUNCOMP_4White_1Black, 0x0001, 5 },
566 { CCIUNCOMP_5White , 0x0001, 6 },
567 { CCIUNCOMP_0White_End , 0x0001, 7 },
568 { CCIUNCOMP_1White_End , 0x0001, 8 },
569 { CCIUNCOMP_2White_End , 0x0001, 9 },
570 { CCIUNCOMP_3White_End , 0x0001, 10 },
571 { CCIUNCOMP_4White_End , 0x0001, 11 }
572 };
573
574 //=========================================================================
575
576
CCIDecompressor(sal_uLong nOpts,sal_uInt32 nImageWidth)577 CCIDecompressor::CCIDecompressor( sal_uLong nOpts, sal_uInt32 nImageWidth ) :
578 bTableBad ( sal_False ),
579 bStatus ( sal_False ),
580 pByteSwap ( NULL ),
581 nWidth ( nImageWidth ),
582 nOptions ( nOpts ),
583 pLastLine ( NULL )
584 {
585 if ( nOpts & CCI_OPTION_INVERSEBITORDER )
586 {
587 pByteSwap = new sal_uInt8[ 256 ];
588 for ( int i = 0; i < 256; i++ )
589 {
590 pByteSwap[ i ] = sal::static_int_cast< sal_uInt8 >(
591 ( i << 7 ) | ( ( i & 2 ) << 5 ) | ( ( i & 4 ) << 3 ) | ( ( i & 8 ) << 1 ) |
592 ( ( i & 16 ) >> 1 ) | ( ( i & 32 ) >> 3 ) | ( ( i & 64 ) >> 5 ) | ( ( i & 128 ) >> 7 ));
593 }
594 }
595
596 pWhiteLookUp =new CCILookUpTableEntry[1<<13];
597 pBlackLookUp =new CCILookUpTableEntry[1<<13];
598 p2DModeLookUp=new CCILookUpTableEntry[1<<10];
599 pUncompLookUp=new CCILookUpTableEntry[1<<11];
600
601 MakeLookUp(CCIWhiteTable,CCIWhiteTableSave,pWhiteLookUp,CCIWhiteTableSize,13);
602 MakeLookUp(CCIBlackTable,CCIBlackTableSave,pBlackLookUp,CCIBlackTableSize,13);
603 MakeLookUp(CCI2DModeTable,CCI2DModeTableSave,p2DModeLookUp,CCI2DModeTableSize,10);
604 MakeLookUp(CCIUncompTable,CCIUncompTableSave,pUncompLookUp,CCIUncompTableSize,11);
605 }
606
607
~CCIDecompressor()608 CCIDecompressor::~CCIDecompressor()
609 {
610 delete[] pByteSwap;
611 delete[] pLastLine;
612 delete[] pWhiteLookUp;
613 delete[] pBlackLookUp;
614 delete[] p2DModeLookUp;
615 delete[] pUncompLookUp;
616 }
617
618
StartDecompression(SvStream & rIStream)619 void CCIDecompressor::StartDecompression( SvStream & rIStream )
620 {
621 pIStream = &rIStream;
622 nInputBitsBufSize = 0;
623 bFirstEOL = sal_True;
624 bStatus = sal_True;
625 nEOLCount = 0;
626
627 if ( bTableBad == sal_True )
628 return;
629 }
630
631
DecompressScanline(sal_uInt8 * pTarget,sal_uLong nTargetBits,bool bLastLine)632 sal_Bool CCIDecompressor::DecompressScanline( sal_uInt8 * pTarget, sal_uLong nTargetBits, bool bLastLine )
633 {
634 sal_uInt16 i;
635 sal_uInt8 * pSrc,* pDst;
636 sal_Bool b2D;
637
638 if ( nEOLCount >= 5 ) // RTC( Return To Controller )
639 return sal_True;
640
641 if ( bStatus == sal_False )
642 return sal_False;
643
644 // Wenn EOL-Codes vorhanden sind, steht der EOL-Code auch vor der ersten Zeile.
645 // (und ich dachte EOL heisst 'End Of Line'...)
646 // Daher lesen wir den EOL-Code immer vor jeder Zeile als erstes ein:
647 if ( nOptions & CCI_OPTION_EOL )
648 {
649 if ( bFirstEOL )
650 {
651 sal_uInt32 nCurPos = pIStream->Tell();
652 sal_uInt16 nOldInputBitsBufSize = nInputBitsBufSize;
653 sal_uInt32 nOldInputBitsBuf = nInputBitsBuf;
654 if ( ReadEOL( 32 ) == sal_False )
655 {
656 nInputBitsBufSize = nOldInputBitsBufSize;
657 nInputBitsBuf = nOldInputBitsBuf;
658 pIStream->Seek( nCurPos );
659 nOptions &=~ CCI_OPTION_EOL; // CCITT Group 3 - Compression Type 2
660 }
661 bFirstEOL = sal_False;
662 }
663 else
664 {
665 if ( ReadEOL( nTargetBits ) == sal_False )
666 {
667 return bStatus;
668 }
669 }
670 }
671
672 if ( nEOLCount >= 5 ) // RTC( Return To Controller )
673 return sal_True;
674
675 // ggf. eine weisse vorherige Zeile herstellen fuer 2D:
676 if ( nOptions & CCI_OPTION_2D )
677 {
678 if ( pLastLine == NULL || nLastLineSize != ( ( nTargetBits + 7 ) >> 3 ) )
679 {
680 if ( pLastLine == NULL )
681 delete[] pLastLine;
682 nLastLineSize = ( nTargetBits + 7 ) >> 3;
683 pLastLine = new sal_uInt8[ nLastLineSize ];
684 pDst = pLastLine;
685 for ( i = 0; i < nLastLineSize; i++ ) *( pDst++ ) = 0x00;
686 }
687 }
688 // ggf. Zeilen-Anfang auf naechste Byte-Grenze runden:
689 if ( nOptions & CCI_OPTION_BYTEALIGNROW )
690 nInputBitsBufSize &= 0xfff8;
691
692 // Ist es eine 2D-Zeile ?:
693 if ( nOptions & CCI_OPTION_2D )
694 {
695 if ( nOptions & CCI_OPTION_EOL )
696 b2D = Read2DTag();
697 else
698 b2D = sal_True;
699 }
700 else
701 b2D = sal_False;
702
703 // Zeile einlesen:
704 if ( b2D )
705 Read2DScanlineData( pTarget, (sal_uInt16)nTargetBits );
706 else
707 Read1DScanlineData( pTarget, (sal_uInt16)nTargetBits );
708
709 // Wenn wir im 2D-Modus sind, muessen wir uns die Zeile merken:
710 if ( nOptions & CCI_OPTION_2D && bStatus == sal_True )
711 {
712 pSrc = pTarget;
713 pDst = pLastLine;
714 for ( i = 0; i < nLastLineSize; i++ ) *(pDst++)=*(pSrc++);
715 }
716
717 // #122984#
718 if( !bStatus && bLastLine )
719 {
720 bStatus = sal_True;
721 }
722
723 if ( pIStream->GetError() )
724 bStatus = sal_False;
725
726 return bStatus;
727 }
728
729
MakeLookUp(const CCIHuffmanTableEntry * pHufTab,const CCIHuffmanTableEntry * pHufTabSave,CCILookUpTableEntry * pLookUp,sal_uInt16 nHuffmanTableSize,sal_uInt16 nMaxCodeBits)730 void CCIDecompressor::MakeLookUp(const CCIHuffmanTableEntry * pHufTab,
731 const CCIHuffmanTableEntry * pHufTabSave,
732 CCILookUpTableEntry * pLookUp,
733 sal_uInt16 nHuffmanTableSize,
734 sal_uInt16 nMaxCodeBits)
735 {
736 sal_uInt16 i,j,nMinCode,nMaxCode,nLookUpSize,nMask;
737
738 if (bTableBad==sal_True) return;
739
740 nLookUpSize=1<<nMaxCodeBits;
741
742 nMask=0xffff>>(16-nMaxCodeBits);
743
744 for (i=0; i<nLookUpSize; i++) pLookUp[i].nCodeBits=0;
745 for (i=0; i<nHuffmanTableSize; i++) {
746 if ( pHufTab[i].nValue!=pHufTabSave[i].nValue ||
747 pHufTab[i].nCode!=pHufTabSave[i].nCode ||
748 pHufTab[i].nCodeBits!=pHufTabSave[i].nCodeBits ||
749 pHufTab[i].nCodeBits==0 ||
750 pHufTab[i].nCodeBits>nMaxCodeBits )
751 {
752 bTableBad=sal_True;
753 return;
754 }
755 nMinCode = nMask & (pHufTab[i].nCode << (nMaxCodeBits-pHufTab[i].nCodeBits));
756 nMaxCode = nMinCode | (nMask >> pHufTab[i].nCodeBits);
757 for (j=nMinCode; j<=nMaxCode; j++) {
758 if (pLookUp[j].nCodeBits!=0) {
759 bTableBad=sal_True;
760 return;
761 }
762 pLookUp[j].nValue=pHufTab[i].nValue;
763 pLookUp[j].nCodeBits=pHufTab[i].nCodeBits;
764 }
765 }
766 }
767
768
ReadEOL(sal_uInt32)769 sal_Bool CCIDecompressor::ReadEOL( sal_uInt32 /*nMaxFillBits*/ )
770 {
771 sal_uInt16 nCode;
772 sal_uInt8 nByte;
773
774 // if (nOptions&CCI_OPTION_BYTEALIGNEOL) nMaxFillBits=7; else nMaxFillBits=0;
775 // Buuuh: Entweder wird die Option in itiff.cxx nicht richtig gesetzt (-> Fehler in Doku)
776 // oder es gibt tatsaechlich gemeine Export-Filter, die immer ein Align machen.
777 // Ausserdem wurden Dateien gefunden, in denen mehr als die maximal 7 noetigen
778 // Fuellbits vor dem EOL-Code stehen. Daher akzeptieren wir nun grundsaetzlich
779 // bis zu 32-Bloedsinn-Bits vor dem EOL-Code:
780 // und ich habe eine Datei gefunden in der bis zu ??? Bloedsinn Bits stehen, zudem ist dort die Bit Reihenfolge verdreht (SJ);
781
782 sal_uInt32 nMaxPos = pIStream->Tell();
783 nMaxPos += nWidth >> 3;
784
785 for ( ;; )
786 {
787 while ( nInputBitsBufSize < 12 )
788 {
789 *pIStream >> nByte;
790 if ( pIStream->IsEof() )
791 return sal_False;
792 if ( pIStream->Tell() > nMaxPos )
793 return sal_False;
794
795 if ( nOptions & CCI_OPTION_INVERSEBITORDER )
796 nByte = pByteSwap[ nByte ];
797 nInputBitsBuf=(nInputBitsBuf<<8) | (sal_uLong)nByte;
798 nInputBitsBufSize += 8;
799 }
800 nCode = (sal_uInt16)( ( nInputBitsBuf >> ( nInputBitsBufSize - 12 ) ) & 0x0fff );
801 if ( nCode == 0x0001 )
802 {
803 nEOLCount++;
804 nInputBitsBufSize -= 12;
805 break;
806 }
807 else
808 nInputBitsBufSize--;
809 }
810 return sal_True;
811 }
812
813
Read2DTag()814 sal_Bool CCIDecompressor::Read2DTag()
815 {
816 sal_uInt8 nByte;
817
818 // Ein Bit einlesen und sal_True liefern, wenn es 0 ist, sonst sal_False
819 if (nInputBitsBufSize==0) {
820 *pIStream >> nByte;
821 if ( nOptions & CCI_OPTION_INVERSEBITORDER )
822 nByte = pByteSwap[ nByte ];
823 nInputBitsBuf=(sal_uLong)nByte;
824 nInputBitsBufSize=8;
825 }
826 nInputBitsBufSize--;
827 if ( ((nInputBitsBuf>>nInputBitsBufSize)&0x0001) ) return sal_False;
828 else return sal_True;
829 }
830
831
ReadBlackOrWhite()832 sal_uInt8 CCIDecompressor::ReadBlackOrWhite()
833 {
834 sal_uInt8 nByte;
835
836 // Ein Bit einlesen und 0x00 liefern, wenn es 0 ist, sonst 0xff
837 if (nInputBitsBufSize==0) {
838 *pIStream >> nByte;
839 if ( nOptions & CCI_OPTION_INVERSEBITORDER )
840 nByte = pByteSwap[ nByte ];
841 nInputBitsBuf=(sal_uLong)nByte;
842 nInputBitsBufSize=8;
843 }
844 nInputBitsBufSize--;
845 if ( ((nInputBitsBuf>>nInputBitsBufSize)&0x0001) ) return 0xff;
846 else return 0x00;
847 }
848
849
ReadCodeAndDecode(const CCILookUpTableEntry * pLookUp,sal_uInt16 nMaxCodeBits)850 sal_uInt16 CCIDecompressor::ReadCodeAndDecode(const CCILookUpTableEntry * pLookUp,
851 sal_uInt16 nMaxCodeBits)
852 {
853 sal_uInt16 nCode,nCodeBits;
854 sal_uInt8 nByte;
855
856 // Einen Huffman-Code einlesen und dekodieren:
857 while (nInputBitsBufSize<nMaxCodeBits) {
858 *pIStream >> nByte;
859 if ( nOptions & CCI_OPTION_INVERSEBITORDER )
860 nByte = pByteSwap[ nByte ];
861 nInputBitsBuf=(nInputBitsBuf<<8) | (sal_uLong)nByte;
862 nInputBitsBufSize+=8;
863 }
864 nCode=(sal_uInt16)((nInputBitsBuf>>(nInputBitsBufSize-nMaxCodeBits))
865 &(0xffff>>(16-nMaxCodeBits)));
866 nCodeBits=pLookUp[nCode].nCodeBits;
867 if (nCodeBits==0) bStatus=sal_False;
868 nInputBitsBufSize = nInputBitsBufSize - nCodeBits;
869 return pLookUp[nCode].nValue;
870 }
871
872
FillBits(sal_uInt8 * pTarget,sal_uInt16 nTargetBits,sal_uInt16 nBitPos,sal_uInt16 nNumBits,sal_uInt8 nBlackOrWhite)873 void CCIDecompressor::FillBits(sal_uInt8 * pTarget, sal_uInt16 nTargetBits,
874 sal_uInt16 nBitPos, sal_uInt16 nNumBits,
875 sal_uInt8 nBlackOrWhite)
876 {
877 if ( nBitPos >= nTargetBits )
878 return;
879 if ( nBitPos + nNumBits > nTargetBits )
880 nNumBits = nTargetBits - nBitPos;
881
882 pTarget+=nBitPos>>3;
883 nBitPos&=7;
884
885 if (nBlackOrWhite==0x00) *pTarget &= 0xff << (8-nBitPos);
886 else *pTarget |= 0xff >> nBitPos;
887 if (nNumBits>8-nBitPos) {
888 nNumBits-=8-nBitPos;
889 while (nNumBits>=8) {
890 *(++pTarget)=nBlackOrWhite;
891 nNumBits-=8;
892 }
893 if (nNumBits>0) *(++pTarget)=nBlackOrWhite;
894 }
895 }
896
897
CountBits(const sal_uInt8 * pData,sal_uInt16 nDataSizeBits,sal_uInt16 nBitPos,sal_uInt8 nBlackOrWhite)898 sal_uInt16 CCIDecompressor::CountBits(const sal_uInt8 * pData, sal_uInt16 nDataSizeBits,
899 sal_uInt16 nBitPos, sal_uInt8 nBlackOrWhite)
900 {
901 sal_uInt16 nPos,nLo;
902 sal_uInt8 nData;
903
904 // Hier wird die Anzahl der zusammenhaengenden Bits gezaehlt, die
905 // ab Position nBitPos in pTarget alle die Farbe nBlackOrWhite
906 // (0xff oder 0x00) haben.
907
908 nPos=nBitPos;
909 for (;;) {
910 if (nPos>=nDataSizeBits) {
911 nPos=nDataSizeBits;
912 break;
913 }
914 nData=pData[nPos>>3];
915 nLo=nPos & 7;
916 if ( nLo==0 && nData==nBlackOrWhite) nPos+=8;
917 else {
918 if ( ((nData^nBlackOrWhite) & (0x80 >> nLo))!=0) break;
919 nPos++;
920 }
921 }
922 if (nPos<=nBitPos) return 0;
923 else return nPos-nBitPos;
924 }
925
926
Read1DScanlineData(sal_uInt8 * pTarget,sal_uInt16 nTargetBits)927 void CCIDecompressor::Read1DScanlineData(sal_uInt8 * pTarget, sal_uInt16 nTargetBits)
928 {
929 sal_uInt16 nCode,nCodeBits,nDataBits,nTgtFreeByteBits;
930 sal_uInt8 nByte;
931 sal_uInt8 nBlackOrWhite; // ist 0xff fuer Black oder 0x00 fuer White
932 sal_Bool bTerminatingCode;
933
934 // Der erste Code ist immer eine "White-Code":
935 nBlackOrWhite=0x00;
936
937 // Anzahl der Bits, die im Byte *pTarget noch nicht geschrieben sind:
938 nTgtFreeByteBits=8;
939
940 // Schleife ueber Codes aus dem Eingabe-Stream:
941 do {
942
943 // die naechsten 13 Bits nach nCode holen, aber noch nicht
944 // aus dem Eingabe-Buffer loeschen:
945 while (nInputBitsBufSize<13) {
946 *pIStream >> nByte;
947 if ( nOptions & CCI_OPTION_INVERSEBITORDER )
948 nByte = pByteSwap[ nByte ];
949 nInputBitsBuf=(nInputBitsBuf<<8) | (sal_uLong)nByte;
950 nInputBitsBufSize+=8;
951 }
952 nCode=(sal_uInt16)((nInputBitsBuf>>(nInputBitsBufSize-13))&0x1fff);
953
954 // Anzahl der DatenBits und Anzahl der CodeBits ermitteln:
955 if (nBlackOrWhite) {
956 nCodeBits=pBlackLookUp[nCode].nCodeBits;
957 nDataBits=pBlackLookUp[nCode].nValue;
958 }
959 else {
960 nCodeBits=pWhiteLookUp[nCode].nCodeBits;
961 nDataBits=pWhiteLookUp[nCode].nValue;
962 }
963 // Ist es ein Ungueltiger Code ?
964 if ( nDataBits == 9999 )
965 {
966 return;
967 }
968 if ( nCodeBits == 0 )
969 {
970 return; // das koennen sich jetzt um FuellBits handeln
971 }
972 nEOLCount = 0;
973 // Zuviele Daten ?
974 if (nDataBits>nTargetBits) {
975 // Ja, koennte ein Folge-Fehler durch ungueltigen Code sein,
976 // daher irdenwie weitermachen:
977 nDataBits=nTargetBits;
978 }
979
980 // Ist es ein 'Terminating-Code' ?
981 if (nDataBits<64) bTerminatingCode=sal_True; else bTerminatingCode=sal_False;
982
983 // Die gelesenen Bits aus dem Eingabe-Buffer entfernen:
984 nInputBitsBufSize = nInputBitsBufSize - nCodeBits;
985
986 // Die Anzahl Daten-Bits in die Scanline schreiben:
987 if (nDataBits>0) {
988 nTargetBits = nTargetBits - nDataBits;
989 if (nBlackOrWhite==0x00) *pTarget &= 0xff << nTgtFreeByteBits;
990 else *pTarget |= 0xff >> (8-nTgtFreeByteBits);
991 if (nDataBits<=nTgtFreeByteBits) {
992 if (nDataBits==nTgtFreeByteBits) {
993 pTarget++;
994 nTgtFreeByteBits=8;
995 }
996 else nTgtFreeByteBits = nTgtFreeByteBits - nDataBits;
997 }
998 else {
999 nDataBits = nDataBits - nTgtFreeByteBits;
1000 pTarget++;
1001 nTgtFreeByteBits=8;
1002 while (nDataBits>=8) {
1003 *(pTarget++)=nBlackOrWhite;
1004 nDataBits-=8;
1005 }
1006 if (nDataBits>0) {
1007 *pTarget=nBlackOrWhite;
1008 nTgtFreeByteBits = nTgtFreeByteBits - nDataBits;
1009 }
1010 }
1011 }
1012
1013 // ggf. Umschaltung Black <-> White:
1014 if (bTerminatingCode==sal_True) nBlackOrWhite=~nBlackOrWhite;
1015
1016 } while (nTargetBits>0 || bTerminatingCode==sal_False);
1017 }
1018
1019
1020
Read2DScanlineData(sal_uInt8 * pTarget,sal_uInt16 nTargetBits)1021 void CCIDecompressor::Read2DScanlineData(sal_uInt8 * pTarget, sal_uInt16 nTargetBits)
1022 {
1023 sal_uInt16 n2DMode,nBitPos,nUncomp,nRun,nRun2,nt;
1024 sal_uInt8 nBlackOrWhite;
1025
1026 nBlackOrWhite=0x00;
1027 nBitPos=0;
1028
1029 while (nBitPos<nTargetBits && bStatus==sal_True) {
1030
1031 n2DMode=ReadCodeAndDecode(p2DModeLookUp,10);
1032 if (bStatus==sal_False) return;
1033
1034 if (n2DMode==CCI2DMODE_UNCOMP) {
1035 for (;;) {
1036 nUncomp=ReadCodeAndDecode(pUncompLookUp,11);
1037 if ( nUncomp <= CCIUNCOMP_4White_1Black ) {
1038 nRun=nUncomp-CCIUNCOMP_0White_1Black;
1039 FillBits(pTarget,nTargetBits,nBitPos,nRun,0x00);
1040 nBitPos = nBitPos + nRun;
1041 FillBits(pTarget,nTargetBits,nBitPos,1,0xff);
1042 nBitPos++;
1043 }
1044 else if ( nUncomp == CCIUNCOMP_5White ) {
1045 FillBits(pTarget,nTargetBits,nBitPos,5,0x00);
1046 nBitPos = nBitPos + 5;
1047 }
1048 else {
1049 nRun=nUncomp-CCIUNCOMP_0White_End;
1050 FillBits(pTarget,nTargetBits,nBitPos,nRun,0x00);
1051 nBitPos = nBitPos + nRun;
1052 nBlackOrWhite=ReadBlackOrWhite();
1053 break;
1054 }
1055 }
1056 }
1057
1058 else if (n2DMode==CCI2DMODE_PASS) {
1059 if (nBitPos==0 && nBlackOrWhite==0x00 && CountBits(pLastLine,nTargetBits,0,0xff)!=0) nRun=0;
1060 else {
1061 nRun=CountBits(pLastLine,nTargetBits,nBitPos,~nBlackOrWhite);
1062 nRun = nRun + CountBits(pLastLine,nTargetBits,nBitPos+nRun,nBlackOrWhite);
1063 }
1064 nRun = nRun + CountBits(pLastLine,nTargetBits,nBitPos+nRun,~nBlackOrWhite);
1065 FillBits(pTarget,nTargetBits,nBitPos,nRun,nBlackOrWhite);
1066 nBitPos = nBitPos + nRun;
1067 }
1068
1069 else if (n2DMode==CCI2DMODE_HORZ) {
1070 if (nBlackOrWhite==0x00) {
1071 nRun=0;
1072 do {
1073 nt=ReadCodeAndDecode(pWhiteLookUp,13);
1074 nRun = nRun + nt;
1075 } while (nt>=64);
1076 nRun2=0;
1077 do {
1078 nt=ReadCodeAndDecode(pBlackLookUp,13);
1079 nRun2 = nRun2 + nt;
1080 } while (nt>=64);
1081 }
1082 else {
1083 nRun=0;
1084 do {
1085 nt=ReadCodeAndDecode(pBlackLookUp,13);
1086 nRun = nRun + nt;
1087 } while (nt>=64);
1088 nRun2=0;
1089 do {
1090 nt=ReadCodeAndDecode(pWhiteLookUp,13);
1091 nRun2 = nRun2 + nt;
1092 } while (nt>=64);
1093 }
1094 FillBits(pTarget,nTargetBits,nBitPos,nRun,nBlackOrWhite);
1095 nBitPos = nBitPos + nRun;
1096 FillBits(pTarget,nTargetBits,nBitPos,nRun2,~nBlackOrWhite);
1097 nBitPos = nBitPos + nRun2;
1098 }
1099
1100 else { // Es ist einer der Modi CCI2DMODE_VERT_...
1101 if (nBitPos==0 && nBlackOrWhite==0x00 && CountBits(pLastLine,nTargetBits,0,0xff)!=0) nRun=0;
1102 else {
1103 nRun=CountBits(pLastLine,nTargetBits,nBitPos,~nBlackOrWhite);
1104 nRun = nRun + CountBits(pLastLine,nTargetBits,nBitPos+nRun,nBlackOrWhite);
1105 }
1106 nRun+=n2DMode-CCI2DMODE_VERT_0;
1107 FillBits(pTarget,nTargetBits,nBitPos,nRun,nBlackOrWhite);
1108 nBitPos = nBitPos + nRun;
1109 nBlackOrWhite=~nBlackOrWhite;
1110 }
1111 }
1112 }
1113
1114
1115