1 | /****************************************************************************** |
---|
2 | * SAGE - Scalable Adaptive Graphics Environment |
---|
3 | * |
---|
4 | * Copyright (C) 2004 Electronic Visualization Laboratory, |
---|
5 | * University of Illinois at Chicago |
---|
6 | * |
---|
7 | * All rights reserved. |
---|
8 | * |
---|
9 | * Redistribution and use in source and binary forms, with or without |
---|
10 | * modification, are permitted provided that the following conditions are met: |
---|
11 | * |
---|
12 | * * Redistributions of source code must retain the above copyright |
---|
13 | * notice, this list of conditions and the following disclaimer. |
---|
14 | * * Redistributions in binary form must reproduce the above |
---|
15 | * copyright notice, this list of conditions and the following disclaimer |
---|
16 | * in the documentation and/or other materials provided with the distribution. |
---|
17 | * * Neither the name of the University of Illinois at Chicago nor |
---|
18 | * the names of its contributors may be used to endorse or promote |
---|
19 | * products derived from this software without specific prior written permission. |
---|
20 | * |
---|
21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
---|
22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
---|
23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
---|
24 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
---|
25 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
---|
26 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
---|
27 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
---|
28 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
---|
29 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
---|
30 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
---|
31 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
32 | * |
---|
33 | * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/ |
---|
34 | * |
---|
35 | *****************************************************************************/ |
---|
36 | |
---|
37 | /*- |
---|
38 | * gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image. |
---|
39 | * |
---|
40 | * Copyright (c) 1988 by Patrick J. Naughton |
---|
41 | * |
---|
42 | * Author: Patrick J. Naughton |
---|
43 | * naughton@wind.sun.com |
---|
44 | * |
---|
45 | * Permission to use, copy, modify, and distribute this software and its |
---|
46 | * documentation for any purpose and without fee is hereby granted, |
---|
47 | * provided that the above copyright notice appear in all copies and that |
---|
48 | * both that copyright notice and this permission notice appear in |
---|
49 | * supporting documentation. |
---|
50 | * |
---|
51 | * This file is provided AS IS with no warranties of any kind. The author |
---|
52 | * shall have no liability with respect to the infringement of copyrights, |
---|
53 | * trade secrets or any patents by this file or any part thereof. In no |
---|
54 | * event will the author be liable for any lost revenue or profits or |
---|
55 | * other special, indirect and consequential damages. |
---|
56 | * |
---|
57 | * Comments and additions should be sent to the author: |
---|
58 | * |
---|
59 | * Patrick J. Naughton |
---|
60 | * Sun Microsystems, Inc. |
---|
61 | * 2550 Garcia Ave, MS 14-40 |
---|
62 | * Mountain View, CA 94043 |
---|
63 | * (415) 336-1080 |
---|
64 | * |
---|
65 | * Revision History: |
---|
66 | * 27-Jul-88: Updated to use libpixrect to fix 386i byteswapping problems. |
---|
67 | * 11-Apr-88: Converted to C and changed to write Sun rasterfiles. |
---|
68 | * 19-Jan-88: GIFSLOW.PAS posted to comp.graphics by Jim Briebel, |
---|
69 | * a Turbo Pascal 4.0 program to painfully slowly display |
---|
70 | * GIF images on an EGA equipped IBM-PC. |
---|
71 | * 13-Jul-90: changed to gif2raw for use by the Geometry Supercomputer Project |
---|
72 | * by Cary Sandvig |
---|
73 | * |
---|
74 | * Description: |
---|
75 | * This program takes a Compuserve "Graphics Interchange Format" or "GIF" |
---|
76 | * file as input and writes a file known as a Sun rasterfile. This datafile |
---|
77 | * can be loaded by the NeWS "readcanvas" operator and is of the same format |
---|
78 | * as the files in /usr/NeWS/smi/... Under X11R2 there is a program called |
---|
79 | * xraster to display these files. |
---|
80 | * |
---|
81 | * Portability: |
---|
82 | * To make this program convert to some image format other than Sun's |
---|
83 | * Rasterfile format simply seach for the tag "SS:" in the source and |
---|
84 | * replace these simple mechanisms with the appropriate ones for the |
---|
85 | * other output format. I have marked all (six) Sun Specific pieces |
---|
86 | * of code with this comment. |
---|
87 | * |
---|
88 | * SS: compile with "cc -o gif2raw -O gif2raw.c" |
---|
89 | */ |
---|
90 | |
---|
91 | #include <fcntl.h> |
---|
92 | #include <stdio.h> |
---|
93 | #include <stdlib.h> |
---|
94 | #include <string.h> |
---|
95 | #include "softpic.h" |
---|
96 | #include "imginfo.h" |
---|
97 | |
---|
98 | typedef int boolean; |
---|
99 | #define True (1) |
---|
100 | #define False (0) |
---|
101 | |
---|
102 | #define NEXTSHORT (ptr += 2, ptr[-2] + 0x100 * ptr[-1]) |
---|
103 | #define NEXTBYTE (*ptr++) |
---|
104 | #define IMAGESEP 0x2c |
---|
105 | #define EXTENSION '!' |
---|
106 | #define TRANSPARENCY 0xF9 /* transparency extension-code */ |
---|
107 | #define INTERLACEMASK 0x40 |
---|
108 | #define COLORMAPMASK 0x80 |
---|
109 | |
---|
110 | static int BitOffset = 0, /* Bit Offset of next code */ |
---|
111 | XC = 0, YC = 0, /* Output X and Y coords of current pixel */ |
---|
112 | Pass = 0, /* Used by output routine if interlaced pic */ |
---|
113 | OutCount = 0, /* Decompressor output 'stack count' */ |
---|
114 | RWidth, RHeight, /* screen dimensions */ |
---|
115 | Width, Height, /* image dimensions */ |
---|
116 | LeftOfs, TopOfs, /* image offset */ |
---|
117 | BitsPerPixel, /* Bits per pixel, read from GIF header */ |
---|
118 | ColorMapSize, /* number of colors */ |
---|
119 | CodeSize, /* Code size, read from GIF header */ |
---|
120 | InitCodeSize, /* Starting code size, used during Clear */ |
---|
121 | Code, /* Value returned by ReadCode */ |
---|
122 | MaxCode, /* limiting value for current code size */ |
---|
123 | ClearCode, /* GIF clear code */ |
---|
124 | EOFCode, /* GIF end-of-information code */ |
---|
125 | CurCode, OldCode, InCode, /* Decompressor variables */ |
---|
126 | FirstFree, /* First free code, generated per GIF spec */ |
---|
127 | FreeCode, /* Decompressor, next free slot in hash table */ |
---|
128 | FinChar, /* Decompressor variable */ |
---|
129 | BitMask, /* AND mask for data size */ |
---|
130 | ReadMask; /* Code AND mask for current code size */ |
---|
131 | |
---|
132 | static boolean Interlace, HasColormap; |
---|
133 | |
---|
134 | static unsigned char *Image; /* The result array */ |
---|
135 | static unsigned char *RawGIF; /* The heap array to hold it, raw */ |
---|
136 | static unsigned char *Raster; /* The raster data stream, unblocked */ |
---|
137 | |
---|
138 | /* The hash table used by the decompressor */ |
---|
139 | static int Prefix[4096]; |
---|
140 | static int Suffix[4096]; |
---|
141 | |
---|
142 | /* An output array used by the decompressor */ |
---|
143 | static int OutCode[1025]; |
---|
144 | |
---|
145 | /* The color map, read from the GIF header */ |
---|
146 | static unsigned char Red[256], Green[256], Blue[256]; |
---|
147 | static long abgr[256]; |
---|
148 | |
---|
149 | static char *id, *id2; |
---|
150 | |
---|
151 | static char *pname; /* program name (used for error messages) */ |
---|
152 | |
---|
153 | static int ReadCode(); |
---|
154 | static void AddToPixel(char Index); |
---|
155 | |
---|
156 | static void error( char *s1, char *s2 ) |
---|
157 | { |
---|
158 | fprintf(stderr, s1, pname, s2); |
---|
159 | exit(1); |
---|
160 | } |
---|
161 | |
---|
162 | |
---|
163 | static void gif_init() |
---|
164 | { |
---|
165 | BitOffset = 0; |
---|
166 | XC = 0; |
---|
167 | YC = 0; |
---|
168 | Pass = 0; |
---|
169 | OutCount = 0; |
---|
170 | id = "GIF87a"; |
---|
171 | id2 = "GIF89a"; |
---|
172 | } |
---|
173 | |
---|
174 | IMG *gifmakedisp( char *inname ) |
---|
175 | { |
---|
176 | FILE *fpin; |
---|
177 | int filesize; |
---|
178 | register unsigned char ch, ch1; |
---|
179 | register unsigned char *ptr, *ptr1; |
---|
180 | IMG *out; |
---|
181 | int transindex = -1; |
---|
182 | int i, j; |
---|
183 | |
---|
184 | gif_init(); |
---|
185 | setbuf(stderr, NULL); |
---|
186 | |
---|
187 | fpin = fopen(inname, "rb"); |
---|
188 | /* find the size of the file */ |
---|
189 | |
---|
190 | fseek(fpin, 0L, 2); |
---|
191 | filesize = ftell(fpin); |
---|
192 | fseek(fpin, 0L, 0); |
---|
193 | |
---|
194 | if (!(ptr = RawGIF = (unsigned char *) malloc(filesize))) |
---|
195 | error("%s: not enough memory to read gif file.\n", NULL); |
---|
196 | |
---|
197 | if (!(Raster = (unsigned char *) malloc(filesize))) |
---|
198 | error("%s: not enough memory to read gif file.\n", NULL); |
---|
199 | |
---|
200 | fread(ptr, filesize, 1, fpin); |
---|
201 | |
---|
202 | if (memcmp(ptr, id, 6) && memcmp(ptr, id2, 6)) |
---|
203 | error("%s: %s is not a GIF file.\n", inname); |
---|
204 | ptr += 6; |
---|
205 | |
---|
206 | /* Get variables from the GIF screen descriptor */ |
---|
207 | |
---|
208 | RWidth = NEXTSHORT; /* screen dimensions... not used. */ |
---|
209 | RHeight = NEXTSHORT; |
---|
210 | |
---|
211 | ch = NEXTBYTE; |
---|
212 | HasColormap = ((ch & COLORMAPMASK) ? True : False); |
---|
213 | |
---|
214 | BitsPerPixel = (ch & 7) + 1; |
---|
215 | ColorMapSize = 1 << BitsPerPixel; |
---|
216 | BitMask = ColorMapSize - 1; |
---|
217 | |
---|
218 | ch = NEXTBYTE; /* background color... not used. */ |
---|
219 | |
---|
220 | (void) NEXTBYTE; /* what's this? */ |
---|
221 | |
---|
222 | /* Read in global colormap. */ |
---|
223 | |
---|
224 | if (HasColormap) { |
---|
225 | /* |
---|
226 | fprintf(stderr, "%s is %d bits per pixel, (%d colors).\n", |
---|
227 | inname, BitsPerPixel, ColorMapSize); |
---|
228 | */ |
---|
229 | for (i = 0; i < ColorMapSize; i++) { |
---|
230 | Red[i] = NEXTBYTE; |
---|
231 | Green[i] = NEXTBYTE; |
---|
232 | Blue[i] = NEXTBYTE; |
---|
233 | abgr[i] = 0xFF000000 | (Blue[i]<<16) | (Green[i]<<8) | Red[i]; |
---|
234 | } |
---|
235 | |
---|
236 | } |
---|
237 | else error("gifdisp: %s does not have a colormap.\n", inname); |
---|
238 | |
---|
239 | |
---|
240 | /* Skip any GIF89 extensions */ |
---|
241 | while((i = NEXTBYTE) == EXTENSION) { |
---|
242 | int extno = NEXTBYTE & 0xFF; |
---|
243 | int len; |
---|
244 | unsigned char block[256]; |
---|
245 | |
---|
246 | /* Skip <lengthbyte><data> segments until we see lengthbyte==0. */ |
---|
247 | while((len = NEXTBYTE) != 0) { |
---|
248 | for(i = 0; i < len; i++) |
---|
249 | block[i] = NEXTBYTE; |
---|
250 | } |
---|
251 | switch(extno) { |
---|
252 | case 0xF9: /* Transparency */ |
---|
253 | if(block[0] & 0x01) { |
---|
254 | transindex = block[3]; |
---|
255 | if(transindex >= 0 && transindex < ColorMapSize) |
---|
256 | abgr[transindex] &= ~0xFF000000; |
---|
257 | } |
---|
258 | break; |
---|
259 | } |
---|
260 | } |
---|
261 | |
---|
262 | /* Check for image separator */ |
---|
263 | if (i != IMAGESEP) |
---|
264 | fprintf(stderr, "gifdisp: %s is a corrupt GIF file.\n", inname); |
---|
265 | |
---|
266 | /* Now read in values from the image descriptor */ |
---|
267 | |
---|
268 | LeftOfs = NEXTSHORT; |
---|
269 | TopOfs = NEXTSHORT; |
---|
270 | Width = NEXTSHORT; |
---|
271 | Height = NEXTSHORT; |
---|
272 | Interlace = ((NEXTBYTE & INTERLACEMASK) ? True : False); |
---|
273 | |
---|
274 | /* |
---|
275 | fprintf(stderr, "Reading a %d by %d %sinterlaced image...", |
---|
276 | Width, Height, (Interlace) ? "" : "non-"); |
---|
277 | */ |
---|
278 | |
---|
279 | |
---|
280 | /* Note that I ignore the possible existence of a local color map. |
---|
281 | * I'm told there aren't many files around that use them, and the spec |
---|
282 | * says it's defined for future use. This could lead to an error |
---|
283 | * reading some files. |
---|
284 | */ |
---|
285 | |
---|
286 | /* Start reading the raster data. First we get the intial code size |
---|
287 | * and compute decompressor constant values, based on this code size. |
---|
288 | */ |
---|
289 | |
---|
290 | CodeSize = NEXTBYTE; |
---|
291 | ClearCode = (1 << CodeSize); |
---|
292 | EOFCode = ClearCode + 1; |
---|
293 | FreeCode = FirstFree = ClearCode + 2; |
---|
294 | |
---|
295 | /* The GIF spec has it that the code size is the code size used to |
---|
296 | * compute the above values is the code size given in the file, but the |
---|
297 | * code size used in compression/decompression is the code size given in |
---|
298 | * the file plus one. (thus the ++). |
---|
299 | */ |
---|
300 | |
---|
301 | CodeSize++; |
---|
302 | InitCodeSize = CodeSize; |
---|
303 | MaxCode = (1 << CodeSize); |
---|
304 | ReadMask = MaxCode - 1; |
---|
305 | |
---|
306 | /* Read the raster data. Here we just transpose it from the GIF array |
---|
307 | * to the Raster array, turning it from a series of blocks into one long |
---|
308 | * data stream, which makes life much easier for ReadCode(). |
---|
309 | */ |
---|
310 | |
---|
311 | ptr1 = Raster; |
---|
312 | do { |
---|
313 | ch = ch1 = NEXTBYTE; |
---|
314 | while (ch--) *ptr1++ = NEXTBYTE; |
---|
315 | } while(ch1); |
---|
316 | |
---|
317 | free(RawGIF); /* We're done with the raw data now... */ |
---|
318 | |
---|
319 | /* |
---|
320 | fprintf(stderr, "done.\n"); |
---|
321 | fprintf(stderr, "Decompressing..."); |
---|
322 | */ |
---|
323 | |
---|
324 | Image = (unsigned char *)calloc((Width*Height), sizeof(char)); |
---|
325 | |
---|
326 | |
---|
327 | /* Decompress the file, continuing until you see the GIF EOF code. |
---|
328 | * One obvious enhancement is to add checking for corrupt files here. |
---|
329 | */ |
---|
330 | |
---|
331 | Code = ReadCode(); |
---|
332 | while (Code != EOFCode) { |
---|
333 | |
---|
334 | /* Clear code sets everything back to its initial value, then reads the |
---|
335 | * immediately subsequent code as uncompressed data. |
---|
336 | */ |
---|
337 | |
---|
338 | if (Code == ClearCode) { |
---|
339 | CodeSize = InitCodeSize; |
---|
340 | MaxCode = (1 << CodeSize); |
---|
341 | ReadMask = MaxCode - 1; |
---|
342 | FreeCode = FirstFree; |
---|
343 | CurCode = OldCode = Code = ReadCode(); |
---|
344 | FinChar = CurCode & BitMask; |
---|
345 | AddToPixel(FinChar); |
---|
346 | } |
---|
347 | else { |
---|
348 | |
---|
349 | /* If not a clear code, then must be data: save same as CurCode and InCode */ |
---|
350 | |
---|
351 | CurCode = InCode = Code; |
---|
352 | |
---|
353 | /* If greater or equal to FreeCode, not in the hash table yet; |
---|
354 | * repeat the last character decoded |
---|
355 | */ |
---|
356 | |
---|
357 | if (CurCode >= FreeCode) { |
---|
358 | CurCode = OldCode; |
---|
359 | OutCode[OutCount++] = FinChar; |
---|
360 | } |
---|
361 | |
---|
362 | /* Unless this code is raw data, pursue the chain pointed to by CurCode |
---|
363 | * through the hash table to its end; each code in the chain puts its |
---|
364 | * associated output code on the output queue. |
---|
365 | */ |
---|
366 | |
---|
367 | while (CurCode > BitMask) { |
---|
368 | OutCode[OutCount++] = Suffix[CurCode]; |
---|
369 | CurCode = Prefix[CurCode]; |
---|
370 | } |
---|
371 | |
---|
372 | /* The last code in the chain is treated as raw data. */ |
---|
373 | |
---|
374 | FinChar = CurCode & BitMask; |
---|
375 | OutCode[OutCount++] = FinChar; |
---|
376 | |
---|
377 | /* Now we put the data out to the Output routine. |
---|
378 | * It's been stacked LIFO, so deal with it that way... |
---|
379 | */ |
---|
380 | |
---|
381 | for (i = OutCount - 1; i >= 0; i--) |
---|
382 | AddToPixel(OutCode[i]); |
---|
383 | OutCount = 0; |
---|
384 | |
---|
385 | /* Build the hash table on-the-fly. No table is stored in the file. */ |
---|
386 | |
---|
387 | Prefix[FreeCode] = OldCode; |
---|
388 | Suffix[FreeCode] = FinChar; |
---|
389 | OldCode = InCode; |
---|
390 | |
---|
391 | /* Point to the next slot in the table. If we exceed the current |
---|
392 | * MaxCode value, increment the code size unless it's already 12. If it |
---|
393 | * is, do nothing: the next code decompressed better be CLEAR |
---|
394 | */ |
---|
395 | |
---|
396 | FreeCode++; |
---|
397 | if (FreeCode >= MaxCode) { |
---|
398 | if (CodeSize < 12) { |
---|
399 | CodeSize++; |
---|
400 | MaxCode *= 2; |
---|
401 | ReadMask = (1 << CodeSize) - 1; |
---|
402 | } |
---|
403 | } |
---|
404 | } |
---|
405 | Code = ReadCode(); |
---|
406 | } |
---|
407 | |
---|
408 | free(Raster); |
---|
409 | |
---|
410 | /* |
---|
411 | fprintf(stderr, "done.\n"); |
---|
412 | |
---|
413 | fprintf(stderr, "outputting image.\n"); |
---|
414 | */ |
---|
415 | |
---|
416 | out = (IMG *)malloc(sizeof(IMG)); |
---|
417 | out->type = IT_LONG; |
---|
418 | out->rowbytes = Width * sizeof(long); |
---|
419 | out->xsize = Width; |
---|
420 | out->ysize = Height; |
---|
421 | out->data = (unsigned char *)malloc(4*(Width*Height)*sizeof(char)); |
---|
422 | |
---|
423 | for(j = 0; j<Height; j++) |
---|
424 | for (i=0; i<Width; i++) { |
---|
425 | *(long *)&out->data[4*(((Height - j - 1)*Width)+i)] = |
---|
426 | abgr[Image[j*Width + i]]; |
---|
427 | } |
---|
428 | |
---|
429 | free(Image); |
---|
430 | fclose(fpin); |
---|
431 | return (out); |
---|
432 | |
---|
433 | /* |
---|
434 | fprintf(stderr, "done.\n"); |
---|
435 | */ |
---|
436 | } |
---|
437 | |
---|
438 | |
---|
439 | /* Fetch the next code from the raster data stream. The codes can be |
---|
440 | * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to |
---|
441 | * maintain our location in the Raster array as a BIT Offset. We compute |
---|
442 | * the byte Offset into the raster array by dividing this by 8, pick up |
---|
443 | * three bytes, compute the bit Offset into our 24-bit chunk, shift to |
---|
444 | * bring the desired code to the bottom, then mask it off and return it. |
---|
445 | */ |
---|
446 | static int ReadCode() |
---|
447 | { |
---|
448 | int RawCode, ByteOffset; |
---|
449 | |
---|
450 | ByteOffset = BitOffset / 8; |
---|
451 | RawCode = Raster[ByteOffset] + (0x100 * Raster[ByteOffset + 1]); |
---|
452 | if (CodeSize >= 8) |
---|
453 | RawCode += (0x10000 * Raster[ByteOffset + 2]); |
---|
454 | RawCode >>= (BitOffset % 8); |
---|
455 | BitOffset += CodeSize; |
---|
456 | return(RawCode & ReadMask); |
---|
457 | } |
---|
458 | |
---|
459 | static void AddToPixel(char Index) |
---|
460 | { |
---|
461 | if((unsigned int)XC >= Width || (unsigned int)YC >= Height) { |
---|
462 | fprintf(stderr, "[BP] "); |
---|
463 | } else { |
---|
464 | *(Image + YC * Width + XC) = Index; |
---|
465 | } |
---|
466 | |
---|
467 | /* Update the X-coordinate, and if it overflows, update the Y-coordinate */ |
---|
468 | |
---|
469 | if (++XC == Width) { |
---|
470 | |
---|
471 | /* If a non-interlaced picture, just increment YC to the next scan line. |
---|
472 | * If it's interlaced, deal with the interlace as described in the GIF |
---|
473 | * spec. Put the decoded scan line out to the screen if we haven't gone |
---|
474 | * past the bottom of it |
---|
475 | */ |
---|
476 | |
---|
477 | XC = 0; |
---|
478 | if (!Interlace) YC++; |
---|
479 | else { |
---|
480 | switch (Pass) { |
---|
481 | case 0: |
---|
482 | YC += 8; |
---|
483 | if (YC >= Height) { |
---|
484 | Pass++; |
---|
485 | YC = 4; |
---|
486 | } |
---|
487 | break; |
---|
488 | case 1: |
---|
489 | YC += 8; |
---|
490 | if (YC >= Height) { |
---|
491 | Pass++; |
---|
492 | YC = 2; |
---|
493 | } |
---|
494 | break; |
---|
495 | case 2: |
---|
496 | YC += 4; |
---|
497 | if (YC >= Height) { |
---|
498 | Pass++; |
---|
499 | YC = 1; |
---|
500 | } |
---|
501 | break; |
---|
502 | case 3: |
---|
503 | YC += 2; |
---|
504 | if(YC >= Height) { |
---|
505 | fprintf(stderr, "[BG] "); |
---|
506 | YC = Height-1; /* eh?? */ |
---|
507 | } |
---|
508 | break; |
---|
509 | default: |
---|
510 | break; |
---|
511 | } |
---|
512 | } |
---|
513 | } |
---|
514 | } |
---|