OSDN Git Service

test for replaceBitmapData Lossless with alpha0
[swfed/swfed.git] / src / jpeg_segment.c
1 /*
2   ref code) http://diary.awm.jp/~yoya/data/2008/02/03/jpegdump.phps
3   
4   gcc -W -Wall -D__JPEG_SEGMENT_DEBUG__ jpeg_segment.c  bitstream.c
5 */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include "swf_define.h"
10 #include "bitstream.h"
11 #include "jpeg_segment.h"
12
13 typedef struct jpeg_marker_name_ {
14     int marker;
15     char *name;
16 } jpeg_marker_name_t;
17
18 jpeg_marker_name_t jpeg_marker_name_table[] = {
19     {0xD8, "SOI"},
20     {0xE0, "APP0"}, {0xE1, "APP1"}, {0xE2, "APP2"}, {0xE3, "APP3"},
21     {0xE4, "APP4"}, {0xE5, "APP5"}, {0xE6, "APP6"}, {0xE7, "APP7"},
22     {0xE8, "APP8"}, {0xE9, "APP9"}, {0xEA, "APP10"},{0xEB, "APP11"},
23     {0xEC, "APP12"},{0xED, "APP13"},{0xEE, "APP14"},{0xEF, "APP15"},
24     {0xFE, "COM"},
25     {0xDB, "DQT"},
26     {0xC0, "SOF0"}, {0xC1, "SOF1"}, {0xC2, "SOF2"}, {0xC3, "SOF3"},
27                     {0xC5, "SOF5"}, {0xC6, "SOF6"}, {0xC7, "SOF7"},
28     {0xC8, "JPG"},  {0xC9, "SOF9"}, {0xCA, "SOF10"},{0xCB, "SOF11"},
29     {0xCC, "DAC"},  {0xCD, "SOF13"},{0xCE, "SOF14"},{0xCF, "SOF15"},
30     {0xC4, "DHT"},
31     {0xDA, "SOS"},
32     {0xD0, "RST0"}, {0xD1, "RST1"}, {0xD2, "RST2"}, {0xD3, "RST3"},
33     {0xD4, "RST4"}, {0xD5, "RST5"}, {0xD6, "RST6"}, {0xD7, "RST7"},
34     {0xDD, "DRI"},
35     {0xD9, "EOI"},
36     {0xDC, "DNL"}, {0xDE, "DHP"},  {0xDF, "EXP"},
37     {0xF0, "JPG0"}, {0xF1, "JPG1"}, {0xF2, "JPG2"}, {0xF3, "JPG3"},
38     {0xF4, "JPG4"}, {0xF5, "JPG5"}, {0xF6, "JPG6"}, {0xF7, "JPG7"},
39     {0xF8, "JPG8"}, {0xF9, "JPG9"}, {0xFA, "JPG10"},{0xFB, "JPG11"},
40     {0xFC, "JPG12"},{0xFD, "JPG13"},
41 };
42
43 #define NumOfTable(t) (sizeof(t) / sizeof(*t))
44      
45 char *jpeg_segment_get_marker_name(int marker) {
46     int i, marker_name_num = NumOfTable(jpeg_marker_name_table);
47     for (i=0 ; i < marker_name_num ; i++) {
48         if (marker == jpeg_marker_name_table[i].marker) {
49             return jpeg_marker_name_table[i].name;
50         }
51     }
52     return "Unknown";
53 }
54
55 jpeg_segment_t *jpeg_segment_create(void) {
56     jpeg_segment_t *jpeg_seg = calloc(sizeof(*jpeg_seg), 1);
57     if (jpeg_seg == NULL) {
58         fprintf(stderr, "jpeg_segment_create: Can't alloc memory\n");
59         return NULL;
60     }
61     jpeg_seg->head = NULL;
62     jpeg_seg->tail = NULL;
63     return jpeg_seg;
64 }
65
66 void jpeg_segment_append(jpeg_segment_t *jpeg_seg,
67                          int marker,
68                          unsigned char *data_ref, unsigned long data_len) {
69     jpeg_segment_node_t *node = jpeg_seg->head;
70     jpeg_segment_node_t *new_node;
71     new_node = calloc(sizeof(*node), 1);
72     if (new_node == NULL) {
73         fprintf(stderr, "jpeg_segment_append: jpeg_segment_create failed\n");
74         return ;
75     }
76     if (jpeg_seg->head == NULL) {
77         jpeg_seg->head = new_node;
78     } else {
79         jpeg_seg->tail->next = new_node;
80     }
81     jpeg_seg->tail = new_node;
82     new_node->marker = marker;
83     new_node->data_ref = data_ref;
84     new_node->data_len = data_len;
85     return ;
86 }
87
88 jpeg_segment_t *jpeg_segment_parse(unsigned char *data, 
89                                    unsigned long data_len,
90                                    int rst_scan) {
91     bitstream_t *bs;
92     jpeg_segment_t *jpeg_seg;
93     int marker1;
94     unsigned len;
95     int eoi_found = 0;
96     bs = bitstream_open();
97     bitstream_input(bs, data, data_len);
98     jpeg_seg = jpeg_segment_create();
99     
100     while((marker1 = bitstream_getbyte(bs)) >= 0) {
101         int marker2;
102         int next_marker2;
103         if (marker1 != 0xFF) {
104             if (eoi_found) {
105                 break;
106             }
107             fprintf(stderr, "jpeg_segment_parse: marker1=0x%02X\n", marker1);
108             jpeg_segment_destroy(jpeg_seg);
109             bitstream_close(bs);
110             return NULL;
111         }
112         marker2 = bitstream_getbyte(bs);
113         switch(marker2) {
114             unsigned long sos_offset;
115           case -1:
116               /* removed segment */
117               break;
118           case 0xD8: // SOI (Start of Image)
119             jpeg_segment_append(jpeg_seg, marker2, NULL, 0);
120             break;
121           case 0xD9: // EOI (End of Image)
122             jpeg_segment_append(jpeg_seg, marker2, NULL, 0);
123             eoi_found = 1;
124             break;
125           case 0xDA: // SOS
126             if ((! rst_scan) && (data[data_len - 2] == 0xFF) &&
127                 (data[data_len - 1] == 0xD9)) {
128               int sos_len;
129               sos_offset = bitstream_getbytepos(bs);
130               sos_len = data_len - sos_offset - 2;
131               jpeg_segment_append(jpeg_seg, marker2, data + sos_offset,
132                                   sos_len);
133               bitstream_incrpos(bs, sos_len, 0);
134               marker1 = bitstream_getbyte(bs);
135               marker2 = bitstream_getbyte(bs);
136               jpeg_segment_append(jpeg_seg, marker2, NULL, 0); // EOI
137               break;
138             }
139             // no break;
140           case 0xD0: case 0xD1: case 0xD2: case 0xD3: // RST
141           case 0xD4: case 0xD5: case 0xD6: case 0xD7: // RST
142               sos_offset = bitstream_getbytepos(bs);
143               while((marker1 = bitstream_getbyte(bs)) >= 0) {
144                   if (marker1 != 0xFF) {
145                       continue;
146                   }
147                   next_marker2 = bitstream_getbyte(bs);
148                   if (next_marker2 == 0x00) {
149                       continue;
150                   }
151                   bitstream_incrpos(bs, -2, 0);
152                   jpeg_segment_append(jpeg_seg, marker2, data + sos_offset,
153                                       bitstream_getbytepos(bs) - sos_offset);
154                   break;
155               }
156               break;
157           default:
158               len = bitstream_getbytesBE(bs, 2) - 2;
159               jpeg_segment_append(jpeg_seg, marker2,
160                                   data + bitstream_getbytepos(bs),
161                                   len);
162               bitstream_incrpos(bs, len, 0);
163               break;
164         }
165     }
166     bitstream_close(bs);
167     return jpeg_seg;
168 }
169
170 int jpeg_segment_contain(jpeg_segment_t *jpeg_seg, int marker) {
171     jpeg_segment_node_t *node;
172     for (node=jpeg_seg->head ; node ; node=node->next) {
173         if (node->marker == marker) {
174             return 1;
175         }            
176     }
177     return 0;
178 }
179
180 unsigned char *jpeg_segment_steal_node(jpeg_segment_t *jpeg_seg,
181                                        int marker,
182                                        unsigned long *length) {
183     jpeg_segment_node_t *node;
184     unsigned char *data;
185     *length = 0;
186     for (node=jpeg_seg->head ; node ; node=node->next) {
187         if (node->marker == marker) {
188             data = node->data_ref;
189             *length = node->data_len;
190             node->marker = -1; // remove mark;
191             node->data_ref = NULL;
192             node->data_len = 0;
193             return data;
194         }
195     }
196     return NULL;
197 }
198
199 int
200 jpeg_segment_delete_node(jpeg_segment_t *jpeg_seg, int marker) {
201     jpeg_segment_node_t *node;
202     int count = 0;
203     for (node=jpeg_seg->head ; node ; node=node->next) {
204         if (node->marker == marker) {
205             node->marker = -1; // remove mark;
206             node->data_ref = NULL;
207             node->data_len = 0;
208             count ++;
209         }
210     }
211     return count;
212 }
213
214 int
215 jpeg_segment_peek_marker(jpeg_segment_t *jpeg_seg) {
216     jpeg_segment_node_t *node;
217     for (node=jpeg_seg->head ; node ; node=node->next) {
218         if (node->marker != -1) {
219             return node->marker;
220         }     
221     }
222     return -1;
223 }
224
225 void
226 jpeg_segment_print(jpeg_segment_t *jpeg_seg) {
227     int i;
228     jpeg_segment_node_t *node;
229     if (jpeg_seg == NULL) {
230         fprintf(stderr, "jpeg_segment_print: jpeg_seg == NULL\n");
231         return ;
232     }
233     node = jpeg_seg->head;
234     for (i=0 ; node ; i++) {
235         char *marker_name;
236         if (node->marker >= 0) {
237             marker_name = jpeg_segment_get_marker_name(node->marker);
238             printf("(%d) marker=%s(FF%02X): length=%lu\n",
239                    i, marker_name?marker_name:"Unknown",
240                    node->marker, node->data_len);
241         }
242         node = node->next;
243     }
244 }
245
246 unsigned char *
247 jpeg_segment_output(jpeg_segment_t *jpeg_seg, unsigned long *length) {
248     bitstream_t *bs;
249     unsigned char *data;
250     jpeg_segment_node_t *node;
251     *length = 0;
252     node = jpeg_seg->head;
253     bs = bitstream_open();
254     for (; node ; node=node->next) {
255         int marker2 = node->marker;
256         if (marker2 == -1) {
257             continue;
258         }
259         bitstream_putbyte(bs, 0xFF); // marker1
260         bitstream_putbyte(bs, marker2); // marker2
261         switch(marker2) {
262           case 0xD8: // SOI (Start of Image)
263           case 0xD9: // EOI (End of Image)
264               /* nothing to do */
265             break;
266           default:
267               bitstream_putbytesBE(bs, node->data_len + 2, 2);
268               /* no break */
269           case 0xDA: // SOS
270           case 0xD0: case 0xD1: case 0xD2: case 0xD3: // RST
271           case 0xD4: case 0xD5: case 0xD6: case 0xD7: // RST
272               bitstream_putstring(bs, node->data_ref, node->data_len);
273               break;
274         }
275     }
276     data = bitstream_steal(bs, length);
277     bitstream_close(bs);
278     return data;
279 }
280
281 void jpeg_segment_destroy(jpeg_segment_t *jpeg_seg) {
282     jpeg_segment_node_t *node, *next_node;
283     if (jpeg_seg == NULL) {
284         return ;
285     }
286     node = jpeg_seg->head;
287     while(node) {
288         next_node = node->next;
289         /* node->data_ref  no free!! */
290         free(node);
291         node = next_node;
292     }
293     free(jpeg_seg);
294 }
295
296 #ifdef __JPEG_SEGMENT_DEBUG__  /* for component debug */
297
298 #include <sys/stat.h>
299
300 int main(int argc, char **argv) {
301     char *filename;
302     struct stat sbuf;
303     FILE *fp, *fp_out = NULL;
304     unsigned char *data, *output_data;
305     unsigned long data_len, output_data_len;
306     jpeg_segment_t *jpeg_seg;
307     if ((argc != 2) && (argc != 3)) {
308         fprintf(stderr, "Usage: %s <jpeg_infile> [<jpeg_outfile>]\n", argv[0]);
309         return EXIT_FAILURE;
310     }
311     filename = argv[1];
312     if (stat(filename, &sbuf)) {
313         fprintf(stderr, "Can't stat file(%s)\n", filename);
314         return EXIT_FAILURE;
315     }
316     data_len = sbuf.st_size;
317     fp = fopen(filename, "rb");
318     if (fp == NULL) {
319         fprintf(stderr, "Can't open infile(%s)\n", filename);
320         return EXIT_FAILURE;
321     }
322     data = malloc(data_len);
323     if (fread(data, 1, data_len, fp) != data_len) {
324         fclose(fp);
325         return 1;
326     }
327     fclose(fp);
328     jpeg_seg = jpeg_segment_parse(data, data_len, 1);
329     jpeg_segment_print(jpeg_seg);
330     if (argc == 3) {
331         fp_out = fopen(argv[2], "wb");
332         if (fp_out == NULL) {
333             fprintf(stderr, "Can't open outfile(%s)\n", argv[2]);
334             return EXIT_FAILURE;
335         }
336         output_data = jpeg_segment_output(jpeg_seg, &output_data_len);
337         fwrite(output_data, output_data_len, 1, fp_out);
338         fclose(fp_out);
339         free(output_data);
340     }
341     jpeg_segment_destroy(jpeg_seg);
342     free(data);
343     return EXIT_SUCCESS;
344 }
345
346 #endif /* __JPEG_SEGMENT_DEBUG__ */