-
Notifications
You must be signed in to change notification settings - Fork 1
/
jaypack.c
181 lines (155 loc) · 4.55 KB
/
jaypack.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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXSIZE 10LL * 1024LL * 1024LL
#define BUFSIZE 8192
#define SKIPBYTES 0
#define RSSIZE 16
typedef unsigned char byte;
typedef long long llong;
typedef unsigned long long ullong;
byte buf[BUFSIZE], rotostring[RSSIZE], *bufptr;
int maxbuf, rsi;
int read_buf()
{
size_t out = fread(buf, 1, BUFSIZE, stdin);
bufptr = buf;
maxbuf = out;
if (out == 0)
return(-1);
else return(out);
}
int next_byte()
{
if (bufptr > buf + maxbuf - 1) {
if (read_buf() < 0)
return(-1);
}
return *bufptr++;
}
void push_rotobyte(byte b)
{
int nrsi = (rsi + 1) % RSSIZE;
rotostring[nrsi] = b;
rsi = nrsi;
}
int test_rotostring(const byte s[], const byte mask[], size_t sz)
{
/* assert sz <= RSSIZE */
int i;
for (i = 0; i < sz; ++i) {
if (mask[sz - 1 - i] && s[sz - 1 - i] != rotostring[(rsi - i + RSSIZE) % RSSIZE])
return(0);
}
return(1);
}
byte start_str [] = { 0xFF, 0xD8, 0xFF },
end_str [] = { 0xFF, 0xD9 },
end_mask [] = { 0x1 , 0x1 },
/* 0xEE are unimportant bytes */
jfif_str [] = { 0xFF, 0xD8, 0xFF, 0xE0, 0xEE, 0xEE, 'J', 'F', 'I', 'F', 0x00 },
jfif_mask [] = { 0x1 , 0x1, 0x1, 0x1, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1 },
spiff_str [] = { 0xFF, 0xD8, 0xFF, 0xE8, 0xEE, 0xEE, 'S', 'P', 'I', 'F', 'F', 0x00 },
spiff_mask[] = { 0x1 , 0x1, 0x1, 0x1, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
exif_str [] = { 0xFF, 0xD8, 0xFF, 0xE1, 0xEE, 0xEE, 'E', 'x', 'i', 'f', 0x00 },
exif_mask [] = { 0x1 , 0x1, 0x1, 0x1, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1 };
typedef struct header_str {
byte * str,
* mask;
char * fmtid;
int len;
} header_str;
header_str headerstrings[] = {
{ jfif_str, jfif_mask, "jfif", sizeof(jfif_str) },
{ spiff_str, spiff_mask, "spiff", sizeof(spiff_str) },
{ exif_str, exif_mask, "exif", sizeof(exif_str) }
};
#define HEADER_STRING_COUNT (sizeof(headerstrings) / sizeof(header_str))
int opt_maxsz,
opt_skipbytes;
void read_through()
{
int c;
llong l2skip = 0, soi = -1, cursz = 0, off = 0;
const header_str *hdrstr = NULL;
void output_img()
{
fprintf(stdout, "%s %lld %lld\n", hdrstr->fmtid, soi + 1 - hdrstr->len, cursz);
fflush(stdout);
}
while ((c = next_byte()) != -1) {
push_rotobyte(c);
if (soi != -1LL) {
/* too big file! */
if (cursz >= opt_maxsz) {
soi = -1LL;
cursz = 0;
l2skip = 0;
hdrstr = NULL;
++off;
continue;
}
if (l2skip <= 0LL) {
if (test_rotostring(end_str, end_mask, sizeof(end_str))) {
/* eoi found! check size... */
if (cursz <= opt_maxsz) {
output_img();
soi = -1LL;
cursz = 0;
l2skip = 0;
hdrstr = NULL;
++off;
continue;
}
}
} else {
--l2skip;
}
++cursz;
}
int i;
for (i = 0; i < HEADER_STRING_COUNT; ++i) {
const header_str* hs = headerstrings + i;
if (test_rotostring(hs->str, hs->mask, hs->len)) {
if (soi != -1LL) { /* we were inside an image before, dump it */
output_img();
}
/* SOI found! */
soi = off;
cursz = 0LL;
l2skip = opt_skipbytes;
hdrstr = hs;
}
}
++off;
}
}
int main(int argc, char** argv)
{
if (argc < 3) {
fprintf(stderr,
"Usage: \n"
"\n"
" %s maxsize skipbytes\n"
"\n"
" maxsize - The maximum size of the file to consider, or a single minus\n"
" sign. If the latter, 10MiB is assumed.\n"
" skipbytes - The number of bytes to skip and not check for EOI after SOI is\n"
" encountered. Since we're still not smart enough to actually\n"
" skip frames and check for EOI only in the image data (which is\n"
" guaranteed not to contain a spurious EOI mark in compressed data\n"
" and can safely be searched), we need to skip some amount of bytes\n"
" in order to prevent something that looks like an EOI from triggering\n"
" us. Note, this is not likely to happen, just possible. A minus sign\n"
" instead of a value will default to 0.\n"
"\n",
argv[0]
);
return(0);
}
opt_maxsz = (strcmp(argv[1], "-") == 0) ? MAXSIZE : atoi(argv[1]);
opt_skipbytes = (strcmp(argv[2], "-") == 0) ? SKIPBYTES : atoi(argv[2]);
read_buf();
read_through();
return(0);
}