-
Notifications
You must be signed in to change notification settings - Fork 9
/
mod_small_light_ext_jpeg.c
132 lines (115 loc) · 3.37 KB
/
mod_small_light_ext_jpeg.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
/*
** mod_small_light_ext_jpeg.c -- extension for jpeg
*/
#include "mod_small_light.h"
#include "mod_small_light_ext_jpeg.h"
/*
** defines.
*/
#define MAX_MARKERS 16
#define M_SOF 0xc0
#define M_SOF_MIN (M_SOF + 0)
#define M_SOF_MAX (M_SOF + 15)
#define M_SOI 0xd8
#define M_EOI 0xd9
#define M_SOS 0xdA
#define M_APP 0xe0
#define M_APP0 (M_APP + 0)
#define M_APP1 (M_APP + 1)
#define M_COM 0xfe // comment
static char jpeg_header[] = { 0xff, M_SOI };
/*
** functions.
*/
int load_exif_from_memory(
unsigned char **exif_data,
unsigned int *exif_size,
request_rec *r,
const unsigned char *data,
unsigned int data_len)
{
// scan SOI marker.
if (data_len <= 2) return 0;
data_len -= 2;
unsigned char c1 = *data++;
unsigned char c2 = *data++;
if (c1 != 0xff || c2 != M_SOI) {
return 0;
}
int num_marker = 0;
unsigned char *marker_data[MAX_MARKERS];
unsigned int marker_size[MAX_MARKERS];
// scan marker.
for (;;) {
unsigned char c;
for (;;) {
c = *data++;
if (data_len == 0) return 0;
data_len--;
if (c == 0xff) break;
}
for (;;) {
c = *data++;
if (data_len == 0) return 0;
data_len--;
if (c != 0xff) break;
}
// check marker.
if (c == M_EOI || c == M_SOS || c == 0) {
break;
} else if (c == M_APP1 || c == M_COM) {
// get length of app1.
unsigned int length;
length = (*data++ << 8);
length += *(data++ + 1);
// validate length.
if (length < 2) return 0;
// get app1 pointer and length.
if (num_marker < MAX_MARKERS) {
marker_data[num_marker] = (unsigned char *)(data - 4);
marker_size[num_marker] = length + 2;
num_marker++;
}
// skip pointer.
if (data_len <= length) return 0;
data_len -= length;
data += length - 2;
} else {
// get length of app1.
unsigned int length;
length = (*data++ << 8);
length += *(data++ + 1);
// validate length.
if (length < 2) return 0;
// skip pointer.
if (data_len <= length) return 0;
data_len -= length;
data += length - 2;
}
}
// copy app1.
int i;
unsigned int exif_size_total = 0;
for (i = 0; i < num_marker; i++) {
exif_size_total += marker_size[i];
}
*exif_size = exif_size_total;
*exif_data = apr_palloc(r->pool, exif_size_total);
unsigned char *exif_data_ptr = *exif_data;
for (i = 0; i < num_marker; i++) {
memcpy(exif_data_ptr, marker_data[i], marker_size[i]);
exif_data_ptr += marker_size[i];
}
return 1;
}
void exif_brigade_insert_tail(
unsigned char *exif_data, unsigned int exif_size,
unsigned char *image_data, unsigned long image_size,
request_rec *r, apr_bucket_brigade *bb)
{
apr_bucket *b;
b = apr_bucket_pool_create(jpeg_header, sizeof(jpeg_header), r->pool, bb->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, b);
b = apr_bucket_pool_create(exif_data, exif_size, r->pool, bb->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, b);
}