1 /******************************************************************************
2  * $Id: tiffset.c,v 1.19 2017-10-01 17:38:12 erouault Exp $
3  *
4  * Project:  libtiff tools
5  * Purpose:  Mainline for setting metadata in existing TIFF files.
6  * Author:   Frank Warmerdam, warmerdam@pobox.com
7  *
8  ******************************************************************************
9  * Copyright (c) 2000, Frank Warmerdam
10  *
11  * Permission to use, copy, modify, distribute, and sell this software and
12  * its documentation for any purpose is hereby granted without fee, provided
13  * that (i) the above copyright notices and this permission notice appear in
14  * all copies of the software and related documentation, and (ii) the names of
15  * Sam Leffler and Silicon Graphics may not be used in any advertising or
16  * publicity relating to the software without the specific, prior written
17  * permission of Sam Leffler and Silicon Graphics.
18  *
19  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
20  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
21  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
22  *
23  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
24  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
25  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
26  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
27  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
28  * OF THIS SOFTWARE.
29  ******************************************************************************
30  */
31 
32 
33 #include <stdio.h>
34 #include <string.h>
35 #include <stdlib.h>
36 
37 #include "tiffio.h"
38 
39 static char* usageMsg[] = {
40 "usage: tiffset [options] filename",
41 "where options are:",
42 " -s <tagname> [count] <value>...   set the tag value",
43 " -u <tagname> to unset the tag",
44 " -d <dirno> set the directory",
45 " -sd <diroff> set the subdirectory",
46 " -sf <tagname> <filename>  read the tag value from file (for ASCII tags only)",
47 NULL
48 };
49 
50 static void
usage(void)51 usage(void)
52 {
53 	int i;
54 	for (i = 0; usageMsg[i]; i++)
55 		fprintf(stderr, "%s\n", usageMsg[i]);
56 	exit(-1);
57 }
58 
59 static const TIFFField *
GetField(TIFF * tiff,const char * tagname)60 GetField(TIFF *tiff, const char *tagname)
61 {
62     const TIFFField *fip;
63 
64     if( atoi(tagname) > 0 )
65         fip = TIFFFieldWithTag(tiff, (ttag_t)atoi(tagname));
66     else
67         fip = TIFFFieldWithName(tiff, tagname);
68 
69     if (!fip) {
70         fprintf( stderr, "Field name \"%s\" is not recognised.\n", tagname );
71         return (TIFFField *)NULL;
72     }
73 
74     return fip;
75 }
76 
77 int
main(int argc,char * argv[])78 main(int argc, char* argv[])
79 {
80     TIFF *tiff;
81     int  arg_index;
82 
83     if (argc < 2)
84         usage();
85 
86     tiff = TIFFOpen(argv[argc-1], "r+");
87     if (tiff == NULL)
88         return 2;
89 
90     for( arg_index = 1; arg_index < argc-1; arg_index++ ) {
91 	if (strcmp(argv[arg_index],"-d") == 0 && arg_index < argc-2) {
92 	    arg_index++;
93 	    if( TIFFSetDirectory(tiff, atoi(argv[arg_index]) ) != 1 )
94             {
95                fprintf( stderr, "Failed to set directory=%s\n", argv[arg_index] );
96                return 6;
97             }
98 	    arg_index++;
99 	}
100 	if (strcmp(argv[arg_index],"-sd") == 0 && arg_index < argc-2) {
101 	    arg_index++;
102 	    if( TIFFSetSubDirectory(tiff, atoi(argv[arg_index]) ) != 1 )
103             {
104                fprintf( stderr, "Failed to set sub directory=%s\n", argv[arg_index] );
105                return 7;
106             }
107 	    arg_index++;
108 	}
109     /* Add unset option to tiffset -- Zach Baker (niquil@niquil.net) 11/14/2012 */
110     if (strcmp(argv[arg_index],"-u") == 0 && arg_index < argc-2) {
111             const TIFFField *fip;
112             const char *tagname;
113             arg_index++;
114             tagname = argv[arg_index];
115             fip = GetField(tiff, tagname);
116             if (!fip)
117                 return 3;
118 
119             if (TIFFUnsetField(tiff, TIFFFieldTag(fip)) != 1)
120             {
121                     fprintf(stderr, "Failed to unset %s\n", TIFFFieldName(fip));
122             }
123             arg_index++;
124     } else if (strcmp(argv[arg_index],"-s") == 0 && arg_index < argc-3) {
125             const TIFFField *fip;
126             const char *tagname;
127 
128             arg_index++;
129             tagname = argv[arg_index];
130             fip = GetField(tiff, tagname);
131 
132             if (!fip)
133                 return 3;
134 
135             arg_index++;
136             if (TIFFFieldDataType(fip) == TIFF_ASCII) {
137                 if (TIFFSetField(tiff, TIFFFieldTag(fip), argv[arg_index]) != 1)
138                     fprintf( stderr, "Failed to set %s=%s\n",
139                              TIFFFieldName(fip), argv[arg_index] );
140             } else if (TIFFFieldWriteCount(fip) > 0
141 		       || TIFFFieldWriteCount(fip) == TIFF_VARIABLE) {
142                 int     ret = 1;
143                 short   wc;
144 
145                 if (TIFFFieldWriteCount(fip) == TIFF_VARIABLE)
146                         wc = atoi(argv[arg_index++]);
147                 else
148                         wc = TIFFFieldWriteCount(fip);
149 
150                 if (argc - arg_index < wc) {
151                     fprintf( stderr,
152                              "Number of tag values is not enough. "
153                              "Expected %d values for %s tag, got %d\n",
154                              wc, TIFFFieldName(fip), argc - arg_index);
155                     return 4;
156                 }
157 
158                 if (wc > 1 || TIFFFieldWriteCount(fip) == TIFF_VARIABLE) {
159                         int     i, size;
160                         void    *array;
161 
162                         switch (TIFFFieldDataType(fip)) {
163                                 /*
164                                  * XXX: We can't use TIFFDataWidth()
165                                  * to determine the space needed to store
166                                  * the value. For TIFF_RATIONAL values
167                                  * TIFFDataWidth() returns 8, but we use 4-byte
168                                  * float to represent rationals.
169                                  */
170                                 case TIFF_BYTE:
171                                 case TIFF_ASCII:
172                                 case TIFF_SBYTE:
173                                 case TIFF_UNDEFINED:
174 				default:
175                                     size = 1;
176                                     break;
177 
178                                 case TIFF_SHORT:
179                                 case TIFF_SSHORT:
180                                     size = 2;
181                                     break;
182 
183                                 case TIFF_LONG:
184                                 case TIFF_SLONG:
185                                 case TIFF_FLOAT:
186                                 case TIFF_IFD:
187                                 case TIFF_RATIONAL:
188                                 case TIFF_SRATIONAL:
189                                     size = 4;
190                                     break;
191 
192                                 case TIFF_DOUBLE:
193                                     size = 8;
194                                     break;
195                         }
196 
197                         array = _TIFFmalloc(wc * size);
198                         if (!array) {
199                                 fprintf(stderr, "No space for %s tag\n",
200                                         tagname);
201                                 return 4;
202                         }
203 
204                         switch (TIFFFieldDataType(fip)) {
205                             case TIFF_BYTE:
206                                 for (i = 0; i < wc; i++)
207                                     ((uint8 *)array)[i] = atoi(argv[arg_index+i]);
208                                 break;
209                             case TIFF_SHORT:
210                                 for (i = 0; i < wc; i++)
211                                     ((uint16 *)array)[i] = atoi(argv[arg_index+i]);
212                                 break;
213                             case TIFF_SBYTE:
214                                 for (i = 0; i < wc; i++)
215                                     ((int8 *)array)[i] = atoi(argv[arg_index+i]);
216                                 break;
217                             case TIFF_SSHORT:
218                                 for (i = 0; i < wc; i++)
219                                     ((int16 *)array)[i] = atoi(argv[arg_index+i]);
220                                 break;
221                             case TIFF_LONG:
222                                 for (i = 0; i < wc; i++)
223                                     ((uint32 *)array)[i] = atol(argv[arg_index+i]);
224                                 break;
225                             case TIFF_SLONG:
226                             case TIFF_IFD:
227                                 for (i = 0; i < wc; i++)
228                                     ((uint32 *)array)[i] = atol(argv[arg_index+i]);
229                                 break;
230                             case TIFF_DOUBLE:
231                                 for (i = 0; i < wc; i++)
232                                     ((double *)array)[i] = atof(argv[arg_index+i]);
233                                 break;
234                             case TIFF_RATIONAL:
235                             case TIFF_SRATIONAL:
236                             case TIFF_FLOAT:
237                                 for (i = 0; i < wc; i++)
238                                     ((float *)array)[i] = (float)atof(argv[arg_index+i]);
239                                 break;
240                             default:
241                                 break;
242                         }
243 
244                         if (TIFFFieldPassCount(fip)) {
245                                 ret = TIFFSetField(tiff, TIFFFieldTag(fip),
246                                                    wc, array);
247                         } else if (TIFFFieldTag(fip) == TIFFTAG_PAGENUMBER
248 				   || TIFFFieldTag(fip) == TIFFTAG_HALFTONEHINTS
249 				   || TIFFFieldTag(fip) == TIFFTAG_YCBCRSUBSAMPLING
250 				   || TIFFFieldTag(fip) == TIFFTAG_DOTRANGE) {
251        				if (TIFFFieldDataType(fip) == TIFF_BYTE) {
252 					ret = TIFFSetField(tiff, TIFFFieldTag(fip),
253 						((uint8 *)array)[0], ((uint8 *)array)[1]);
254 				} else if (TIFFFieldDataType(fip) == TIFF_SHORT) {
255 					ret = TIFFSetField(tiff, TIFFFieldTag(fip),
256 						((uint16 *)array)[0], ((uint16 *)array)[1]);
257 				}
258 			} else {
259                                 ret = TIFFSetField(tiff, TIFFFieldTag(fip),
260                                                    array);
261                         }
262 
263                         _TIFFfree(array);
264                 } else {
265                         switch (TIFFFieldDataType(fip)) {
266                             case TIFF_BYTE:
267                             case TIFF_SHORT:
268                             case TIFF_SBYTE:
269                             case TIFF_SSHORT:
270                                 ret = TIFFSetField(tiff, TIFFFieldTag(fip),
271                                                    atoi(argv[arg_index++]));
272                                 break;
273                             case TIFF_LONG:
274                             case TIFF_SLONG:
275                             case TIFF_IFD:
276                                 ret = TIFFSetField(tiff, TIFFFieldTag(fip),
277                                                    atol(argv[arg_index++]));
278                                 break;
279                             case TIFF_DOUBLE:
280                                 ret = TIFFSetField(tiff, TIFFFieldTag(fip),
281                                                    atof(argv[arg_index++]));
282                                 break;
283                             case TIFF_RATIONAL:
284                             case TIFF_SRATIONAL:
285                             case TIFF_FLOAT:
286                                 ret = TIFFSetField(tiff, TIFFFieldTag(fip),
287                                                    (float)atof(argv[arg_index++]));
288                                 break;
289                             default:
290                                 break;
291                         }
292                 }
293 
294                 if (ret != 1)
295                     fprintf(stderr, "Failed to set %s\n", TIFFFieldName(fip));
296                 arg_index += wc;
297             }
298         } else if (strcmp(argv[arg_index],"-sf") == 0 && arg_index < argc-3) {
299             FILE    *fp;
300             const TIFFField *fip;
301             char    *text;
302             size_t  len;
303 
304             arg_index++;
305             fip = GetField(tiff, argv[arg_index]);
306 
307             if (!fip)
308                 return 3;
309 
310             if (TIFFFieldDataType(fip) != TIFF_ASCII) {
311                 fprintf( stderr,
312                          "Only ASCII tags can be set from file. "
313                          "%s is not ASCII tag.\n", TIFFFieldName(fip) );
314                 return 5;
315             }
316 
317             arg_index++;
318             fp = fopen( argv[arg_index], "rt" );
319             if(fp == NULL) {
320                 perror( argv[arg_index] );
321                 continue;
322             }
323 
324             text = (char *) malloc(1000000);
325             len = fread( text, 1, 999999, fp );
326             text[len] = '\0';
327 
328             fclose( fp );
329 
330             if(TIFFSetField( tiff, TIFFFieldTag(fip), text ) != 1) {
331                 fprintf(stderr, "Failed to set %s from file %s\n",
332                         TIFFFieldName(fip), argv[arg_index]);
333             }
334 
335             _TIFFfree( text );
336             arg_index++;
337         } else {
338             fprintf(stderr, "Unrecognised option: %s\n",
339                     argv[arg_index]);
340             usage();
341         }
342     }
343 
344     TIFFRewriteDirectory(tiff);
345     TIFFClose(tiff);
346     return 0;
347 }
348 
349 /* vim: set ts=8 sts=8 sw=8 noet: */
350 /*
351  * Local Variables:
352  * mode: c
353  * c-basic-offset: 8
354  * fill-column: 78
355  * End:
356  */
357