rjhead 0.2.88

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+