/
image_empty_check.c
131 lines (113 loc) · 2.49 KB
/
image_empty_check.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
/* compile using: gcc -O2 -lwebp -lpng image_empty_check.c */
#include <stdio.h>
#include <stdlib.h>
#ifndef NO_WEBP
#include <webp/decode.h>
#endif
#ifndef NO_PNG
#include <png.h>
#endif
#define ERROR(...) do { fprintf(stderr, __VA_ARGS__); return 2; } while(0)
/* disallow loading images >32MB in size */
#ifndef MAX_SIZE
#define MAX_SIZE 33554432
#endif
#ifndef MAX_IMAGE_SIZE
#define MAX_IMAGE_SIZE 134217728
#endif
#define SIG_PNG (*(uint32_t*)"\x89PNG")
#define SIG_WEBP (*(uint32_t*)"RIFF")
int main(int argc, char** argv) {
/* read input */
if(argc != 2)
ERROR("Usage: %s [image_file]\n", argv[0]);
FILE* fp = fopen(argv[1], "rb");
if(!fp)
ERROR("Failed to open input file\n");
fseek(fp, 0, SEEK_END);
size_t size = ftell(fp);
fseek(fp, 0, SEEK_SET);
if(size > MAX_SIZE) {
fclose(fp);
ERROR("File size limited exceeded\n");
}
uint8_t* buf = malloc(size);
size_t read = fread(buf, size, 1, fp);
fclose(fp);
if(!read) {
free(buf);
ERROR("Failed to read file\n");
}
/* Render */
uint32_t sig = *(uint32_t*)buf;
int width, height;
uint8_t* image = NULL;
#ifndef NO_PNG
if(sig == SIG_PNG) {
png_image png;
png.version = PNG_IMAGE_VERSION;
png.opaque = NULL;
if(!png_image_begin_read_from_memory(&png, buf, size)) {
free(buf);
ERROR("%s\n", png.message);
}
if(!(png.format & PNG_FORMAT_FLAG_ALPHA)) {
free(buf);
png_image_free(&png);
return 1;
}
png.format = PNG_FORMAT_ARGB;
if(PNG_IMAGE_SIZE(png) > MAX_IMAGE_SIZE) {
free(buf);
ERROR("Image too large\n");
}
image = malloc(PNG_IMAGE_SIZE(png));
int success = png_image_finish_read(&png, NULL, image, 0, NULL);
png_image_free(&png);
if(!success) {
free(image);
free(buf);
ERROR("%s\n", png.message);
}
width = png.width;
height = png.height;
} else
#endif
#ifndef NO_WEBP
if(sig == SIG_WEBP) {
WebPBitstreamFeatures webp;
if(WebPGetFeatures(buf, size, &webp) != VP8_STATUS_OK) {
free(buf);
ERROR("Invalid WEBP file\n");
}
if(!webp.has_alpha) {
free(buf);
return 1;
}
if(webp.width * webp.height * 4 > MAX_IMAGE_SIZE) {
free(buf);
ERROR("Image too large\n");
}
image = WebPDecodeARGB(buf, size, &width, &height);
} else
#endif
{
free(buf);
ERROR("Invalid PNG/WEBP file\n");
}
free(buf);
if(!image)
ERROR("Failed to render supplied file\n");
/* transparency check */
int result = 0;
long i = width * height * 4;
while(i) {
i -= 4;
if(image[i] != 0) {
result = 1;
break;
}
}
free(image);
return result;
}