rjhead 0.2.88

Sign up to get free protection for your applications and to get access to all the features.
data/ext/make.bat ADDED
@@ -0,0 +1 @@
1
+ nmake -f makefile-win32
data/ext/makefile ADDED
@@ -0,0 +1,23 @@
1
+ #--------------------------------
2
+ # jhead makefile for Unix
3
+ #--------------------------------
4
+ OBJ=.
5
+ SRC=.
6
+ CFLAGS= -O3 -Wall
7
+
8
+ all: jhead
9
+
10
+ objs = $(OBJ)/jhead.o $(OBJ)/jpgfile.o $(OBJ)/paths.o \
11
+ $(OBJ)/exif.o $(OBJ)/iptc.o $(OBJ)/gpsinfo.o $(OBJ)/makernote.o
12
+
13
+ $(OBJ)/%.o:$(SRC)/%.c
14
+ ${CC} $(CFLAGS) -c $< -o $@
15
+
16
+ jhead: $(objs) jhead.h
17
+ ${CC} -o jhead $(objs) -lm
18
+
19
+ clean:
20
+ rm -f $(objs) jhead
21
+
22
+ install:
23
+ mkdir -p ../bin; cp jhead ../bin/jhead
@@ -0,0 +1,27 @@
1
+ #--------------------------------
2
+ # jhead makefile for Win32
3
+ #--------------------------------
4
+
5
+ CC=cl /nologo
6
+ CFLAGS=-c -G3 -Ox -W3 -Zp -Zd
7
+ LINKER=link
8
+ LINKCON = /nologo
9
+
10
+ all:jhead.exe
11
+
12
+ OBJ = .
13
+
14
+ OBJECTS_JHEAD = $(OBJ)\jhead.obj \
15
+ $(OBJ)\jpgfile.obj \
16
+ $(OBJ)\myglob.obj \
17
+ $(OBJ)\paths.obj \
18
+ $(OBJ)\exif.obj \
19
+ $(OBJ)\iptc.obj \
20
+ $(OBJ)\gpsinfo.obj \
21
+ $(OBJ)\makernote.obj
22
+
23
+ $(OBJECTS_JHEAD): $(@B).c jhead.h
24
+ $(CC) /Fo$(OBJ)\ $(CFLAGS) $(@B).c
25
+
26
+ jhead.exe: $(OBJECTS_JHEAD)
27
+ $(LINKER) $(LINKCON) -OUT:jhead.exe $(OBJECTS_JHEAD)
data/ext/makernote.c ADDED
@@ -0,0 +1,184 @@
1
+ //--------------------------------------------------------------------------
2
+ // Parse some maker specific onformation.
3
+ // (Very limited right now - add maker specific stuff to this module)
4
+ //--------------------------------------------------------------------------
5
+ #include "jhead.h"
6
+
7
+ //--------------------------------------------------------------------------
8
+ // Process exif format directory, as used by Cannon maker note
9
+ //--------------------------------------------------------------------------
10
+ void ProcessCanonMakerNoteDir(unsigned char * DirStart, unsigned char * OffsetBase,
11
+ unsigned ExifLength)
12
+ {
13
+ int de;
14
+ int a;
15
+ int NumDirEntries;
16
+
17
+ NumDirEntries = Get16u(DirStart);
18
+ #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry))
19
+
20
+ {
21
+ unsigned char * DirEnd;
22
+ DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries);
23
+ if (DirEnd > (OffsetBase+ExifLength)){
24
+ ErrNonfatal("Illegally sized Exif makernote subdir (%d entries)",NumDirEntries,0);
25
+ return;
26
+ }
27
+
28
+ if (DumpExifMap){
29
+ printf("Map: %05d-%05d: Directory (makernote)\n",(int)(DirStart-OffsetBase), (int)(DirEnd-OffsetBase));
30
+ }
31
+ }
32
+
33
+ if (ShowTags){
34
+ printf("(dir has %d entries)\n",NumDirEntries);
35
+ }
36
+
37
+ for (de=0;de<NumDirEntries;de++){
38
+ int Tag, Format, Components;
39
+ unsigned char * ValuePtr;
40
+ int ByteCount;
41
+ unsigned char * DirEntry;
42
+ DirEntry = DIR_ENTRY_ADDR(DirStart, de);
43
+
44
+ Tag = Get16u(DirEntry);
45
+ Format = Get16u(DirEntry+2);
46
+ Components = Get32u(DirEntry+4);
47
+
48
+ if ((Format-1) >= NUM_FORMATS) {
49
+ // (-1) catches illegal zero case as unsigned underflows to positive large.
50
+ ErrNonfatal("Illegal Exif number format %d for maker tag %04x", Format, Tag);
51
+ continue;
52
+ }
53
+
54
+ if ((unsigned)Components > 0x10000){
55
+ ErrNonfatal("Too many components (%d) for Exif maker tag %04x", Components, Tag);
56
+ continue;
57
+ }
58
+
59
+ ByteCount = Components * BytesPerFormat[Format];
60
+
61
+ if (ByteCount > 4){
62
+ unsigned OffsetVal;
63
+ OffsetVal = Get32u(DirEntry+8);
64
+ // If its bigger than 4 bytes, the dir entry contains an offset.
65
+ if (OffsetVal+ByteCount > ExifLength){
66
+ // Bogus pointer offset and / or bytecount value
67
+ ErrNonfatal("Illegal value pointer for Exif maker tag %04x", Tag,0);
68
+ continue;
69
+ }
70
+ ValuePtr = OffsetBase+OffsetVal;
71
+
72
+ if (DumpExifMap){
73
+ printf("Map: %05d-%05d: Data for makernote tag %04x\n",OffsetVal, OffsetVal+ByteCount, Tag);
74
+ }
75
+ }else{
76
+ // 4 bytes or less and value is in the dir entry itself
77
+ ValuePtr = DirEntry+8;
78
+ }
79
+
80
+ if (ShowTags){
81
+ // Show tag name
82
+ printf(" Canon maker tag %04x Value = ", Tag);
83
+ }
84
+
85
+ // Show tag value.
86
+ switch(Format){
87
+
88
+ case FMT_UNDEFINED:
89
+ // Undefined is typically an ascii string.
90
+
91
+ case FMT_STRING:
92
+ // String arrays printed without function call (different from int arrays)
93
+ if (ShowTags){
94
+ printf("\"");
95
+ for (a=0;a<ByteCount;a++){
96
+ int ZeroSkipped = 0;
97
+ if (ValuePtr[a] >= 32){
98
+ if (ZeroSkipped){
99
+ printf("?");
100
+ ZeroSkipped = 0;
101
+ }
102
+ putchar(ValuePtr[a]);
103
+ }else{
104
+ if (ValuePtr[a] == 0){
105
+ ZeroSkipped = 1;
106
+ }
107
+ }
108
+ }
109
+ printf("\"\n");
110
+ }
111
+ break;
112
+
113
+ default:
114
+ if (ShowTags){
115
+ PrintFormatNumber(ValuePtr, Format, ByteCount);
116
+ printf("\n");
117
+ }
118
+ }
119
+ if (Tag == 1 && Components > 16){
120
+ int IsoCode = Get16u(ValuePtr + 16*sizeof(unsigned short));
121
+ if (IsoCode >= 16 && IsoCode <= 24){
122
+ ImageInfo.ISOequivalent = 50 << (IsoCode-16);
123
+ }
124
+ }
125
+
126
+ if (Tag == 4 && Format == FMT_USHORT){
127
+ if (Components > 7){
128
+ int WhiteBalance = Get16u(ValuePtr + 7*sizeof(unsigned short));
129
+ switch(WhiteBalance){
130
+ // 0=Auto, 6=Custom
131
+ case 1: ImageInfo.LightSource = 1; break; // Sunny
132
+ case 2: ImageInfo.LightSource = 1; break; // Cloudy
133
+ case 3: ImageInfo.LightSource = 3; break; // Thungsten
134
+ case 4: ImageInfo.LightSource = 2; break; // Fourescent
135
+ case 5: ImageInfo.LightSource = 4; break; // Flash
136
+ }
137
+ }
138
+ if (Components > 19 && ImageInfo.Distance <= 0) {
139
+ // Indicates the distance the autofocus camera is focused to.
140
+ // Tends to be less accurate as distance increases.
141
+ int temp_dist = Get16u(ValuePtr + 19*sizeof(unsigned short));
142
+ if (temp_dist != 65535){
143
+ ImageInfo.Distance = (float)temp_dist/100;
144
+ }else{
145
+ ImageInfo.Distance = -1 /* infinity */;
146
+ }
147
+ }
148
+ }
149
+ }
150
+ }
151
+
152
+ //--------------------------------------------------------------------------
153
+ // Show generic maker note - just hex bytes.
154
+ //--------------------------------------------------------------------------
155
+ void ShowMakerNoteGeneric(unsigned char * ValuePtr, int ByteCount)
156
+ {
157
+ int a;
158
+ for (a=0;a<ByteCount;a++){
159
+ if (a > 10){
160
+ printf("...");
161
+ break;
162
+ }
163
+ printf(" %02x",ValuePtr[a]);
164
+ }
165
+ printf(" (%d bytes)", ByteCount);
166
+ printf("\n");
167
+
168
+ }
169
+
170
+ //--------------------------------------------------------------------------
171
+ // Process maker note - to the limited extent that its supported.
172
+ //--------------------------------------------------------------------------
173
+ void ProcessMakerNote(unsigned char * ValuePtr, int ByteCount,
174
+ unsigned char * OffsetBase, unsigned ExifLength)
175
+ {
176
+ if (strstr(ImageInfo.CameraMake, "Canon")){
177
+ ProcessCanonMakerNoteDir(ValuePtr, OffsetBase, ExifLength);
178
+ }else{
179
+ if (ShowTags){
180
+ ShowMakerNoteGeneric(ValuePtr, ByteCount);
181
+ }
182
+ }
183
+ }
184
+
data/ext/myglob.c ADDED
@@ -0,0 +1,305 @@
1
+ //--------------------------------------------------------------------------------
2
+ // Module to do recursive directory file matching under windows.
3
+ //
4
+ // Tries to do pattern matching to produce similar results as Unix, but using
5
+ // the Windows _findfirst to do all the pattern matching.
6
+ //
7
+ // Also hadles recursive directories - "**" path component expands into
8
+ // any levels of subdirectores (ie c:\**\*.c matches ALL .c files on drive c:)
9
+ //
10
+ // Matthias Wandel Nov 5 2000
11
+ //--------------------------------------------------------------------------------
12
+ #include <stdio.h>
13
+ #include <stdlib.h>
14
+ #include <string.h>
15
+ #include <errno.h>
16
+ #include <ctype.h>
17
+ #include <io.h>
18
+ #include "jhead.h"
19
+
20
+ #define TRUE 1
21
+ #define FALSE 0
22
+
23
+ //#define DEBUGGING
24
+
25
+ typedef struct {
26
+ char * Name;
27
+ int attrib;
28
+ }FileEntry;
29
+
30
+
31
+ #ifdef DEBUGGING
32
+ //--------------------------------------------------------------------------------
33
+ // Dummy function to show operation.
34
+ //--------------------------------------------------------------------------------
35
+ void ShowName(const char * FileName)
36
+ {
37
+ printf(" %s\n",FileName);
38
+ }
39
+ #endif
40
+
41
+ //--------------------------------------------------------------------------------
42
+ // Simple path splicing (assumes no '\' in either part)
43
+ //--------------------------------------------------------------------------------
44
+ static void SplicePath(char * dest, const char * p1, const char * p2)
45
+ {
46
+ int l;
47
+ l = strlen(p1);
48
+ if (!l){
49
+ strcpy(dest, p2);
50
+ }else{
51
+ if (l+strlen(p2) > _MAX_PATH-2){
52
+ fprintf(stderr,"Path too long\n");
53
+ exit(-1);
54
+ }
55
+ memcpy(dest, p1, l+1);
56
+ if (dest[l-1] != '\\' && dest[l-1] != ':'){
57
+ dest[l++] = '\\';
58
+ }
59
+ strcpy(dest+l, p2);
60
+ }
61
+ }
62
+
63
+ //--------------------------------------------------------------------------------
64
+ // Qsort compare function
65
+ //--------------------------------------------------------------------------------
66
+ int CompareFunc(const void * f1, const void * f2)
67
+ {
68
+ return strcmp(((FileEntry *)f1)->Name,((FileEntry *)f2)->Name);
69
+ }
70
+
71
+ //--------------------------------------------------------------------------------
72
+ // Decide how a particular pattern should be handled, and call function for each.
73
+ //--------------------------------------------------------------------------------
74
+ void MyGlob(const char * Pattern , void (*FileFuncParm)(const char * FileName))
75
+ {
76
+ char BasePattern[_MAX_PATH];
77
+ char MatchPattern[_MAX_PATH];
78
+ char PatCopy[_MAX_PATH*2+1];
79
+
80
+ int a;
81
+
82
+ int MatchFiles, MatchDirs;
83
+ int BaseEnd, PatternEnd;
84
+ int SawPat;
85
+ int RecurseAt;
86
+
87
+ strcpy(PatCopy, Pattern);
88
+
89
+ #ifdef DEBUGGING
90
+ printf("Called with '%s'\n",Pattern);
91
+ #endif
92
+
93
+ DoRecursion:
94
+ MatchFiles = FALSE;
95
+ MatchDirs = TRUE;
96
+ BaseEnd = 0;
97
+ PatternEnd = 0;
98
+
99
+ SawPat = FALSE;
100
+ RecurseAt = -1;
101
+
102
+ // Split the path into base path and pattern to match against using findfirst.
103
+ for (a=0;;a++){
104
+ if (PatCopy[a] == '*' || PatCopy[a] == '?'){
105
+ SawPat = TRUE;
106
+ }
107
+
108
+ if (PatCopy[a] == '*' && PatCopy[a+1] == '*'){
109
+ if (a == 0 || PatCopy[a-1] == '\\' || PatCopy[a-1] == ':'){
110
+ if (PatCopy[a+2] == '\\' || PatCopy[a+2] == '\0'){
111
+ // x\**\y ---> x\y x\*\**\y
112
+ RecurseAt = a;
113
+ if (PatCopy[a+2]){
114
+ memcpy(PatCopy+a, PatCopy+a+3, strlen(PatCopy)-a-1);
115
+ }else{
116
+ PatCopy[a+1] = '\0';
117
+ }
118
+ }
119
+ }
120
+ }
121
+
122
+ if (PatCopy[a] == '\\' || (PatCopy[a] == ':' && PatCopy[a+1] != '\\')){
123
+ PatternEnd = a;
124
+ if (SawPat) break; // Findfirst can only match one level of wildcard at a time.
125
+ BaseEnd = a+1;
126
+ }
127
+ if (PatCopy[a] == '\0'){
128
+ PatternEnd = a;
129
+ MatchFiles = TRUE;
130
+ MatchDirs = FALSE;
131
+ break;
132
+ }
133
+ }
134
+
135
+ if (!SawPat){
136
+ // No pattern. This should refer to a file.
137
+ FileFuncParm(PatCopy);
138
+ return;
139
+ }
140
+
141
+ strncpy(BasePattern, PatCopy, BaseEnd);
142
+ BasePattern[BaseEnd] = 0;
143
+
144
+ strncpy(MatchPattern, PatCopy, PatternEnd);
145
+ MatchPattern[PatternEnd] = 0;
146
+
147
+ #ifdef DEBUGGING
148
+ printf("Base:%s Pattern:%s Files:%d dirs:%d\n",BasePattern, MatchPattern, MatchFiles, MatchDirs);
149
+ #endif
150
+
151
+ {
152
+ FileEntry * FileList = NULL;
153
+ int NumAllocated = 0;
154
+ int NumHave = 0;
155
+
156
+ struct _finddata_t finddata;
157
+ long find_handle;
158
+
159
+ find_handle = _findfirst(MatchPattern, &finddata);
160
+
161
+ for (;;){
162
+ if (find_handle == -1) break;
163
+
164
+ // Eliminate the obvious patterns.
165
+ if (!memcmp(finddata.name, ".",2)) goto next_file;
166
+ if (!memcmp(finddata.name, "..",3)) goto next_file;
167
+
168
+ if (finddata.attrib & _A_SUBDIR){
169
+ if (!MatchDirs) goto next_file;
170
+ }else{
171
+ if (!MatchFiles) goto next_file;
172
+ }
173
+
174
+ // Add it to the list.
175
+ if (NumAllocated <= NumHave){
176
+ NumAllocated = NumAllocated+10+NumAllocated/2;
177
+ FileList = realloc(FileList, NumAllocated * sizeof(FileEntry));
178
+ if (FileList == NULL) goto nomem;
179
+ }
180
+ a = strlen(finddata.name);
181
+ FileList[NumHave].Name = malloc(a+1);
182
+ if (FileList[NumHave].Name == NULL){
183
+ nomem:
184
+ printf("malloc failure\n");
185
+ exit(-1);
186
+ }
187
+ memcpy(FileList[NumHave].Name, finddata.name, a+1);
188
+ FileList[NumHave].attrib = finddata.attrib;
189
+ NumHave++;
190
+
191
+ next_file:
192
+ if (_findnext(find_handle, &finddata) != 0) break;
193
+ }
194
+ _findclose(find_handle);
195
+
196
+ // Sort the list...
197
+ qsort(FileList, NumHave, sizeof(FileEntry), CompareFunc);
198
+
199
+
200
+ // Use the list.
201
+ for (a=0;a<NumHave;a++){
202
+ char CombinedName[_MAX_PATH*2+1];
203
+ if (FileList[a].attrib & _A_SUBDIR){
204
+ if (MatchDirs){
205
+ // Need more directories.
206
+ SplicePath(CombinedName, BasePattern, FileList[a].Name);
207
+ strncat(CombinedName, PatCopy+PatternEnd, _MAX_PATH*2-strlen(CombinedName));
208
+ MyGlob(CombinedName,FileFuncParm);
209
+ }
210
+ }else{
211
+ if (MatchFiles){
212
+ // We need files at this level.
213
+ SplicePath(CombinedName, BasePattern, FileList[a].Name);
214
+ FileFuncParm(CombinedName);
215
+ }
216
+ }
217
+ free(FileList[a].Name);
218
+ }
219
+ free(FileList);
220
+ }
221
+
222
+ if(RecurseAt >= 0){
223
+ strcpy(MatchPattern, PatCopy+RecurseAt);
224
+ PatCopy[RecurseAt] = 0;
225
+ strncpy(PatCopy+RecurseAt, "*\\**\\", _MAX_PATH*2-RecurseAt);
226
+ strncat(PatCopy, MatchPattern, _MAX_PATH*2-strlen(PatCopy));
227
+
228
+ #ifdef DEBUGGING
229
+ printf("Recurse with '%s'\n",PatCopy);
230
+ #endif
231
+
232
+ // As this function context is no longer needed, we can just goto back
233
+ // to the top of it to avoid adding another context on the stack.
234
+ goto DoRecursion;
235
+ }
236
+ }
237
+
238
+ //--------------------------------------------------------------------------------
239
+ // Flip slashes to native OS representation (for Windows)
240
+ //--------------------------------------------------------------------------------
241
+ void SlashToNative(char * Path)
242
+ {
243
+ int a;
244
+ for (a=0;Path[a];a++){
245
+ if (Path[a] == '/') Path[a] = SLASH;
246
+ }
247
+ }
248
+
249
+
250
+ #ifdef DEBUGGING
251
+ //--------------------------------------------------------------------------------
252
+ // The main program.
253
+ //--------------------------------------------------------------------------------
254
+ int main (int argc, char **argv)
255
+ {
256
+ int argn;
257
+ char * arg;
258
+ int Subdirs = 0;
259
+
260
+ for (argn=1;argn<argc;argn++){
261
+ arg = argv[argn];
262
+ if (arg[0] != '-') break; // Filenames from here on.
263
+ if (!strcmp(arg,"-r")){
264
+ printf("do recursive\n");
265
+ Subdirs = 1;
266
+ }else{
267
+ fprintf(stderr, "Argument '%s' not understood\n",arg);
268
+ }
269
+ }
270
+ if (argn == argc){
271
+ fprintf(stderr,"Error: Must supply a file name\n");
272
+ }
273
+
274
+ for (;argn<argc;argn++){
275
+ MyGlob(argv[argn], ShowName);
276
+ }
277
+ return EXIT_SUCCESS;
278
+ }
279
+ #endif
280
+
281
+ /*
282
+
283
+ non-recursive test cases:
284
+
285
+ e:\make*\*
286
+ \make*\*
287
+ e:*\*.c
288
+ \*\*.c
289
+ \*
290
+ c:*.c
291
+ c:\*
292
+ ..\*.c
293
+
294
+
295
+ recursive test cases:
296
+ **
297
+ **\*.c
298
+ c:\**\*.c
299
+ c:**\*.c
300
+ .\**
301
+ ..\**
302
+
303
+ */
304
+
305
+