source: trunk/JPGPROC/source/gbmsrc/gbmtifh.c@ 2

Last change on this file since 2 was 2, checked in by stevenhl, 8 years ago

Import sources from cwmm-full.zip dated 2005-03-21

File size: 15.8 KB
Line 
1
2/*
3
4gbmtifh.c - Routines to handle TIFF file headers
5
6*/
7
8/*...sincludes:0:*/
9#include <stdio.h>
10#include <stdlib.h>
11#include <stddef.h>
12#include <string.h>
13#include "gbm.h"
14#include "gbmhelp.h"
15#define _GBMTIFH_
16#include "gbmtifh.h"
17
18/*...vgbm\46\h:0:*/
19/*...vgbmhelp\46\h:0:*/
20/*...vgbmtifh\46\h:0:*/
21/*...e*/
22
23/*...susefull:0:*/
24#define ifd_malloc() ((IFD *) malloc((size_t) sizeof(IFD)))
25#define ifd_free(ifd) free((char *) ifd)
26
27#define ifh_malloc() ((IFH *) malloc((size_t) sizeof(IFH)))
28#define ifh_free(ifh) free((char *) ifh)
29
30static int sizeof_data_type(short data_type)
31 {
32 switch ( data_type )
33 {
34 case D_BYTE:
35 case D_SBYTE:
36 case D_ASCII:
37 case D_UNDEFINED:
38 return 1;
39 case D_SHORT:
40 case D_SSHORT:
41 return sizeof(short);
42 case D_LONG:
43 case D_SLONG:
44 return sizeof(long);
45 case D_RATIONAL:
46 case D_SRATIONAL:
47 return sizeof(rational);
48 case D_FLOAT:
49 return 4;
50 case D_DOUBLE:
51 return 8;
52 }
53 return 1;
54 }
55
56static void tag_free(TAG *tag)
57 {
58 free(tag->value);
59 }
60
61/*
62This finds the slot for the new tag. It returns NULL if the limit of
63MAX_TAGS tags is curruntly defined.
64*/
65
66static TAG *get_tag_slot(short type, IFD *ifd)
67 {
68 int i;
69
70 if ( ifd->n_tags == MAX_TAGS )
71 return NULL;
72
73 for ( i = ifd->n_tags;
74 i > 0 && ifd->tags[i - 1].type >= type;
75 i-- )
76 memcpy(ifd->tags + i,
77 ifd->tags + i - 1,
78 sizeof(TAG));
79
80 ifd->n_tags++;
81
82 /* now i == slot, with greater than elements moved up */
83
84 return &(ifd->tags[i]);
85 }
86/*...e*/
87
88/*...sread_ifh_and_ifd:0:*/
89/*...sread_long:0:*/
90#define make_long(b1,b2,b3,b4) ( ((long)(b1)<<24) | ((long)(b2)<<16) | ((long)(b3)<<8) | (long)(b4) )
91
92static long read_long(int fd, BOOLEAN motorola)
93 {
94 byte b[4];
95
96 gbm_file_read(fd, b, 4);
97 return ( motorola ) ?
98 make_long(b[0], b[1], b[2], b[3]) :
99 make_long(b[3], b[2], b[1], b[0]) ;
100 }
101/*...e*/
102/*...sread_short:0:*/
103#define make_short(b1,b2) ( ((short)(b1)<<8) | (short)(b2) )
104
105static short read_short(int fd, BOOLEAN motorola)
106 {
107 byte b[2];
108
109 gbm_file_read(fd, b, 2);
110 return ( motorola ) ?
111 make_short(b[0], b[1]) :
112 make_short(b[1], b[0]) ;
113 }
114/*...e*/
115/*...sread_rational:0:*/
116static void read_rational(int fd, BOOLEAN motorola, rational *r)
117 {
118 r->numerator = read_long(fd, motorola);
119 r->denominator = read_long(fd, motorola);
120 }
121/*...e*/
122/*...sread_tag:0:*/
123static int read_tag(int fd, BOOLEAN motorola, TAG *tag)
124 {
125 int i, s, n;
126 long len;
127 long seek_to, old_pos;
128
129 tag->type = read_short(fd, motorola);
130 tag->data_type = read_short(fd, motorola);
131 tag->length = read_long(fd, motorola);
132
133 if ( tag->type & 0x8000 )
134 /* proprietry tag */
135 {
136 gbm_file_lseek(fd, 4L, SEEK_CUR); /* skip data */
137 return TE_OK; /* assumed ok */
138 }
139
140 n = (int) tag->length;
141
142/*...sbugfix for UBU\39\s writing of ColorMap tag:8:*/
143/* UBU writes out a length feild of 256 when it should write 768 */
144
145if ( tag->type == T_COLORMAP && (n / 3) * 3 != n )
146 n *= 3;
147/*...e*/
148
149 s = sizeof_data_type(tag->data_type);
150 len = s * n;
151
152 if ( len > 4 )
153 /* will have to seek for data */
154 {
155 seek_to = read_long(fd, motorola);
156 old_pos = gbm_file_lseek(fd, 0L, SEEK_CUR);
157 gbm_file_lseek(fd, seek_to, SEEK_SET);
158 }
159
160 if ( (tag->value = malloc((size_t) len)) == NULL )
161 return TE_MEM;
162
163 switch ( tag->data_type )
164 {
165 case D_BYTE:
166 case D_SBYTE:
167 gbm_file_read(fd, tag->value, n);
168 break;
169 case D_ASCII:
170 gbm_file_read(fd, tag->value, n);
171 break;
172 case D_SHORT:
173 case D_SSHORT:
174 {
175 short *short_ptr = (short *) tag->value;
176
177 for ( i = 0; i < n; i++ )
178 *short_ptr++ = read_short(fd, motorola);
179 }
180 break;
181 case D_LONG:
182 case D_SLONG:
183 {
184 long *long_ptr = (long *) tag->value;
185
186 for ( i = 0; i < n; i++ )
187 *long_ptr++ = read_long(fd, motorola);
188 }
189 break;
190 case D_RATIONAL:
191 case D_SRATIONAL:
192 {
193 rational *rational_ptr = (rational *) tag->value;
194
195 for ( i = 0; i < n; i++ )
196 read_rational(fd, motorola, rational_ptr++);
197 }
198 break;
199 case D_FLOAT:
200 /* Skip 4 byte IEEE floating point */
201 gbm_file_lseek(fd, 4 * len, SEEK_CUR);
202 break;
203 case D_DOUBLE:
204 /* Skip 8 byte IEEE double precision floating point */
205 gbm_file_lseek(fd, 8 * len, SEEK_CUR);
206 break;
207 default:
208 gbm_file_read(fd, tag->value, (int) len);
209 break;
210 }
211
212 if ( len > 4 )
213 gbm_file_lseek(fd, old_pos, SEEK_SET);
214 else if ( len < 4 )
215 gbm_file_lseek(fd, 4L - len, SEEK_CUR); /* advance past gap */
216
217 return TE_OK;
218 }
219/*...e*/
220/*...sread_ifd:0:*/
221/*
222For the time being we will assume there is only one IFD in
223a given TIFF file. When this code was written, the author
224knew of no software packages that support multiple IFDs.
225*/
226
227/*...sclean_up_ifd:0:*/
228static void clean_up_ifd(IFD *ifd, int n)
229 {
230 int i;
231 TAG *tag;
232
233 for ( i = 0; i < n; i++ )
234 {
235 tag = &(ifd->tags[i]);
236 if ( !(tag->type & 0x8000) ) /* its not read in */
237 tag_free(tag);
238 }
239 ifd_free(ifd);
240 }
241/*...e*/
242
243static int read_ifd(int fd, BOOLEAN motorola, IFD **ifd_return)
244 {
245 IFD *ifd;
246 int i, ecode;
247
248 if ( (ifd = ifd_malloc()) == NULL )
249 return TE_MEM;
250
251 /* ensure we can handle all the tags */
252
253 if ( (ifd->n_tags = read_short(fd, motorola)) > MAX_TAGS )
254 {
255 ifd_free(ifd); return TE_N_TAGS;
256 }
257
258 /* get the tags */
259
260 for ( i = 0; i < ifd->n_tags; i++ )
261 if ( (ecode = read_tag(fd, motorola, &(ifd->tags[i]))) != TE_OK )
262 {
263 clean_up_ifd(ifd, i);
264 return ecode;
265 }
266
267 *ifd_return = ifd;
268
269 return TE_OK;
270 }
271/*...e*/
272/*...sskip_ifd:0:*/
273/* Returns TRUE if there is another IFD afterwards */
274
275static BOOLEAN skip_ifd(int fd, BOOLEAN motorola)
276 {
277 short n_tags = read_short(fd, motorola);
278 long offset_ifd;
279 gbm_file_lseek(fd, 12L * n_tags, SEEK_CUR);
280 offset_ifd = read_long(fd, motorola);
281 if ( offset_ifd == 0L )
282 return FALSE;
283 gbm_file_lseek(fd, offset_ifd, SEEK_SET);
284 return TRUE;
285 }
286/*...e*/
287
288int read_ifh_and_ifd(int fd, int n_ifds_to_skip, IFH **ifh_return)
289 {
290 IFH *ifh;
291 long offset_ifd;
292 BOOLEAN motorola;
293 int ecode;
294
295 if ( (ifh = ifh_malloc()) == NULL )
296 return TE_MEM;
297
298 gbm_file_read(fd, (char *) &(ifh->byte_order), sizeof(short));
299 motorola = ( ifh->byte_order == ('M' << 8) + 'M' );
300
301 /* Apparently, the following number has great univeral significance! */
302 /* See the TIFF 5.0 spec. for details! */
303
304 if ( (ifh->version_no = read_short(fd, motorola)) != 42 )
305 {
306 ifh_free(ifh); return TE_VERSION;
307 }
308
309 offset_ifd = read_long(fd, motorola);
310 gbm_file_lseek(fd, offset_ifd, SEEK_SET);
311 while ( n_ifds_to_skip-- > 0 )
312 if ( !skip_ifd(fd, motorola) )
313 return TE_N_IFD;
314
315 if ( (ecode = read_ifd(fd, motorola, &(ifh->ifd))) != TE_OK )
316 {
317 ifh_free(ifh); return ecode;
318 }
319
320 *ifh_return = ifh;
321
322 return TE_OK;
323 }
324/*...e*/
325/*...slocate_tag:0:*/
326TAG *locate_tag(IFD *ifd, short type)
327 {
328 int i;
329
330 for ( i = 0; i < ifd->n_tags; i++ )
331 if ( ifd->tags[i].type == type )
332 return &(ifd->tags[i]);
333 return NULL;
334 }
335/*...e*/
336/*...snumeric_tag:0:*/
337BOOLEAN numeric_tag(TAG *tag)
338 {
339 short t = tag->data_type;
340 return t == D_BYTE ||
341 t == D_SHORT || t == D_SSHORT ||
342 t == D_LONG || t == D_SLONG ;
343 }
344/*...e*/
345/*...svalue_of_tag_n:0:*/
346/*
347For a numeric tag, return the value of the nth item in it.
348Upto the caller to know that tag is signed or unsigned.
349*/
350
351long value_of_tag_n(TAG *tag, int n)
352 {
353 switch ( tag->data_type )
354 {
355 case D_BYTE:
356 {
357 unsigned char *p = (unsigned char *) tag->value;
358 return (long) (unsigned long) p[n];
359 }
360 case D_SBYTE:
361 {
362 signed char *p = (signed char *) tag->value;
363 return (long) p[n];
364 }
365 case D_SHORT:
366 {
367 unsigned short *p = (unsigned short *) tag->value;
368 return (long) (unsigned long) p[n];
369 }
370 case D_SSHORT:
371 {
372 signed short *p = (signed short *) tag->value;
373 return (long) p[n];
374 }
375 case D_LONG:
376 {
377 unsigned long *p = (unsigned long *) tag->value;
378 return (long) p[n];
379 }
380 case D_SLONG:
381 {
382 signed long *p = (signed long *) tag->value;
383 return (long) p[n];
384 }
385 }
386 return 0L;
387 }
388/*...e*/
389/*...svalue_of_tag:0:*/
390/*
391For a numeric tag, return the value of the 1st value in it.
392This is usefull for tags that typically only have 1 value anyway.
393*/
394
395long value_of_tag(TAG *tag)
396 {
397 return value_of_tag_n(tag, 0);
398 }
399/*...e*/
400/*...sfree_ifh:0:*/
401void free_ifh(IFH *ifh)
402 {
403 IFD *ifd = ifh->ifd;
404 clean_up_ifd(ifd, ifd->n_tags);
405 ifh_free(ifh);
406 }
407/*...e*/
408/*...smake_ifh:0:*/
409/*
410Creates an empty IFH set up for the image.
411Also creates an IFD as part of the IFH.
412Use add_?_tag() routines to add tags to IFH's IFD.
413*/
414
415IFH *make_ifh(void)
416 {
417 IFH *ifh;
418 IFD *ifd;
419
420 if ( (ifh = ifh_malloc()) == NULL )
421 return NULL;
422
423 if ( (ifh->ifd = ifd = ifd_malloc()) == NULL )
424 {
425 ifh_free(ifh);
426 return NULL;
427 }
428
429 ifh->byte_order = ('I' << 8) + 'I';
430 ifh->version_no = 42;
431
432 ifd->n_tags = 0;
433
434 return ifh;
435 }
436/*...e*/
437/*...sadd_byte_tag:0:*/
438BOOLEAN add_byte_tag(IFD *ifd, short type, byte *value, int n)
439 {
440 byte *byte_ptr;
441 TAG *tag;
442
443 if ( (byte_ptr = (byte *) malloc((size_t) (n * sizeof(byte)))) == NULL )
444 return FALSE;
445 if ( (tag = get_tag_slot(type, ifd)) == NULL )
446 return FALSE;
447 tag->type = type;
448 tag->data_type = D_BYTE;
449 tag->length = (long) n;
450 if ( value != NULL )
451 memcpy(tag->value = (char *) byte_ptr,
452 value,
453 n * sizeof(byte));
454 return TRUE;
455 }
456/*...e*/
457/*...sadd_ascii_tag:0:*/
458BOOLEAN add_ascii_tag(IFD *ifd, short type, char *value)
459 {
460 char *ascii_ptr;
461 TAG *tag;
462 int n;
463
464 n = strlen(value) + 1;
465 if ( (ascii_ptr = (char *) malloc((size_t) n)) == NULL )
466 return FALSE;
467 if ( (tag = get_tag_slot(type, ifd)) == NULL )
468 return FALSE;
469 tag->type = type;
470 tag->data_type = D_ASCII;
471 tag->length = (long) n;
472 strcpy(tag->value = ascii_ptr, value);
473 return TRUE;
474 }
475/*...e*/
476/*...sadd_short_tag:0:*/
477BOOLEAN add_short_tag(IFD *ifd, short type, short *value, int n)
478 {
479 short *short_ptr;
480 TAG *tag;
481
482 if ( (short_ptr = (short *) malloc((size_t) (n * sizeof(short)))) == NULL )
483 return FALSE;
484 if ( (tag = get_tag_slot(type, ifd)) == NULL )
485 return FALSE;
486 tag->type = type;
487 tag->data_type = D_SHORT;
488 tag->length = (long) n;
489 if ( value != NULL )
490 memcpy(tag->value = (char *) short_ptr,
491 value,
492 n * sizeof(short));
493 return TRUE;
494 }
495/*...e*/
496/*...sadd_long_tag:0:*/
497BOOLEAN add_long_tag(IFD *ifd, short type, long *value, int n)
498 {
499 long *long_ptr;
500 TAG *tag;
501
502 if ( (long_ptr = (long *) malloc((size_t) (n * sizeof(long)))) == NULL )
503 return FALSE;
504 if ( (tag = get_tag_slot(type, ifd)) == NULL )
505 return FALSE;
506 tag->type = type;
507 tag->data_type = D_LONG;
508 tag->length = (long) n;
509 if ( value != NULL )
510 memcpy(tag->value = (char *) long_ptr,
511 value,
512 n * sizeof(long));
513 return TRUE;
514 }
515/*...e*/
516/*...sadd_rational_tag:0:*/
517BOOLEAN add_rational_tag(IFD *ifd, short type, rational *value, int n)
518 {
519 rational *rational_ptr;
520 TAG *tag;
521
522 if ( (rational_ptr = (rational *) malloc((size_t) (n * sizeof(rational)))) == NULL )
523 return FALSE;
524 if ( (tag = get_tag_slot(type, ifd)) == NULL )
525 return FALSE;
526 tag->type = type;
527 tag->data_type = D_RATIONAL;
528 tag->length = (long) n;
529 if ( value != NULL )
530 memcpy(tag->value = (char *) rational_ptr,
531 value,
532 n * sizeof(rational));
533 return TRUE;
534 }
535/*...e*/
536/*...swrite_ifh_and_ifd:0:*/
537/*...spad:0:*/
538static BOOLEAN pad(int fd, int n)
539 {
540 static char padding[] = { 0, 0, 0, 0 };
541
542 return gbm_file_write(fd, padding, n) == n;
543 }
544/*...e*/
545/*...swrite_short:0:*/
546static BOOLEAN write_short(int fd, short s)
547 {
548 byte b[2];
549
550 b[0] = (byte) (s & 0x00ffU) ;
551 b[1] = (byte) ((unsigned short) (s & 0xff00U) >> 8);
552
553 return gbm_file_write(fd, b, 2) == 2;
554 }
555/*...e*/
556/*...swrite_long:0:*/
557static BOOLEAN write_long(int fd, long l)
558 {
559 byte b[4];
560
561 b[0] = (byte) (l & 0x000000ffUL);
562 b[1] = (byte) ((l & 0x0000ff00UL) >> 8);
563 b[2] = (byte) ((l & 0x00ff0000UL) >> 16);
564 b[3] = (byte) ((l & 0xff000000UL) >> 24);
565
566 return gbm_file_write(fd, b, 4) == 4;
567 }
568/*...e*/
569/*...swrite_rational:0:*/
570static BOOLEAN write_rational(int fd, rational *rational)
571 {
572 return write_long(fd, rational->numerator ) &&
573 write_long(fd, rational->denominator) ;
574 }
575/*...e*/
576/*...swrite_tag:0:*/
577static BOOLEAN write_tag(int fd, TAG *tag, long *offset_upto)
578 {
579 BOOLEAN ok;
580 int s, i, n, len;
581 long offset_return_to;
582
583 ok = write_short(fd, tag->type) &&
584 write_short(fd, tag->data_type) &&
585 write_long(fd, tag->length);
586
587 if ( !ok )
588 return FALSE;
589
590 /* if we can fit the tag into 4 bytes, do so */
591 /* else we will have to allocate some disc space */
592
593 s = sizeof_data_type(tag->data_type);
594 n = (int) tag->length;
595 len = s * n;
596
597 if ( len > 4 )
598 {
599 if ( !write_long(fd, *offset_upto) )
600 return FALSE;
601 offset_return_to = gbm_file_lseek(fd, 0L, SEEK_CUR);
602 gbm_file_lseek(fd, *offset_upto, SEEK_SET);
603 }
604
605 /* actually write the tag */
606
607 switch ( tag->data_type )
608 {
609 case D_BYTE:
610 case D_ASCII:
611 if ( gbm_file_write(fd, tag->value, n) != n )
612 return FALSE;
613 break;
614 case D_SHORT:
615 {
616 short *short_ptr = (short *) tag->value;
617
618 for ( i = 0; i < n; i++ )
619 if ( !write_short(fd, *short_ptr++) )
620 return FALSE;
621 }
622 break;
623 case D_LONG:
624 {
625 long *long_ptr = (long *) tag->value;
626
627 for ( i = 0; i < n; i++ )
628 if ( !write_long(fd, *long_ptr++) )
629 return FALSE;
630 }
631 break;
632 case D_RATIONAL:
633 {
634 rational *rational_ptr = (rational *) tag->value;
635
636 for ( i = 0; i < n; i++ )
637 if ( !write_rational(fd, rational_ptr++) )
638 return FALSE;
639 }
640 break;
641 }
642
643 if ( len > 4 )
644 {
645 if ( (*offset_upto = gbm_file_lseek(fd, 0L, SEEK_CUR)) & 1L )
646 /* pad to make next offset even */
647 {
648 if ( !pad(fd, 1) )
649 return FALSE;
650 (*offset_upto)++;
651 }
652 gbm_file_lseek(fd, offset_return_to, SEEK_SET);
653 }
654 else if ( len < 4 )
655 if ( !pad(fd, 4 - len) )
656 return FALSE;
657 return TRUE;
658 }
659/*...e*/
660/*...swrite_ifd:0:*/
661/*
662Given an IFD, write it out to disc.
663Also patch the IFH (which we know will be at the start of the file).
664In writing out a tag we may need some more disc space other than
665that for the IFD table. This occurs when a field is larger than
6664 bytes. What we do is to keep a pointer to the next free space
667(after the table) and write_tag() will advance it if it uses any
668extra space.
669*/
670
671BOOLEAN write_ifd(int fd, IFD *ifd)
672 {
673 int i, n;
674 long offset_upto;
675
676 if ( !write_short(fd, (short) (n = ifd->n_tags)) )
677 return FALSE;
678
679 /* write out tags */
680
681 offset_upto = gbm_file_lseek(fd, 0L, SEEK_CUR) + n * 12L + 4L;
682 /* leave space for each tag plus next IFD ptr */
683
684 for ( i = 0; i < n; i++ )
685 if ( !write_tag(fd, &(ifd->tags[i]), &offset_upto) )
686 return FALSE;
687
688 /* done writing out the IFD, now put null next IFD pointer */
689
690 if ( !write_long(fd, 0L) )
691 return FALSE;
692
693 gbm_file_lseek(fd, offset_upto, SEEK_SET);
694
695 return TRUE;
696 }
697/*...e*/
698
699BOOLEAN write_ifh_and_ifd(IFH *ifh, int fd)
700 {
701 return write_short(fd, ifh->byte_order) &&
702 write_short(fd, ifh->version_no) &&
703 write_long(fd, 8L) &&
704 write_ifd(fd, ifh->ifd);
705 }
706/*...e*/
707/*...supdate_byte_tag:0:*/
708void update_byte_tag(IFD *ifd, short type, byte *value)
709 {
710 TAG *tag;
711 int n;
712
713 tag = locate_tag(ifd, type);
714 n = (int) tag->length;
715 memcpy(tag->value, value, n * sizeof(byte));
716 }
717/*...e*/
718/*...supdate_ascii_tag:0:*/
719void update_ascii_tag(IFD *ifd, short type, char *value)
720 {
721 TAG *tag;
722 int n;
723
724 tag = locate_tag(ifd, type);
725 n = (int) tag->length;
726 memcpy(tag->value, value, n);
727 }
728/*...e*/
729/*...supdate_short_tag:0:*/
730void update_short_tag(IFD *ifd, short type, short *value)
731 {
732 TAG *tag;
733 int n;
734
735 tag = locate_tag(ifd, type);
736 n = (int) tag->length;
737 memcpy(tag->value, value, n * sizeof(short));
738 }
739/*...e*/
740/*...supdate_long_tag:0:*/
741void update_long_tag(IFD *ifd, short type, long *value)
742 {
743 TAG *tag;
744 int n;
745
746 tag = locate_tag(ifd, type);
747 n = (int) tag->length;
748 memcpy(tag->value, value, n * sizeof(long));
749 }
750/*...e*/
751/*...supdate_rational_tag:0:*/
752void update_rational_tag(IFD *ifd, short type, rational *value)
753 {
754 TAG *tag;
755 int n;
756
757 tag = locate_tag(ifd, type);
758 n = (int) tag->length;
759 memcpy(tag->value, value, n * sizeof(rational));
760 }
761/*...e*/
762/*...supdate_ifd:0:*/
763/*
764Go back to the IFD, and rewrite it.
765*/
766
767BOOLEAN update_ifd(IFD *ifd, int fd)
768 {
769 gbm_file_lseek(fd, 8L, SEEK_SET);
770 return write_ifd(fd, ifd);
771 }
772/*...e*/
Note: See TracBrowser for help on using the repository browser.