-
Notifications
You must be signed in to change notification settings - Fork 6
/
pngchunks.c
180 lines (154 loc) · 4.26 KB
/
pngchunks.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// List the chunks which appear in a given PNG image
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <arpa/inet.h>
void usage();
const char magic[] = {137, 'P', 'N', 'G', '\r', '\n', 26, '\n'};
typedef struct pngchunks_internal_header
{
int32_t len;
union{
int32_t i;
char c[4];
} type;
} pngchunks_header;
char *meanings[4][2] = {
{"Critical", "Ancillary"},
{"public", "private"},
{"PNG 1.2 compliant", "in reserved chunk space"},
{"unsafe to copy", "safe to copy"}
};
typedef struct pngchunks_internal_IHDR
{
int32_t width;
int32_t height;
unsigned char bitdepth;
unsigned char colortype;
unsigned char compression;
unsigned char filter;
unsigned char interlace;
} pngchunks_IHDR;
int main(int argc, char *argv[])
{
char *data, *offset;
int fd, lastchunk;
struct stat stat;
pngchunks_header *head;
if(argc != 2)
usage();
if ((fd = open (argv[1], O_RDONLY)) < 0)
{
fprintf (stderr, "Could not open the input PNG file\n");
exit (1);
}
if (fstat(fd, &stat) < 0)
{
fprintf(stderr, "Could not determine file size\n");
close(fd);
exit(1);
}
if ((data = mmap (NULL, stat.st_size, PROT_READ, MAP_SHARED, fd, 0)) < 0)
{
fprintf (stderr, "Could not mmap data file\n");
exit (1);
}
offset = data;
// Check that the file is a PNG file
if(memcmp(magic, offset, 8) != 0){
fprintf(stderr, "This is not a PNG file...\n");
exit(1);
}
offset += 8;
// Go into a loop reading chunks from memory until we hit the end chunk
lastchunk = 0;
while(!lastchunk)
{
head = (pngchunks_header *) offset;
printf("Chunk: Data Length %d (max %d), Type %d [%c%c%c%c]\n",
ntohl(head->len),
(unsigned int) pow(2, 31) - 1,
head->type.i,
head->type.c[0], head->type.c[1],
head->type.c[2], head->type.c[3]);
offset += sizeof(pngchunks_header);
printf (" %s, %s, %s, %s\n",
isupper (head->type.c[0]) ? meanings[0][0] : meanings[0][1],
isupper (head->type.c[1]) ? meanings[1][0] : meanings[1][1],
isupper (head->type.c[2]) ? meanings[2][0] : meanings[2][1],
isupper (head->type.c[3]) ? meanings[3][0] : meanings[3][1]);
if(strncmp(head->type.c, "IHDR", 4) == 0)
{
printf(" IHDR Width: %d\n IHDR Height: %d\n IHDR Bitdepth: %d\n IHDR Colortype: %d\n IHDR Compression: %d\n IHDR Filter: %d\n IHDR Interlace: %d\n",
ntohl(((pngchunks_IHDR *) offset)->width),
ntohl(((pngchunks_IHDR *) offset)->height),
((pngchunks_IHDR *) offset)->bitdepth,
((pngchunks_IHDR *) offset)->colortype,
((pngchunks_IHDR *) offset)->compression,
((pngchunks_IHDR *) offset)->filter,
((pngchunks_IHDR *) offset)->interlace);
switch( ((pngchunks_IHDR *) offset)->compression){
case 0:
printf(" IHDR Compression algorithm is Deflate\n");
break;
default:
printf(" IHDR Compression algorithm is unknown\n");
break;
}
switch( ((pngchunks_IHDR *) offset)->filter)
{
case 0:
printf(" IHDR Filter method is type zero (None, Sub, Up, Average, Paeth)\n");
break;
default:
printf(" IHDR Filter method is unknown\n");
break;
}
switch( ((pngchunks_IHDR *) offset)->interlace)
{
case 0:
printf(" IHDR Interlacing is disabled\n");
break;
case 7:
printf(" IHDR Interlacing is Adam7\n");
break;
default:
printf(" IHDR Interlacing method is unknown\n");
break;
}
}
else if(strncmp(head->type.c, "IDAT", 4) == 0)
{
printf(" IDAT contains image data\n");
}
else if(strncmp(head->type.c, "IEND", 4) == 0)
{
printf(" IEND contains no data\n");
lastchunk = 1;
}
else{
printf(" ... Unknown chunk type\n");
}
offset += ntohl(head->len);
printf(" Chunk CRC: %d\n", ntohl(*((long *) offset)));
offset += 4;
}
// Unmap the file
if(munmap(data, stat.st_size) < 0)
{
fprintf(stderr, "Error unmapping memory\n");
exit(1);
}
}
void usage()
{
fprintf(stderr, "Usage: pngchunks <filename>\n");
exit(1);
}