/src/imagemagick/coders/meta.c
Line | Count | Source |
1 | | /* |
2 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
3 | | % % |
4 | | % % |
5 | | % % |
6 | | % M M EEEEE TTTTT AAA % |
7 | | % MM MM E T A A % |
8 | | % M M M EEE T AAAAA % |
9 | | % M M E T A A % |
10 | | % M M EEEEE T A A % |
11 | | % % |
12 | | % % |
13 | | % Read/Write Embedded Image Profiles. % |
14 | | % % |
15 | | % Software Design % |
16 | | % William Radcliffe % |
17 | | % July 2001 % |
18 | | % % |
19 | | % % |
20 | | % Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization % |
21 | | % dedicated to making software imaging solutions freely available. % |
22 | | % % |
23 | | % You may not use this file except in compliance with the License. You may % |
24 | | % obtain a copy of the License at % |
25 | | % % |
26 | | % https://imagemagick.org/license/ % |
27 | | % % |
28 | | % Unless required by applicable law or agreed to in writing, software % |
29 | | % distributed under the License is distributed on an "AS IS" BASIS, % |
30 | | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % |
31 | | % See the License for the specific language governing permissions and % |
32 | | % limitations under the License. % |
33 | | % % |
34 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
35 | | % |
36 | | % |
37 | | */ |
38 | | |
39 | | /* |
40 | | Include declarations. |
41 | | */ |
42 | | #include "MagickCore/studio.h" |
43 | | #include "MagickCore/blob.h" |
44 | | #include "MagickCore/blob-private.h" |
45 | | #include "MagickCore/channel.h" |
46 | | #include "MagickCore/exception.h" |
47 | | #include "MagickCore/exception-private.h" |
48 | | #include "MagickCore/image.h" |
49 | | #include "MagickCore/image-private.h" |
50 | | #include "MagickCore/list.h" |
51 | | #include "MagickCore/locale-private.h" |
52 | | #include "MagickCore/magick.h" |
53 | | #include "MagickCore/memory_.h" |
54 | | #include "MagickCore/module.h" |
55 | | #include "MagickCore/profile-private.h" |
56 | | #include "MagickCore/splay-tree.h" |
57 | | #include "MagickCore/quantum-private.h" |
58 | | #include "MagickCore/static.h" |
59 | | #include "MagickCore/string_.h" |
60 | | #include "MagickCore/string-private.h" |
61 | | #include "MagickCore/token.h" |
62 | | #include "MagickCore/utility.h" |
63 | | |
64 | | /* |
65 | | Forward declarations. |
66 | | */ |
67 | | static MagickBooleanType |
68 | | WriteMETAImage(const ImageInfo *,Image *,ExceptionInfo *); |
69 | | |
70 | | /* |
71 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
72 | | % % |
73 | | % % |
74 | | % % |
75 | | % I s M E T A % |
76 | | % % |
77 | | % % |
78 | | % % |
79 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
80 | | % |
81 | | % IsMETA() returns MagickTrue if the image format type, identified by the |
82 | | % magick string, is META. |
83 | | % |
84 | | % The format of the IsMETA method is: |
85 | | % |
86 | | % MagickBooleanType IsMETA(const unsigned char *magick,const size_t length) |
87 | | % |
88 | | % A description of each parameter follows: |
89 | | % |
90 | | % o magick: compare image format pattern against these bytes. |
91 | | % |
92 | | % o length: Specifies the length of the magick string. |
93 | | % |
94 | | % |
95 | | */ |
96 | | #ifdef IMPLEMENT_IS_FUNCTION |
97 | | static MagickBooleanType IsMETA(const unsigned char *magick,const size_t length) |
98 | | { |
99 | | if (length < 4) |
100 | | return(MagickFalse); |
101 | | if (LocaleNCompare((char *) magick,"8BIM",4) == 0) |
102 | | return(MagickTrue); |
103 | | if (LocaleNCompare((char *) magick,"APP1",4) == 0) |
104 | | return(MagickTrue); |
105 | | if (LocaleNCompare((char *) magick,"\034\002",2) == 0) |
106 | | return(MagickTrue); |
107 | | return(MagickFalse); |
108 | | } |
109 | | #endif |
110 | | |
111 | | /* |
112 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
113 | | % % |
114 | | % % |
115 | | % % |
116 | | % R e a d M E T A I m a g e % |
117 | | % % |
118 | | % % |
119 | | % % |
120 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
121 | | % |
122 | | % ReadMETAImage() reads a META image file and returns it. It |
123 | | % allocates the memory necessary for the new Image structure and returns a |
124 | | % pointer to the new image. |
125 | | % |
126 | | % The format of the ReadMETAImage method is: |
127 | | % |
128 | | % Image *ReadMETAImage(const ImageInfo *image_info, |
129 | | % ExceptionInfo *exception) |
130 | | % |
131 | | % Decompression code contributed by Kyle Shorter. |
132 | | % |
133 | | % A description of each parameter follows: |
134 | | % |
135 | | % o image: Method ReadMETAImage returns a pointer to the image after |
136 | | % reading. A null image is returned if there is a memory shortage or |
137 | | % if the image cannot be read. |
138 | | % |
139 | | % o image_info: Specifies a pointer to an ImageInfo structure. |
140 | | % |
141 | | % o exception: return any errors or warnings in this structure. |
142 | | % |
143 | | */ |
144 | | |
145 | | static const struct |
146 | | { |
147 | | const unsigned char |
148 | | len; |
149 | | |
150 | | const char |
151 | | code[7], |
152 | | val; |
153 | | } html_codes[] = { |
154 | | #ifdef HANDLE_GT_LT |
155 | | { 4,"<",'<' }, |
156 | | { 4,">",'>' }, |
157 | | #endif |
158 | | { 5,"&",'&' }, |
159 | | { 6,""",'"' }, |
160 | | { 6,"'",'\''} |
161 | | }; |
162 | | |
163 | | static int stringnicmp(const char *p,const char *q,size_t n) |
164 | 2.84k | { |
165 | 2.84k | ssize_t |
166 | 2.84k | i, |
167 | 2.84k | j; |
168 | | |
169 | 2.84k | if (p == q) |
170 | 0 | return(0); |
171 | 2.84k | if (p == (char *) NULL) |
172 | 0 | return(-1); |
173 | 2.84k | if (q == (char *) NULL) |
174 | 0 | return(1); |
175 | 5.70k | while ((*p != '\0') && (*q != '\0')) |
176 | 5.70k | { |
177 | 5.70k | if ((*p == '\0') || (*q == '\0')) |
178 | 0 | break; |
179 | 5.70k | i=(*p); |
180 | 5.70k | if (islower((int) ((unsigned char) i)) != 0) |
181 | 101 | i=LocaleToUppercase((int) i); |
182 | 5.70k | j=(*q); |
183 | 5.70k | if (islower((int) ((unsigned char) j)) != 0) |
184 | 2.85k | j=LocaleToUppercase((int) j); |
185 | 5.70k | if (i != j) |
186 | 2.84k | break; |
187 | 2.85k | n--; |
188 | 2.85k | if (n == 0) |
189 | 0 | break; |
190 | 2.85k | p++; |
191 | 2.85k | q++; |
192 | 2.85k | } |
193 | 2.84k | return(LocaleToUppercase((int) *p)-LocaleToUppercase((int) *q)); |
194 | 2.84k | } |
195 | | |
196 | | static size_t convertHTMLcodes(char *s) |
197 | 7.24k | { |
198 | 7.24k | int |
199 | 7.24k | value; |
200 | | |
201 | 7.24k | size_t |
202 | 7.24k | i; |
203 | | |
204 | 7.24k | size_t |
205 | 7.24k | length; |
206 | | |
207 | 7.24k | length=0; |
208 | 40.1k | for (i=0; (i < 7U) && (s[i] != '\0'); i++) |
209 | 37.1k | if (s[i] == ';') |
210 | 4.27k | { |
211 | 4.27k | length=i+1; |
212 | 4.27k | break; |
213 | 4.27k | } |
214 | 7.24k | if ((length == 0) || (s == (char *) NULL) || (*s == '\0')) |
215 | 2.97k | return(0); |
216 | 4.27k | if ((length > 3) && (s[1] == '#') && (MagickSscanf(s,"&#%d;",&value) == 1)) |
217 | 92 | { |
218 | 92 | size_t |
219 | 92 | o; |
220 | | |
221 | 92 | o=3; |
222 | 188 | while (s[o] != ';') |
223 | 143 | { |
224 | 143 | o++; |
225 | 143 | if (o > 5) |
226 | 47 | break; |
227 | 143 | } |
228 | 92 | if (o < 6) |
229 | 45 | (void) memmove(s+1,s+1+o,strlen(s+1+o)+1); |
230 | 92 | *s=(char) value; |
231 | 92 | return(o); |
232 | 92 | } |
233 | 16.7k | for (i=0; i < (ssize_t) (sizeof(html_codes)/sizeof(html_codes[0])); i++) |
234 | 12.5k | { |
235 | 12.5k | if (html_codes[i].len <= (ssize_t) length) |
236 | 2.84k | if (stringnicmp(s,html_codes[i].code,(size_t) (html_codes[i].len)) == 0) |
237 | 0 | { |
238 | 0 | (void) memmove(s+1,s+html_codes[i].len,strlen(s+html_codes[i].len)+1); |
239 | 0 | *s=html_codes[i].val; |
240 | 0 | return(html_codes[i].len-1); |
241 | 0 | } |
242 | 12.5k | } |
243 | 4.17k | return(0); |
244 | 4.17k | } |
245 | | |
246 | | static char *super_fgets(char **b, size_t *blen, Image *file) |
247 | 0 | { |
248 | 0 | int |
249 | 0 | c; |
250 | |
|
251 | 0 | size_t |
252 | 0 | len; |
253 | |
|
254 | 0 | unsigned char |
255 | 0 | *p, |
256 | 0 | *q; |
257 | |
|
258 | 0 | len=*blen; |
259 | 0 | p=(unsigned char *) (*b); |
260 | 0 | for (q=p; ; q++) |
261 | 0 | { |
262 | 0 | c=ReadBlobByte(file); |
263 | 0 | if (c == EOF || c == '\n') |
264 | 0 | break; |
265 | 0 | if ((size_t) (q-p+1) >= len) |
266 | 0 | { |
267 | 0 | size_t |
268 | 0 | tlen; |
269 | |
|
270 | 0 | unsigned char |
271 | 0 | *buffer; |
272 | |
|
273 | 0 | tlen=(size_t) (q-p); |
274 | 0 | len<<=1; |
275 | 0 | buffer=(unsigned char *) ResizeQuantumMemory(p,len+2UL,sizeof(*p)); |
276 | 0 | p=(unsigned char *) NULL; |
277 | 0 | if (buffer == (unsigned char *) NULL) |
278 | 0 | break; |
279 | 0 | p=buffer; |
280 | 0 | q=p+tlen; |
281 | 0 | } |
282 | 0 | *q=(unsigned char) c; |
283 | 0 | } |
284 | 0 | *b=(char *) p; |
285 | 0 | *blen=0; |
286 | 0 | if (p != (unsigned char *) NULL) |
287 | 0 | { |
288 | 0 | size_t |
289 | 0 | tlen; |
290 | |
|
291 | 0 | tlen=(size_t) (q-p); |
292 | 0 | if (tlen == 0) |
293 | 0 | return (char *) NULL; |
294 | 0 | p[tlen] = '\0'; |
295 | 0 | *blen=++tlen; |
296 | 0 | } |
297 | 0 | return(*b); |
298 | 0 | } |
299 | | |
300 | 415 | #define IPTC_ID 1028 |
301 | 0 | #define THUMBNAIL_ID 1033 |
302 | | |
303 | | static ssize_t parse8BIM(Image *ifile, Image *ofile) |
304 | 0 | { |
305 | 0 | char |
306 | 0 | brkused, |
307 | 0 | quoted, |
308 | 0 | *line, |
309 | 0 | *token, |
310 | 0 | *newstr, |
311 | 0 | *name; |
312 | |
|
313 | 0 | int |
314 | 0 | state, |
315 | 0 | next; |
316 | |
|
317 | 0 | MagickBooleanType |
318 | 0 | status; |
319 | |
|
320 | 0 | MagickOffsetType |
321 | 0 | savedpos, |
322 | 0 | currentpos; |
323 | |
|
324 | 0 | size_t |
325 | 0 | inputlen = MagickPathExtent; |
326 | |
|
327 | 0 | ssize_t |
328 | 0 | savedolen = 0L, |
329 | 0 | outputlen = 0L; |
330 | |
|
331 | 0 | TokenInfo |
332 | 0 | *token_info; |
333 | |
|
334 | 0 | unsigned char |
335 | 0 | dataset; |
336 | |
|
337 | 0 | unsigned int |
338 | 0 | recnum; |
339 | |
|
340 | 0 | dataset = 0; |
341 | 0 | recnum = 0; |
342 | 0 | line = (char *) AcquireQuantumMemory(inputlen,sizeof(*line)); |
343 | 0 | if (line == (char *) NULL) |
344 | 0 | return(-1); |
345 | 0 | newstr = name = token = (char *) NULL; |
346 | 0 | savedpos = 0; |
347 | 0 | status=MagickTrue; |
348 | 0 | token_info=AcquireTokenInfo(); |
349 | 0 | while (super_fgets(&line,&inputlen,ifile)!=NULL) |
350 | 0 | { |
351 | 0 | state=0; |
352 | 0 | next=0; |
353 | |
|
354 | 0 | token=(char *) AcquireQuantumMemory(inputlen,sizeof(*token)); |
355 | 0 | if (token == (char *) NULL) |
356 | 0 | break; |
357 | 0 | newstr=(char *) AcquireQuantumMemory(inputlen,sizeof(*newstr)); |
358 | 0 | if (newstr == (char *) NULL) |
359 | 0 | break; |
360 | 0 | while (Tokenizer(token_info,0,token,inputlen,line,"","=","\"",0, |
361 | 0 | &brkused,&next,"ed)==0) |
362 | 0 | { |
363 | 0 | if (state == 0) |
364 | 0 | { |
365 | 0 | int |
366 | 0 | s, |
367 | 0 | n; |
368 | |
|
369 | 0 | s=0; |
370 | 0 | n=0; |
371 | 0 | while (Tokenizer(token_info,0,newstr,inputlen,token,"","#", |
372 | 0 | "", 0,&brkused,&n,"ed)==0) |
373 | 0 | { |
374 | 0 | switch (s) |
375 | 0 | { |
376 | 0 | case 0: |
377 | 0 | if (strcmp(newstr,"8BIM")==0) |
378 | 0 | dataset = 255; |
379 | 0 | else |
380 | 0 | dataset = (unsigned char) StringToLong(newstr); |
381 | 0 | break; |
382 | 0 | case 1: |
383 | 0 | recnum = (unsigned int) StringToUnsignedLong(newstr); |
384 | 0 | break; |
385 | 0 | case 2: |
386 | 0 | { |
387 | 0 | size_t extent = strlen(newstr)+MagickPathExtent; |
388 | 0 | name=(char *) AcquireQuantumMemory(extent,sizeof(*name)); |
389 | 0 | if (name != (char *) NULL) |
390 | 0 | (void) CopyMagickString(name,newstr,extent); |
391 | 0 | break; |
392 | 0 | } |
393 | 0 | } |
394 | 0 | s++; |
395 | 0 | } |
396 | 0 | } |
397 | 0 | else |
398 | 0 | if (state == 1) |
399 | 0 | { |
400 | 0 | int |
401 | 0 | n; |
402 | |
|
403 | 0 | ssize_t |
404 | 0 | len; |
405 | |
|
406 | 0 | n=0; |
407 | 0 | len = (ssize_t) strlen(token); |
408 | 0 | while (Tokenizer(token_info,0,newstr,inputlen,token,"","&", |
409 | 0 | "",0,&brkused,&n,"ed)==0) |
410 | 0 | { |
411 | 0 | if (brkused && n > 0) |
412 | 0 | { |
413 | 0 | size_t |
414 | 0 | codes_length; |
415 | |
|
416 | 0 | char |
417 | 0 | *s = &token[n-1]; |
418 | |
|
419 | 0 | codes_length=convertHTMLcodes(s); |
420 | 0 | if ((ssize_t) codes_length > len) |
421 | 0 | len=0; |
422 | 0 | else |
423 | 0 | len-=(ssize_t) codes_length; |
424 | 0 | } |
425 | 0 | } |
426 | |
|
427 | 0 | if (dataset == 255) |
428 | 0 | { |
429 | 0 | unsigned char |
430 | 0 | nlen = 0; |
431 | |
|
432 | 0 | int |
433 | 0 | i; |
434 | |
|
435 | 0 | if (savedolen > 0) |
436 | 0 | { |
437 | 0 | MagickOffsetType |
438 | 0 | offset; |
439 | |
|
440 | 0 | ssize_t diff = outputlen - savedolen; |
441 | 0 | currentpos = TellBlob(ofile); |
442 | 0 | if (currentpos < 0) |
443 | 0 | { |
444 | 0 | status=MagickFalse; |
445 | 0 | break; |
446 | 0 | } |
447 | 0 | offset=SeekBlob(ofile,savedpos,SEEK_SET); |
448 | 0 | if (offset < 0) |
449 | 0 | { |
450 | 0 | status=MagickFalse; |
451 | 0 | break; |
452 | 0 | } |
453 | 0 | (void) WriteBlobMSBLong(ofile,(unsigned int) diff); |
454 | 0 | offset=SeekBlob(ofile,currentpos,SEEK_SET); |
455 | 0 | if (offset < 0) |
456 | 0 | { |
457 | 0 | status=MagickFalse; |
458 | 0 | break; |
459 | 0 | } |
460 | 0 | savedolen = 0L; |
461 | 0 | } |
462 | 0 | if (outputlen & 1) |
463 | 0 | { |
464 | 0 | (void) WriteBlobByte(ofile,0x00); |
465 | 0 | outputlen++; |
466 | 0 | } |
467 | 0 | (void) WriteBlobString(ofile,"8BIM"); |
468 | 0 | (void) WriteBlobMSBShort(ofile,(unsigned short) recnum); |
469 | 0 | outputlen += 6; |
470 | 0 | if (name) |
471 | 0 | nlen = (unsigned char) strlen(name); |
472 | 0 | (void) WriteBlobByte(ofile,nlen); |
473 | 0 | outputlen++; |
474 | 0 | for (i=0; i<nlen; i++) |
475 | 0 | (void) WriteBlobByte(ofile,(unsigned char) name[i]); |
476 | 0 | outputlen += nlen; |
477 | 0 | if ((nlen & 0x01) == 0) |
478 | 0 | { |
479 | 0 | (void) WriteBlobByte(ofile,0x00); |
480 | 0 | outputlen++; |
481 | 0 | } |
482 | 0 | if (recnum != IPTC_ID) |
483 | 0 | { |
484 | 0 | (void) WriteBlobMSBLong(ofile, (unsigned int) len); |
485 | 0 | outputlen += 4; |
486 | |
|
487 | 0 | n=0; |
488 | 0 | outputlen += len; |
489 | 0 | while (len-- > 0) |
490 | 0 | (void) WriteBlobByte(ofile,(unsigned char) token[n++]); |
491 | |
|
492 | 0 | if (outputlen & 1) |
493 | 0 | { |
494 | 0 | (void) WriteBlobByte(ofile,0x00); |
495 | 0 | outputlen++; |
496 | 0 | } |
497 | 0 | } |
498 | 0 | else |
499 | 0 | { |
500 | | /* patch in a fake length for now and fix it later */ |
501 | 0 | savedpos = TellBlob(ofile); |
502 | 0 | if (savedpos < 0) |
503 | 0 | { |
504 | 0 | status=MagickFalse; |
505 | 0 | break; |
506 | 0 | } |
507 | 0 | (void) WriteBlobMSBLong(ofile,0xFFFFFFFFU); |
508 | 0 | outputlen += 4; |
509 | 0 | savedolen = outputlen; |
510 | 0 | } |
511 | 0 | } |
512 | 0 | else |
513 | 0 | { |
514 | 0 | if (len <= 0x7FFF) |
515 | 0 | { |
516 | 0 | (void) WriteBlobByte(ofile,0x1c); |
517 | 0 | (void) WriteBlobByte(ofile,(unsigned char) dataset); |
518 | 0 | (void) WriteBlobByte(ofile,(unsigned char) (recnum & 0xff)); |
519 | 0 | (void) WriteBlobMSBShort(ofile,(unsigned short) len); |
520 | 0 | outputlen += 5; |
521 | 0 | n=0; |
522 | 0 | outputlen += len; |
523 | 0 | while (len-- > 0) |
524 | 0 | (void) WriteBlobByte(ofile,(unsigned char) token[n++]); |
525 | 0 | } |
526 | 0 | } |
527 | 0 | } |
528 | 0 | state++; |
529 | 0 | } |
530 | 0 | if (token != (char *) NULL) |
531 | 0 | token=DestroyString(token); |
532 | 0 | if (newstr != (char *) NULL) |
533 | 0 | newstr=DestroyString(newstr); |
534 | 0 | if (name != (char *) NULL) |
535 | 0 | name=DestroyString(name); |
536 | 0 | if (status == MagickFalse) |
537 | 0 | break; |
538 | 0 | } |
539 | 0 | token_info=DestroyTokenInfo(token_info); |
540 | 0 | if (token != (char *) NULL) |
541 | 0 | token=DestroyString(token); |
542 | 0 | if (newstr != (char *) NULL) |
543 | 0 | newstr=DestroyString(newstr); |
544 | 0 | if (name != (char *) NULL) |
545 | 0 | name=DestroyString(name); |
546 | 0 | line=DestroyString(line); |
547 | 0 | if (savedolen > 0) |
548 | 0 | { |
549 | 0 | MagickOffsetType |
550 | 0 | offset; |
551 | |
|
552 | 0 | ssize_t diff = outputlen - savedolen; |
553 | |
|
554 | 0 | currentpos = TellBlob(ofile); |
555 | 0 | if (currentpos < 0) |
556 | 0 | return(-1); |
557 | 0 | offset=SeekBlob(ofile,savedpos,SEEK_SET); |
558 | 0 | if (offset < 0) |
559 | 0 | return(-1); |
560 | 0 | (void) WriteBlobMSBLong(ofile,(unsigned int) diff); |
561 | 0 | offset=SeekBlob(ofile,currentpos,SEEK_SET); |
562 | 0 | if (offset < 0) |
563 | 0 | return(-1); |
564 | 0 | savedolen = 0L; |
565 | 0 | } |
566 | 0 | return(status == MagickFalse ? -1 : outputlen); |
567 | 0 | } |
568 | | |
569 | | static char *super_fgets_w(char **b, size_t *blen, Image *file) |
570 | 3.48k | { |
571 | 3.48k | int |
572 | 3.48k | c; |
573 | | |
574 | 3.48k | size_t |
575 | 3.48k | len; |
576 | | |
577 | 3.48k | unsigned char |
578 | 3.48k | *p, |
579 | 3.48k | *q; |
580 | | |
581 | 3.48k | len=*blen; |
582 | 3.48k | p=(unsigned char *) (*b); |
583 | 68.1k | for (q=p; ; q++) |
584 | 71.6k | { |
585 | 71.6k | c=ReadBlobLSBSignedShort(file); |
586 | 71.6k | if ((c == -1) || (c == '\n')) |
587 | 3.20k | break; |
588 | 68.4k | if (EOFBlob(file)) |
589 | 283 | break; |
590 | 68.1k | if ((size_t) (q-p+1) >= len) |
591 | 2.10k | { |
592 | 2.10k | size_t |
593 | 2.10k | tlen; |
594 | | |
595 | 2.10k | unsigned char |
596 | 2.10k | *buffer; |
597 | | |
598 | 2.10k | tlen=(size_t) (q-p); |
599 | 2.10k | len<<=1; |
600 | 2.10k | buffer=(unsigned char *) ResizeQuantumMemory(p,len+2,sizeof(*p)); |
601 | 2.10k | p=(unsigned char *) NULL; |
602 | 2.10k | if (buffer == (unsigned char *) NULL) |
603 | 0 | break; |
604 | 2.10k | p=buffer; |
605 | 2.10k | q=p+tlen; |
606 | 2.10k | } |
607 | 68.1k | *q=(unsigned char) c; |
608 | 68.1k | } |
609 | 3.48k | *b=(char *) p; |
610 | 3.48k | *blen=0; |
611 | 3.48k | if (p != (unsigned char *) NULL) |
612 | 3.48k | { |
613 | 3.48k | size_t |
614 | 3.48k | tlen; |
615 | | |
616 | 3.48k | tlen=(size_t) (q-p); |
617 | 3.48k | if (tlen == 0) |
618 | 149 | return (char *) NULL; |
619 | 3.33k | p[tlen]='\0'; |
620 | 3.33k | *blen=++tlen; |
621 | 3.33k | } |
622 | 3.33k | return(*b); |
623 | 3.48k | } |
624 | | |
625 | | static ssize_t parse8BIMW(Image *ifile, Image *ofile) |
626 | 149 | { |
627 | 149 | char |
628 | 149 | brkused, |
629 | 149 | quoted, |
630 | 149 | *line, |
631 | 149 | *token, |
632 | 149 | *newstr, |
633 | 149 | *name; |
634 | | |
635 | 149 | int |
636 | 149 | state, |
637 | 149 | next; |
638 | | |
639 | 149 | unsigned char |
640 | 149 | dataset; |
641 | | |
642 | 149 | unsigned int |
643 | 149 | recnum; |
644 | | |
645 | 149 | size_t |
646 | 149 | inputlen = MagickPathExtent; |
647 | | |
648 | 149 | ssize_t |
649 | 149 | savedolen = 0L, |
650 | 149 | outputlen = 0L; |
651 | | |
652 | 149 | MagickBooleanType |
653 | 149 | status; |
654 | | |
655 | 149 | MagickOffsetType |
656 | 149 | savedpos, |
657 | 149 | currentpos; |
658 | | |
659 | 149 | TokenInfo |
660 | 149 | *token_info; |
661 | | |
662 | 149 | dataset = 0; |
663 | 149 | recnum = 0; |
664 | 149 | line=(char *) AcquireQuantumMemory(inputlen,sizeof(*line)); |
665 | 149 | if (line == (char *) NULL) |
666 | 0 | return(-1); |
667 | 149 | newstr = name = token = (char *) NULL; |
668 | 149 | savedpos = 0; |
669 | 149 | token_info=AcquireTokenInfo(); |
670 | 149 | status=MagickTrue; |
671 | 3.48k | while (super_fgets_w(&line,&inputlen,ifile) != NULL) |
672 | 3.33k | { |
673 | 3.33k | state=0; |
674 | 3.33k | next=0; |
675 | | |
676 | 3.33k | token=(char *) AcquireQuantumMemory(inputlen,sizeof(*token)); |
677 | 3.33k | if (token == (char *) NULL) |
678 | 0 | break; |
679 | 3.33k | newstr=(char *) AcquireQuantumMemory(inputlen,sizeof(*newstr)); |
680 | 3.33k | if (newstr == (char *) NULL) |
681 | 0 | break; |
682 | 9.90k | while (Tokenizer(token_info,0,token,inputlen,line,"","=","\"",0, |
683 | 9.90k | &brkused,&next,"ed)==0) |
684 | 6.57k | { |
685 | 6.57k | if (state == 0) |
686 | 3.22k | { |
687 | 3.22k | int |
688 | 3.22k | s, |
689 | 3.22k | n; |
690 | | |
691 | 3.22k | s=0; |
692 | 3.22k | n=0; |
693 | 7.48k | while (Tokenizer(token_info,0,newstr,inputlen,token,"","#", |
694 | 7.48k | "",0,&brkused,&n,"ed)==0) |
695 | 4.26k | { |
696 | 4.26k | switch (s) |
697 | 4.26k | { |
698 | 2.62k | case 0: |
699 | 2.62k | if (strcmp(newstr,"8BIM")==0) |
700 | 340 | dataset = 255; |
701 | 2.28k | else |
702 | 2.28k | dataset = (unsigned char) StringToLong(newstr); |
703 | 2.62k | break; |
704 | 681 | case 1: |
705 | 681 | recnum=(unsigned int) StringToUnsignedLong(newstr); |
706 | 681 | break; |
707 | 538 | case 2: |
708 | 538 | name=(char *) AcquireQuantumMemory(strlen(newstr)+MagickPathExtent, |
709 | 538 | sizeof(*name)); |
710 | 538 | if (name) |
711 | 538 | (void) CopyMagickString(name,newstr,strlen(newstr)+MagickPathExtent); |
712 | 538 | break; |
713 | 4.26k | } |
714 | 4.26k | s++; |
715 | 4.26k | } |
716 | 3.22k | } |
717 | 3.34k | else |
718 | 3.34k | if (state == 1) |
719 | 1.49k | { |
720 | 1.49k | int |
721 | 1.49k | n; |
722 | | |
723 | 1.49k | ssize_t |
724 | 1.49k | len; |
725 | | |
726 | 1.49k | n=0; |
727 | 1.49k | len = (ssize_t) strlen(token); |
728 | 9.53k | while (Tokenizer(token_info,0,newstr,inputlen,token,"","&", |
729 | 9.53k | "",0,&brkused,&n,"ed)==0) |
730 | 8.03k | { |
731 | 8.03k | if (brkused && n > 0) |
732 | 7.24k | { |
733 | 7.24k | size_t |
734 | 7.24k | codes_length; |
735 | | |
736 | 7.24k | char |
737 | 7.24k | *s = &token[n-1]; |
738 | | |
739 | 7.24k | codes_length=convertHTMLcodes(s); |
740 | 7.24k | if ((ssize_t) codes_length > len) |
741 | 0 | len=0; |
742 | 7.24k | else |
743 | 7.24k | len-=(ssize_t) codes_length; |
744 | 7.24k | } |
745 | 8.03k | } |
746 | | |
747 | 1.49k | if (dataset == 255) |
748 | 415 | { |
749 | 415 | unsigned char |
750 | 415 | nlen = 0; |
751 | | |
752 | 415 | int |
753 | 415 | i; |
754 | | |
755 | 415 | if (savedolen > 0) |
756 | 0 | { |
757 | 0 | MagickOffsetType |
758 | 0 | offset; |
759 | |
|
760 | 0 | ssize_t |
761 | 0 | diff = outputlen - savedolen; |
762 | |
|
763 | 0 | currentpos = TellBlob(ofile); |
764 | 0 | if (currentpos < 0) |
765 | 0 | { |
766 | 0 | status=MagickFalse; |
767 | 0 | break; |
768 | 0 | } |
769 | 0 | offset=SeekBlob(ofile,savedpos,SEEK_SET); |
770 | 0 | if (offset < 0) |
771 | 0 | { |
772 | 0 | status=MagickFalse; |
773 | 0 | break; |
774 | 0 | } |
775 | 0 | (void) WriteBlobMSBLong(ofile,(unsigned int) diff); |
776 | 0 | offset=SeekBlob(ofile,currentpos,SEEK_SET); |
777 | 0 | if (offset < 0) |
778 | 0 | { |
779 | 0 | status=MagickFalse; |
780 | 0 | break; |
781 | 0 | } |
782 | 0 | savedolen = 0L; |
783 | 0 | } |
784 | 415 | if (outputlen & 1) |
785 | 67 | { |
786 | 67 | (void) WriteBlobByte(ofile,0x00); |
787 | 67 | outputlen++; |
788 | 67 | } |
789 | 415 | (void) WriteBlobString(ofile,"8BIM"); |
790 | 415 | (void) WriteBlobMSBShort(ofile,(unsigned short) recnum); |
791 | 415 | outputlen += 6; |
792 | 415 | if (name) |
793 | 90 | nlen = (unsigned char) strlen(name); |
794 | 415 | (void) WriteBlobByte(ofile,(unsigned char) nlen); |
795 | 415 | outputlen++; |
796 | 1.32k | for (i=0; i<nlen; i++) |
797 | 912 | (void) WriteBlobByte(ofile,(unsigned char) name[i]); |
798 | 415 | outputlen += nlen; |
799 | 415 | if ((nlen & 0x01) == 0) |
800 | 329 | { |
801 | 329 | (void) WriteBlobByte(ofile,0x00); |
802 | 329 | outputlen++; |
803 | 329 | } |
804 | 415 | if (recnum != IPTC_ID) |
805 | 415 | { |
806 | 415 | (void) WriteBlobMSBLong(ofile,(unsigned int) len); |
807 | 415 | outputlen += 4; |
808 | | |
809 | 415 | n=0; |
810 | 415 | outputlen += len; |
811 | 19.2k | while (len-- > 0) |
812 | 18.8k | (void) WriteBlobByte(ofile,(unsigned char) token[n++]); |
813 | | |
814 | 415 | if (outputlen & 1) |
815 | 126 | { |
816 | 126 | (void) WriteBlobByte(ofile,0x00); |
817 | 126 | outputlen++; |
818 | 126 | } |
819 | 415 | } |
820 | 0 | else |
821 | 0 | { |
822 | | /* patch in a fake length for now and fix it later */ |
823 | 0 | savedpos = TellBlob(ofile); |
824 | 0 | if (savedpos < 0) |
825 | 0 | { |
826 | 0 | status=MagickFalse; |
827 | 0 | break; |
828 | 0 | } |
829 | 0 | (void) WriteBlobMSBLong(ofile,0xFFFFFFFFU); |
830 | 0 | outputlen += 4; |
831 | 0 | savedolen = outputlen; |
832 | 0 | } |
833 | 415 | } |
834 | 1.08k | else |
835 | 1.08k | { |
836 | 1.08k | if (len <= 0x7FFF) |
837 | 1.08k | { |
838 | 1.08k | (void) WriteBlobByte(ofile,0x1c); |
839 | 1.08k | (void) WriteBlobByte(ofile,dataset); |
840 | 1.08k | (void) WriteBlobByte(ofile,(unsigned char) (recnum & 0xff)); |
841 | 1.08k | (void) WriteBlobMSBShort(ofile,(unsigned short) len); |
842 | 1.08k | outputlen += 5; |
843 | 1.08k | n=0; |
844 | 1.08k | outputlen += len; |
845 | 2.64k | while (len-- > 0) |
846 | 1.55k | (void) WriteBlobByte(ofile,(unsigned char) token[n++]); |
847 | 1.08k | } |
848 | 1.08k | } |
849 | 1.49k | } |
850 | 6.57k | state++; |
851 | 6.57k | } |
852 | 3.33k | if (token != (char *) NULL) |
853 | 3.33k | token=DestroyString(token); |
854 | 3.33k | if (newstr != (char *) NULL) |
855 | 3.33k | newstr=DestroyString(newstr); |
856 | 3.33k | if (name != (char *) NULL) |
857 | 538 | name=DestroyString(name); |
858 | 3.33k | if (status == MagickFalse) |
859 | 0 | break; |
860 | 3.33k | } |
861 | 149 | token_info=DestroyTokenInfo(token_info); |
862 | 149 | if (token != (char *) NULL) |
863 | 0 | token=DestroyString(token); |
864 | 149 | if (newstr != (char *) NULL) |
865 | 0 | newstr=DestroyString(newstr); |
866 | 149 | if (name != (char *) NULL) |
867 | 0 | name=DestroyString(name); |
868 | 149 | line=DestroyString(line); |
869 | 149 | if (savedolen > 0) |
870 | 0 | { |
871 | 0 | MagickOffsetType |
872 | 0 | offset; |
873 | |
|
874 | 0 | ssize_t diff = outputlen - savedolen; |
875 | |
|
876 | 0 | currentpos = TellBlob(ofile); |
877 | 0 | if (currentpos < 0) |
878 | 0 | return(-1); |
879 | 0 | offset=SeekBlob(ofile,savedpos,SEEK_SET); |
880 | 0 | if (offset < 0) |
881 | 0 | return(-1); |
882 | 0 | (void) WriteBlobMSBLong(ofile,(unsigned int) diff); |
883 | 0 | offset=SeekBlob(ofile,currentpos,SEEK_SET); |
884 | 0 | if (offset < 0) |
885 | 0 | return(-1); |
886 | 0 | savedolen = 0L; |
887 | 0 | } |
888 | 149 | return(status == MagickFalse ? -1 : outputlen); |
889 | 149 | } |
890 | | |
891 | | /* some defines for the different JPEG block types */ |
892 | | #define M_SOF0 0xC0 /* Start Of Frame N */ |
893 | | #define M_SOF1 0xC1 /* N indicates which compression process */ |
894 | | #define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */ |
895 | | #define M_SOF3 0xC3 |
896 | | #define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */ |
897 | | #define M_SOF6 0xC6 |
898 | | #define M_SOF7 0xC7 |
899 | | #define M_SOF9 0xC9 |
900 | | #define M_SOF10 0xCA |
901 | | #define M_SOF11 0xCB |
902 | | #define M_SOF13 0xCD |
903 | | #define M_SOF14 0xCE |
904 | | #define M_SOF15 0xCF |
905 | 0 | #define M_SOI 0xD8 |
906 | 0 | #define M_EOI 0xD9 /* End Of Image (end of datastream) */ |
907 | 0 | #define M_SOS 0xDA /* Start Of Scan (begins compressed data) */ |
908 | 0 | #define M_APP0 0xe0 |
909 | | #define M_APP1 0xe1 |
910 | | #define M_APP2 0xe2 |
911 | | #define M_APP3 0xe3 |
912 | | #define M_APP4 0xe4 |
913 | | #define M_APP5 0xe5 |
914 | | #define M_APP6 0xe6 |
915 | | #define M_APP7 0xe7 |
916 | | #define M_APP8 0xe8 |
917 | | #define M_APP9 0xe9 |
918 | | #define M_APP10 0xea |
919 | | #define M_APP11 0xeb |
920 | | #define M_APP12 0xec |
921 | 0 | #define M_APP13 0xed |
922 | | #define M_APP14 0xee |
923 | | #define M_APP15 0xef |
924 | | |
925 | | static int jpeg_transfer_1(Image *ifile, Image *ofile) |
926 | 0 | { |
927 | 0 | int c; |
928 | |
|
929 | 0 | c = ReadBlobByte(ifile); |
930 | 0 | if (c == EOF) |
931 | 0 | return EOF; |
932 | 0 | (void) WriteBlobByte(ofile,(unsigned char) c); |
933 | 0 | return c; |
934 | 0 | } |
935 | | |
936 | | #if defined(future) |
937 | | static int jpeg_skip_1(Image *ifile) |
938 | | { |
939 | | int c; |
940 | | |
941 | | c = ReadBlobByte(ifile); |
942 | | if (c == EOF) |
943 | | return EOF; |
944 | | return c; |
945 | | } |
946 | | #endif |
947 | | |
948 | | static int jpeg_read_remaining(Image *ifile, Image *ofile) |
949 | 0 | { |
950 | 0 | int c; |
951 | |
|
952 | 0 | while ((c = jpeg_transfer_1(ifile, ofile)) != EOF) |
953 | 0 | continue; |
954 | 0 | return M_EOI; |
955 | 0 | } |
956 | | |
957 | | static int jpeg_skip_variable(Image *ifile, Image *ofile) |
958 | 0 | { |
959 | 0 | unsigned int length; |
960 | 0 | int c1,c2; |
961 | |
|
962 | 0 | if ((c1 = jpeg_transfer_1(ifile, ofile)) == EOF) |
963 | 0 | return M_EOI; |
964 | 0 | if ((c2 = jpeg_transfer_1(ifile, ofile)) == EOF) |
965 | 0 | return M_EOI; |
966 | | |
967 | 0 | length = (((unsigned int) c1) << 8) + ((unsigned int) c2); |
968 | 0 | length -= 2; |
969 | |
|
970 | 0 | while (length--) |
971 | 0 | if (jpeg_transfer_1(ifile, ofile) == EOF) |
972 | 0 | return M_EOI; |
973 | | |
974 | 0 | return 0; |
975 | 0 | } |
976 | | |
977 | | static int jpeg_skip_variable2(Image *ifile, Image *ofile) |
978 | 0 | { |
979 | 0 | unsigned int length; |
980 | 0 | int c1,c2; |
981 | |
|
982 | 0 | (void) ofile; |
983 | 0 | if ((c1 = ReadBlobByte(ifile)) == EOF) return M_EOI; |
984 | 0 | if ((c2 = ReadBlobByte(ifile)) == EOF) return M_EOI; |
985 | | |
986 | 0 | length = (((unsigned int) c1) << 8) + ((unsigned int) c2); |
987 | 0 | length -= 2; |
988 | |
|
989 | 0 | while (length--) |
990 | 0 | if (ReadBlobByte(ifile) == EOF) |
991 | 0 | return M_EOI; |
992 | | |
993 | 0 | return 0; |
994 | 0 | } |
995 | | |
996 | | static int jpeg_nextmarker(Image *ifile, Image *ofile) |
997 | 0 | { |
998 | 0 | int c; |
999 | | |
1000 | | /* transfer anything until we hit 0xff */ |
1001 | 0 | do |
1002 | 0 | { |
1003 | 0 | c = ReadBlobByte(ifile); |
1004 | 0 | if (c == EOF) |
1005 | 0 | return M_EOI; /* we hit EOF */ |
1006 | 0 | else |
1007 | 0 | if (c != 0xff) |
1008 | 0 | (void) WriteBlobByte(ofile,(unsigned char) c); |
1009 | 0 | } while (c != 0xff); |
1010 | | |
1011 | | /* get marker byte, swallowing possible padding */ |
1012 | 0 | do |
1013 | 0 | { |
1014 | 0 | c = ReadBlobByte(ifile); |
1015 | 0 | if (c == EOF) |
1016 | 0 | return M_EOI; /* we hit EOF */ |
1017 | 0 | } while (c == 0xff); |
1018 | | |
1019 | 0 | return c; |
1020 | 0 | } |
1021 | | |
1022 | | #if defined(future) |
1023 | | static int jpeg_skip_till_marker(Image *ifile, int marker) |
1024 | | { |
1025 | | int c, i; |
1026 | | |
1027 | | do |
1028 | | { |
1029 | | /* skip anything until we hit 0xff */ |
1030 | | i = 0; |
1031 | | do |
1032 | | { |
1033 | | c = ReadBlobByte(ifile); |
1034 | | i++; |
1035 | | if (c == EOF) |
1036 | | return M_EOI; /* we hit EOF */ |
1037 | | } while (c != 0xff); |
1038 | | |
1039 | | /* get marker byte, swallowing possible padding */ |
1040 | | do |
1041 | | { |
1042 | | c = ReadBlobByte(ifile); |
1043 | | if (c == EOF) |
1044 | | return M_EOI; /* we hit EOF */ |
1045 | | } while (c == 0xff); |
1046 | | } while (c != marker); |
1047 | | return c; |
1048 | | } |
1049 | | #endif |
1050 | | |
1051 | | /* Embed binary IPTC data into a JPEG image. */ |
1052 | | static int jpeg_embed(Image *ifile, Image *ofile, Image *iptc) |
1053 | 0 | { |
1054 | 0 | unsigned int marker; |
1055 | 0 | unsigned int done = 0; |
1056 | 0 | unsigned int len; |
1057 | 0 | int inx; |
1058 | |
|
1059 | 0 | if (jpeg_transfer_1(ifile, ofile) != 0xFF) |
1060 | 0 | return 0; |
1061 | 0 | if (jpeg_transfer_1(ifile, ofile) != M_SOI) |
1062 | 0 | return 0; |
1063 | | |
1064 | 0 | while (done == MagickFalse) |
1065 | 0 | { |
1066 | 0 | marker=(unsigned int) jpeg_nextmarker(ifile, ofile); |
1067 | 0 | if (marker == M_EOI) |
1068 | 0 | { /* EOF */ |
1069 | 0 | break; |
1070 | 0 | } |
1071 | 0 | else |
1072 | 0 | { |
1073 | 0 | if (marker != M_APP13) |
1074 | 0 | { |
1075 | 0 | (void) WriteBlobByte(ofile,0xff); |
1076 | 0 | (void) WriteBlobByte(ofile,(unsigned char) marker); |
1077 | 0 | } |
1078 | 0 | } |
1079 | | |
1080 | 0 | switch (marker) |
1081 | 0 | { |
1082 | 0 | case M_APP13: |
1083 | | /* we are going to write a new APP13 marker, so don't output the old one */ |
1084 | 0 | jpeg_skip_variable2(ifile, ofile); |
1085 | 0 | break; |
1086 | | |
1087 | 0 | case M_APP0: |
1088 | | /* APP0 is in each and every JPEG, so when we hit APP0 we insert our new APP13! */ |
1089 | 0 | jpeg_skip_variable(ifile, ofile); |
1090 | |
|
1091 | 0 | if (iptc != (Image *) NULL) |
1092 | 0 | { |
1093 | 0 | char |
1094 | 0 | psheader[] = "\xFF\xED\0\0Photoshop 3.0\0" "8BIM\x04\x04\0\0\0\0"; |
1095 | |
|
1096 | 0 | len=(unsigned int) GetBlobSize(iptc); |
1097 | 0 | if (len & 1) |
1098 | 0 | len++; /* make the length even */ |
1099 | 0 | psheader[2]=(char) ((len+16)>>8); |
1100 | 0 | psheader[3]=(char) ((len+16)&0xff); |
1101 | 0 | for (inx = 0; inx < 18; inx++) |
1102 | 0 | (void) WriteBlobByte(ofile,(unsigned char) psheader[inx]); |
1103 | 0 | jpeg_read_remaining(iptc, ofile); |
1104 | 0 | len=(unsigned int) GetBlobSize(iptc); |
1105 | 0 | if (len & 1) |
1106 | 0 | (void) WriteBlobByte(ofile,0); |
1107 | 0 | } |
1108 | 0 | break; |
1109 | | |
1110 | 0 | case M_SOS: |
1111 | | /* we hit data, no more marker-inserting can be done! */ |
1112 | 0 | jpeg_read_remaining(ifile, ofile); |
1113 | 0 | done = 1; |
1114 | 0 | break; |
1115 | | |
1116 | 0 | default: |
1117 | 0 | jpeg_skip_variable(ifile, ofile); |
1118 | 0 | break; |
1119 | 0 | } |
1120 | 0 | } |
1121 | 0 | return 1; |
1122 | 0 | } |
1123 | | |
1124 | | /* handle stripping the APP13 data out of a JPEG */ |
1125 | | #if defined(future) |
1126 | | static void jpeg_strip(Image *ifile, Image *ofile) |
1127 | | { |
1128 | | unsigned int marker; |
1129 | | |
1130 | | marker = jpeg_skip_till_marker(ifile, M_SOI); |
1131 | | if (marker == M_SOI) |
1132 | | { |
1133 | | (void) WriteBlobByte(ofile,0xff); |
1134 | | (void) WriteBlobByte(ofile,M_SOI); |
1135 | | jpeg_read_remaining(ifile, ofile); |
1136 | | } |
1137 | | } |
1138 | | |
1139 | | /* Extract any APP13 binary data into a file. */ |
1140 | | static int jpeg_extract(Image *ifile, Image *ofile) |
1141 | | { |
1142 | | unsigned int marker; |
1143 | | unsigned int done = 0; |
1144 | | |
1145 | | if (jpeg_skip_1(ifile) != 0xff) |
1146 | | return 0; |
1147 | | if (jpeg_skip_1(ifile) != M_SOI) |
1148 | | return 0; |
1149 | | |
1150 | | while (done == MagickFalse) |
1151 | | { |
1152 | | marker = jpeg_skip_till_marker(ifile, M_APP13); |
1153 | | if (marker == M_APP13) |
1154 | | { |
1155 | | marker = jpeg_nextmarker(ifile, ofile); |
1156 | | break; |
1157 | | } |
1158 | | } |
1159 | | return 1; |
1160 | | } |
1161 | | #endif |
1162 | | |
1163 | | static inline void CopyBlob(Image *source,Image *destination) |
1164 | 815 | { |
1165 | 815 | ssize_t |
1166 | 815 | i; |
1167 | | |
1168 | 815 | unsigned char |
1169 | 815 | *buffer; |
1170 | | |
1171 | 815 | ssize_t |
1172 | 815 | count, |
1173 | 815 | length; |
1174 | | |
1175 | 815 | buffer=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent, |
1176 | 815 | sizeof(*buffer)); |
1177 | 815 | if (buffer != (unsigned char *) NULL) |
1178 | 815 | { |
1179 | 815 | (void) memset(buffer,0,MagickMaxBufferExtent*sizeof(*buffer)); |
1180 | 815 | i=0; |
1181 | 1.63k | while ((length=ReadBlob(source,MagickMaxBufferExtent,buffer)) != 0) |
1182 | 815 | { |
1183 | 815 | count=0; |
1184 | 1.63k | for (i=0; i < (ssize_t) length; i+=count) |
1185 | 815 | { |
1186 | 815 | count=WriteBlob(destination,(size_t) (length-i),buffer+i); |
1187 | 815 | if (count <= 0) |
1188 | 0 | break; |
1189 | 815 | } |
1190 | 815 | if (i < (ssize_t) length) |
1191 | 0 | break; |
1192 | 815 | } |
1193 | 815 | buffer=(unsigned char *) RelinquishMagickMemory(buffer); |
1194 | 815 | } |
1195 | 815 | } |
1196 | | |
1197 | | static Image *ReadMETAImage(const ImageInfo *image_info, |
1198 | | ExceptionInfo *exception) |
1199 | 964 | { |
1200 | 964 | Image |
1201 | 964 | *buff, |
1202 | 964 | *image; |
1203 | | |
1204 | 964 | MagickBooleanType |
1205 | 964 | status; |
1206 | | |
1207 | 964 | StringInfo |
1208 | 964 | *profile; |
1209 | | |
1210 | 964 | size_t |
1211 | 964 | length; |
1212 | | |
1213 | 964 | unsigned char |
1214 | 964 | *blob; |
1215 | | |
1216 | | /* |
1217 | | Open file containing binary metadata |
1218 | | */ |
1219 | 964 | assert(image_info != (const ImageInfo *) NULL); |
1220 | 964 | assert(image_info->signature == MagickCoreSignature); |
1221 | 964 | assert(exception != (ExceptionInfo *) NULL); |
1222 | 964 | assert(exception->signature == MagickCoreSignature); |
1223 | 964 | if (IsEventLogging() != MagickFalse) |
1224 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", |
1225 | 0 | image_info->filename); |
1226 | 964 | image=AcquireImage(image_info,exception); |
1227 | 964 | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
1228 | 964 | if (status == MagickFalse) |
1229 | 0 | { |
1230 | 0 | image=DestroyImageList(image); |
1231 | 0 | return((Image *) NULL); |
1232 | 0 | } |
1233 | 964 | image->columns=1; |
1234 | 964 | image->rows=1; |
1235 | 964 | if (SetImageBackgroundColor(image,exception) == MagickFalse) |
1236 | 0 | { |
1237 | 0 | image=DestroyImageList(image); |
1238 | 0 | return((Image *) NULL); |
1239 | 0 | } |
1240 | 964 | length=1; |
1241 | 964 | if (LocaleNCompare(image_info->magick,"8BIM",4) == 0) |
1242 | 513 | { |
1243 | | /* |
1244 | | Read 8BIM binary metadata. |
1245 | | */ |
1246 | 513 | buff=AcquireImage((ImageInfo *) NULL,exception); |
1247 | 513 | if (buff == (Image *) NULL) |
1248 | 513 | ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
1249 | 513 | blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char)); |
1250 | 513 | if (blob == (unsigned char *) NULL) |
1251 | 0 | { |
1252 | 0 | buff=DestroyImage(buff); |
1253 | 0 | ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
1254 | 0 | } |
1255 | 513 | (void) memset(blob,0,length); |
1256 | 513 | AttachBlob(buff->blob,blob,length); |
1257 | 513 | if (LocaleCompare(image_info->magick,"8BIMTEXT") == 0) |
1258 | 0 | { |
1259 | 0 | length=(size_t) parse8BIM(image, buff); |
1260 | 0 | if (length == 0) |
1261 | 0 | { |
1262 | 0 | blob=(unsigned char *) DetachBlob(buff->blob); |
1263 | 0 | blob=(unsigned char *) RelinquishMagickMemory(blob); |
1264 | 0 | buff=DestroyImage(buff); |
1265 | 0 | ThrowReaderException(CorruptImageError,"CorruptImage"); |
1266 | 0 | } |
1267 | 0 | if (length & 1) |
1268 | 0 | (void) WriteBlobByte(buff,0x0); |
1269 | 0 | } |
1270 | 513 | else if (LocaleCompare(image_info->magick,"8BIMWTEXT") == 0) |
1271 | 149 | { |
1272 | 149 | length=(size_t) parse8BIMW(image, buff); |
1273 | 149 | if (length == 0) |
1274 | 18 | { |
1275 | 18 | blob=(unsigned char *) DetachBlob(buff->blob); |
1276 | 18 | blob=(unsigned char *) RelinquishMagickMemory(blob); |
1277 | 18 | buff=DestroyImage(buff); |
1278 | 18 | ThrowReaderException(CorruptImageError,"CorruptImage"); |
1279 | 0 | } |
1280 | 131 | if (length & 1) |
1281 | 21 | (void) WriteBlobByte(buff,0x0); |
1282 | 131 | } |
1283 | 364 | else |
1284 | 364 | CopyBlob(image,buff); |
1285 | 495 | profile=BlobToProfileStringInfo("8bim",GetBlobStreamData(buff),(size_t) |
1286 | 495 | GetBlobSize(buff),exception); |
1287 | 495 | SetImageProfilePrivate(image,profile,exception); |
1288 | 495 | blob=(unsigned char *) DetachBlob(buff->blob); |
1289 | 495 | blob=(unsigned char *) RelinquishMagickMemory(blob); |
1290 | 495 | buff=DestroyImage(buff); |
1291 | 495 | if (status == MagickFalse) |
1292 | 495 | ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
1293 | 495 | } |
1294 | 946 | if (LocaleNCompare(image_info->magick,"APP1",4) == 0) |
1295 | 0 | { |
1296 | 0 | char |
1297 | 0 | name[MagickPathExtent]; |
1298 | |
|
1299 | 0 | (void) FormatLocaleString(name,MagickPathExtent,"APP%d",1); |
1300 | 0 | buff=AcquireImage((ImageInfo *) NULL,exception); |
1301 | 0 | if (buff == (Image *) NULL) |
1302 | 0 | ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
1303 | 0 | blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char)); |
1304 | 0 | if (blob == (unsigned char *) NULL) |
1305 | 0 | { |
1306 | 0 | buff=DestroyImage(buff); |
1307 | 0 | ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
1308 | 0 | } |
1309 | 0 | AttachBlob(buff->blob,blob,length); |
1310 | 0 | if (LocaleCompare(image_info->magick,"APP1JPEG") == 0) |
1311 | 0 | { |
1312 | 0 | Image |
1313 | 0 | *iptc; |
1314 | |
|
1315 | 0 | int |
1316 | 0 | result; |
1317 | |
|
1318 | 0 | if (image_info->profile == (void *) NULL) |
1319 | 0 | { |
1320 | 0 | blob=(unsigned char *) DetachBlob(buff->blob); |
1321 | 0 | blob=(unsigned char *) RelinquishMagickMemory(blob); |
1322 | 0 | buff=DestroyImage(buff); |
1323 | 0 | ThrowReaderException(CoderError,"NoIPTCProfileAvailable"); |
1324 | 0 | } |
1325 | 0 | profile=CloneStringInfo((StringInfo *) image_info->profile); |
1326 | 0 | iptc=AcquireImage((ImageInfo *) NULL,exception); |
1327 | 0 | if (iptc == (Image *) NULL) |
1328 | 0 | { |
1329 | 0 | blob=(unsigned char *) DetachBlob(buff->blob); |
1330 | 0 | blob=(unsigned char *) RelinquishMagickMemory(blob); |
1331 | 0 | buff=DestroyImage(buff); |
1332 | 0 | ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
1333 | 0 | } |
1334 | 0 | AttachBlob(iptc->blob,GetStringInfoDatum(profile), |
1335 | 0 | GetStringInfoLength(profile)); |
1336 | 0 | profile->datum=(unsigned char *) NULL; |
1337 | 0 | profile->length=0; |
1338 | 0 | profile=DestroyStringInfo(profile); |
1339 | 0 | result=jpeg_embed(image,buff,iptc); |
1340 | 0 | blob=(unsigned char *) DetachBlob(iptc->blob); |
1341 | 0 | blob=(unsigned char *) RelinquishMagickMemory(blob); |
1342 | 0 | iptc=DestroyImage(iptc); |
1343 | 0 | if (result == 0) |
1344 | 0 | { |
1345 | 0 | blob=(unsigned char *) DetachBlob(buff->blob); |
1346 | 0 | blob=(unsigned char *) RelinquishMagickMemory(blob); |
1347 | 0 | buff=DestroyImage(buff); |
1348 | 0 | ThrowReaderException(CoderError,"JPEGEmbeddingFailed"); |
1349 | 0 | } |
1350 | 0 | } |
1351 | 0 | else |
1352 | 0 | CopyBlob(image,buff); |
1353 | 0 | profile=BlobToProfileStringInfo(name,GetBlobStreamData(buff),(size_t) |
1354 | 0 | GetBlobSize(buff),exception); |
1355 | 0 | (void) SetImageProfilePrivate(image,profile,exception); |
1356 | 0 | blob=(unsigned char *) DetachBlob(buff->blob); |
1357 | 0 | blob=(unsigned char *) RelinquishMagickMemory(blob); |
1358 | 0 | buff=DestroyImage(buff); |
1359 | 0 | } |
1360 | 946 | if ((LocaleCompare(image_info->magick,"ICC") == 0) || |
1361 | 944 | (LocaleCompare(image_info->magick,"ICM") == 0)) |
1362 | 3 | { |
1363 | 3 | buff=AcquireImage((ImageInfo *) NULL,exception); |
1364 | 3 | if (buff == (Image *) NULL) |
1365 | 3 | ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
1366 | 3 | blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char)); |
1367 | 3 | if (blob == (unsigned char *) NULL) |
1368 | 0 | { |
1369 | 0 | buff=DestroyImage(buff); |
1370 | 0 | ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
1371 | 0 | } |
1372 | 3 | AttachBlob(buff->blob,blob,length); |
1373 | 3 | CopyBlob(image,buff); |
1374 | 3 | profile=BlobToProfileStringInfo("icc",GetBlobStreamData(buff),(size_t) |
1375 | 3 | GetBlobSize(buff),exception); |
1376 | 3 | (void) SetImageProfilePrivate(image,profile,exception); |
1377 | 3 | blob=(unsigned char *) DetachBlob(buff->blob); |
1378 | 3 | blob=(unsigned char *) RelinquishMagickMemory(blob); |
1379 | 3 | buff=DestroyImage(buff); |
1380 | 3 | } |
1381 | 946 | if (LocaleCompare(image_info->magick,"IPTC") == 0) |
1382 | 446 | { |
1383 | 446 | buff=AcquireImage((ImageInfo *) NULL,exception); |
1384 | 446 | if (buff == (Image *) NULL) |
1385 | 446 | ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
1386 | 446 | blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char)); |
1387 | 446 | if (blob == (unsigned char *) NULL) |
1388 | 0 | { |
1389 | 0 | buff=DestroyImage(buff); |
1390 | 0 | ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
1391 | 0 | } |
1392 | 446 | AttachBlob(buff->blob,blob,length); |
1393 | 446 | CopyBlob(image,buff); |
1394 | 446 | profile=BlobToProfileStringInfo("iptc",GetBlobStreamData(buff),(size_t) |
1395 | 446 | GetBlobSize(buff),exception); |
1396 | 446 | (void) SetImageProfilePrivate(image,profile,exception); |
1397 | 446 | blob=(unsigned char *) DetachBlob(buff->blob); |
1398 | 446 | blob=(unsigned char *) RelinquishMagickMemory(blob); |
1399 | 446 | buff=DestroyImage(buff); |
1400 | 446 | } |
1401 | 946 | if (LocaleCompare(image_info->magick,"XMP") == 0) |
1402 | 2 | { |
1403 | 2 | buff=AcquireImage((ImageInfo *) NULL,exception); |
1404 | 2 | if (buff == (Image *) NULL) |
1405 | 2 | ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
1406 | 2 | blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char)); |
1407 | 2 | if (blob == (unsigned char *) NULL) |
1408 | 0 | { |
1409 | 0 | buff=DestroyImage(buff); |
1410 | 0 | ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
1411 | 0 | } |
1412 | 2 | AttachBlob(buff->blob,blob,length); |
1413 | 2 | CopyBlob(image,buff); |
1414 | 2 | profile=BlobToProfileStringInfo("xmp",GetBlobStreamData(buff),(size_t) |
1415 | 2 | GetBlobSize(buff),exception); |
1416 | 2 | (void) SetImageProfilePrivate(image,profile,exception); |
1417 | 2 | blob=(unsigned char *) DetachBlob(buff->blob); |
1418 | 2 | blob=(unsigned char *) RelinquishMagickMemory(blob); |
1419 | 2 | buff=DestroyImage(buff); |
1420 | 2 | } |
1421 | 946 | if (CloseBlob(image) == MagickFalse) |
1422 | 0 | status=MagickFalse; |
1423 | 946 | if (status == MagickFalse) |
1424 | 0 | return(DestroyImageList(image)); |
1425 | 946 | return(GetFirstImageInList(image)); |
1426 | 946 | } |
1427 | | |
1428 | | /* |
1429 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1430 | | % % |
1431 | | % % |
1432 | | % % |
1433 | | % R e g i s t e r M E T A I m a g e % |
1434 | | % % |
1435 | | % % |
1436 | | % % |
1437 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1438 | | % |
1439 | | % RegisterMETAImage() adds attributes for the META image format to |
1440 | | % the list of supported formats. The attributes include the image format |
1441 | | % tag, a method to read and/or write the format, whether the format |
1442 | | % supports the saving of more than one frame to the same file or blob, |
1443 | | % whether the format supports native in-memory I/O, and a brief |
1444 | | % description of the format. |
1445 | | % |
1446 | | % The format of the RegisterMETAImage method is: |
1447 | | % |
1448 | | % size_t RegisterMETAImage(void) |
1449 | | % |
1450 | | */ |
1451 | | ModuleExport size_t RegisterMETAImage(void) |
1452 | 8 | { |
1453 | 8 | MagickInfo |
1454 | 8 | *entry; |
1455 | | |
1456 | 8 | entry=AcquireMagickInfo("META","8BIM","Photoshop resource format"); |
1457 | 8 | entry->decoder=(DecodeImageHandler *) ReadMETAImage; |
1458 | 8 | entry->encoder=(EncodeImageHandler *) WriteMETAImage; |
1459 | 8 | entry->flags^=CoderAdjoinFlag; |
1460 | 8 | entry->flags|=CoderStealthFlag; |
1461 | 8 | entry->flags|=CoderDecoderSeekableStreamFlag; |
1462 | 8 | (void) RegisterMagickInfo(entry); |
1463 | 8 | entry=AcquireMagickInfo("META","8BIMTEXT","Photoshop resource text format"); |
1464 | 8 | entry->decoder=(DecodeImageHandler *) ReadMETAImage; |
1465 | 8 | entry->encoder=(EncodeImageHandler *) WriteMETAImage; |
1466 | 8 | entry->flags^=CoderAdjoinFlag; |
1467 | 8 | entry->flags|=CoderStealthFlag; |
1468 | 8 | entry->flags|=CoderDecoderSeekableStreamFlag; |
1469 | 8 | (void) RegisterMagickInfo(entry); |
1470 | 8 | entry=AcquireMagickInfo("META","8BIMWTEXT", |
1471 | 8 | "Photoshop resource wide text format"); |
1472 | 8 | entry->decoder=(DecodeImageHandler *) ReadMETAImage; |
1473 | 8 | entry->encoder=(EncodeImageHandler *) WriteMETAImage; |
1474 | 8 | entry->flags^=CoderAdjoinFlag; |
1475 | 8 | entry->flags|=CoderStealthFlag; |
1476 | 8 | entry->flags|=CoderDecoderSeekableStreamFlag; |
1477 | 8 | (void) RegisterMagickInfo(entry); |
1478 | 8 | entry=AcquireMagickInfo("META","APP1","Raw application information"); |
1479 | 8 | entry->decoder=(DecodeImageHandler *) ReadMETAImage; |
1480 | 8 | entry->encoder=(EncodeImageHandler *) WriteMETAImage; |
1481 | 8 | entry->flags^=CoderAdjoinFlag; |
1482 | 8 | entry->flags|=CoderStealthFlag; |
1483 | 8 | entry->flags|=CoderDecoderSeekableStreamFlag; |
1484 | 8 | (void) RegisterMagickInfo(entry); |
1485 | 8 | entry=AcquireMagickInfo("META","APP1JPEG","Raw JPEG binary data"); |
1486 | 8 | entry->decoder=(DecodeImageHandler *) ReadMETAImage; |
1487 | 8 | entry->encoder=(EncodeImageHandler *) WriteMETAImage; |
1488 | 8 | entry->flags^=CoderAdjoinFlag; |
1489 | 8 | entry->flags|=CoderStealthFlag; |
1490 | 8 | entry->flags|=CoderDecoderSeekableStreamFlag; |
1491 | 8 | (void) RegisterMagickInfo(entry); |
1492 | 8 | entry=AcquireMagickInfo("META","EXIF","Exif digital camera binary data"); |
1493 | 8 | entry->decoder=(DecodeImageHandler *) ReadMETAImage; |
1494 | 8 | entry->encoder=(EncodeImageHandler *) WriteMETAImage; |
1495 | 8 | entry->flags^=CoderAdjoinFlag; |
1496 | 8 | entry->flags|=CoderStealthFlag; |
1497 | 8 | entry->flags|=CoderDecoderSeekableStreamFlag; |
1498 | 8 | (void) RegisterMagickInfo(entry); |
1499 | 8 | entry=AcquireMagickInfo("META","XMP","Adobe XML metadata"); |
1500 | 8 | entry->decoder=(DecodeImageHandler *) ReadMETAImage; |
1501 | 8 | entry->encoder=(EncodeImageHandler *) WriteMETAImage; |
1502 | 8 | entry->flags^=CoderAdjoinFlag; |
1503 | 8 | entry->flags|=CoderStealthFlag; |
1504 | 8 | entry->flags|=CoderDecoderSeekableStreamFlag; |
1505 | 8 | (void) RegisterMagickInfo(entry); |
1506 | 8 | entry=AcquireMagickInfo("META","ICM","ICC Color Profile"); |
1507 | 8 | entry->decoder=(DecodeImageHandler *) ReadMETAImage; |
1508 | 8 | entry->encoder=(EncodeImageHandler *) WriteMETAImage; |
1509 | 8 | entry->flags^=CoderAdjoinFlag; |
1510 | 8 | entry->flags|=CoderStealthFlag; |
1511 | 8 | entry->flags|=CoderDecoderSeekableStreamFlag; |
1512 | 8 | (void) RegisterMagickInfo(entry); |
1513 | 8 | entry=AcquireMagickInfo("META","ICC","ICC Color Profile"); |
1514 | 8 | entry->decoder=(DecodeImageHandler *) ReadMETAImage; |
1515 | 8 | entry->encoder=(EncodeImageHandler *) WriteMETAImage; |
1516 | 8 | entry->flags^=CoderAdjoinFlag; |
1517 | 8 | entry->flags|=CoderStealthFlag; |
1518 | 8 | entry->flags|=CoderDecoderSeekableStreamFlag; |
1519 | 8 | (void) RegisterMagickInfo(entry); |
1520 | 8 | entry=AcquireMagickInfo("META","IPTC","IPTC Newsphoto"); |
1521 | 8 | entry->decoder=(DecodeImageHandler *) ReadMETAImage; |
1522 | 8 | entry->encoder=(EncodeImageHandler *) WriteMETAImage; |
1523 | 8 | entry->flags^=CoderAdjoinFlag; |
1524 | 8 | entry->flags|=CoderStealthFlag; |
1525 | 8 | entry->flags|=CoderDecoderSeekableStreamFlag; |
1526 | 8 | (void) RegisterMagickInfo(entry); |
1527 | 8 | entry=AcquireMagickInfo("META","IPTCTEXT","IPTC Newsphoto text format"); |
1528 | 8 | entry->decoder=(DecodeImageHandler *) ReadMETAImage; |
1529 | 8 | entry->encoder=(EncodeImageHandler *) WriteMETAImage; |
1530 | 8 | entry->flags^=CoderAdjoinFlag; |
1531 | 8 | entry->flags|=CoderStealthFlag; |
1532 | 8 | entry->flags|=CoderDecoderSeekableStreamFlag; |
1533 | 8 | (void) RegisterMagickInfo(entry); |
1534 | 8 | entry=AcquireMagickInfo("META","IPTCWTEXT","IPTC Newsphoto text format"); |
1535 | 8 | entry->decoder=(DecodeImageHandler *) ReadMETAImage; |
1536 | 8 | entry->encoder=(EncodeImageHandler *) WriteMETAImage; |
1537 | 8 | entry->flags^=CoderAdjoinFlag; |
1538 | 8 | entry->flags|=CoderStealthFlag; |
1539 | 8 | entry->flags|=CoderDecoderSeekableStreamFlag; |
1540 | 8 | (void) RegisterMagickInfo(entry); |
1541 | 8 | return(MagickImageCoderSignature); |
1542 | 8 | } |
1543 | | |
1544 | | /* |
1545 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1546 | | % % |
1547 | | % % |
1548 | | % % |
1549 | | % U n r e g i s t e r M E T A I m a g e % |
1550 | | % % |
1551 | | % % |
1552 | | % % |
1553 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1554 | | % |
1555 | | % UnregisterMETAImage() removes format registrations made by the |
1556 | | % META module from the list of supported formats. |
1557 | | % |
1558 | | % The format of the UnregisterMETAImage method is: |
1559 | | % |
1560 | | % UnregisterMETAImage(void) |
1561 | | % |
1562 | | */ |
1563 | | ModuleExport void UnregisterMETAImage(void) |
1564 | 0 | { |
1565 | 0 | (void) UnregisterMagickInfo("8BIM"); |
1566 | 0 | (void) UnregisterMagickInfo("8BIMTEXT"); |
1567 | 0 | (void) UnregisterMagickInfo("8BIMWTEXT"); |
1568 | 0 | (void) UnregisterMagickInfo("EXIF"); |
1569 | 0 | (void) UnregisterMagickInfo("APP1"); |
1570 | 0 | (void) UnregisterMagickInfo("APP1JPEG"); |
1571 | 0 | (void) UnregisterMagickInfo("ICCTEXT"); |
1572 | 0 | (void) UnregisterMagickInfo("ICM"); |
1573 | 0 | (void) UnregisterMagickInfo("ICC"); |
1574 | 0 | (void) UnregisterMagickInfo("IPTC"); |
1575 | 0 | (void) UnregisterMagickInfo("IPTCTEXT"); |
1576 | 0 | (void) UnregisterMagickInfo("IPTCWTEXT"); |
1577 | 0 | (void) UnregisterMagickInfo("XMP"); |
1578 | 0 | } |
1579 | | |
1580 | | /* |
1581 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1582 | | % % |
1583 | | % % |
1584 | | % % |
1585 | | % W r i t e M E T A I m a g e % |
1586 | | % % |
1587 | | % % |
1588 | | % % |
1589 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1590 | | % |
1591 | | % WriteMETAImage() writes a META image to a file. |
1592 | | % |
1593 | | % The format of the WriteMETAImage method is: |
1594 | | % |
1595 | | % MagickBooleanType WriteMETAImage(const ImageInfo *image_info, |
1596 | | % Image *image,ExceptionInfo *exception) |
1597 | | % |
1598 | | % Compression code contributed by Kyle Shorter. |
1599 | | % |
1600 | | % A description of each parameter follows: |
1601 | | % |
1602 | | % o image_info: Specifies a pointer to an ImageInfo structure. |
1603 | | % |
1604 | | % o image: A pointer to a Image structure. |
1605 | | % |
1606 | | % o exception: return any errors or warnings in this structure. |
1607 | | % |
1608 | | */ |
1609 | | |
1610 | | static size_t GetIPTCStream(unsigned char **info,size_t length) |
1611 | 0 | { |
1612 | 0 | int |
1613 | 0 | c; |
1614 | |
|
1615 | 0 | size_t |
1616 | 0 | extent, |
1617 | 0 | info_length, |
1618 | 0 | tag_length; |
1619 | |
|
1620 | 0 | unsigned char |
1621 | 0 | *p; |
1622 | |
|
1623 | 0 | ssize_t |
1624 | 0 | i; |
1625 | |
|
1626 | 0 | unsigned int |
1627 | 0 | marker; |
1628 | |
|
1629 | 0 | p=(*info); |
1630 | 0 | extent=length; |
1631 | 0 | if ((*p == 0x1c) && (*(p+1) == 0x02)) |
1632 | 0 | return(length); |
1633 | | /* |
1634 | | Extract IPTC from 8BIM resource block. |
1635 | | */ |
1636 | 0 | while (extent >= 12) |
1637 | 0 | { |
1638 | 0 | if (strncmp((const char *) p,"8BIM",4)) |
1639 | 0 | break; |
1640 | 0 | p+=(ptrdiff_t) 4; |
1641 | 0 | extent-=4; |
1642 | 0 | marker=(unsigned int) (*p) << 8 | *(p+1); |
1643 | 0 | p+=(ptrdiff_t) 2; |
1644 | 0 | extent-=2; |
1645 | 0 | c=*p++; |
1646 | 0 | extent--; |
1647 | 0 | c|=0x01; |
1648 | 0 | if ((size_t) c >= extent) |
1649 | 0 | break; |
1650 | 0 | p+=(ptrdiff_t) c; |
1651 | 0 | extent=(size_t) ((ssize_t) extent-c); |
1652 | 0 | if (extent < 4) |
1653 | 0 | break; |
1654 | 0 | tag_length=(((size_t) *p) << 24) | (((size_t) *(p+1)) << 16) | |
1655 | 0 | (((size_t) *(p+2)) << 8) | ((size_t) *(p+3)); |
1656 | 0 | p+=(ptrdiff_t) 4; |
1657 | 0 | extent-=4; |
1658 | 0 | if (tag_length > extent) |
1659 | 0 | break; |
1660 | 0 | if (marker == IPTC_ID) |
1661 | 0 | { |
1662 | 0 | *info=p; |
1663 | 0 | return(tag_length); |
1664 | 0 | } |
1665 | 0 | if ((tag_length & 0x01) != 0) |
1666 | 0 | { |
1667 | 0 | tag_length++; |
1668 | 0 | if (tag_length > extent) |
1669 | 0 | break; |
1670 | 0 | } |
1671 | 0 | p+=(ptrdiff_t) tag_length; |
1672 | 0 | extent-=tag_length; |
1673 | 0 | } |
1674 | | /* |
1675 | | Find the beginning of the IPTC info. |
1676 | | */ |
1677 | 0 | p=(*info); |
1678 | 0 | tag_length=0; |
1679 | 0 | iptc_find: |
1680 | 0 | info_length=0; |
1681 | 0 | marker=MagickFalse; |
1682 | 0 | while (length != 0) |
1683 | 0 | { |
1684 | 0 | c=(*p++); |
1685 | 0 | length--; |
1686 | 0 | if (length == 0) |
1687 | 0 | break; |
1688 | 0 | if (c == 0x1c) |
1689 | 0 | { |
1690 | 0 | p--; |
1691 | 0 | *info=p; /* let the caller know were it is */ |
1692 | 0 | break; |
1693 | 0 | } |
1694 | 0 | } |
1695 | | /* |
1696 | | Determine the length of the IPTC info. |
1697 | | */ |
1698 | 0 | while (length != 0) |
1699 | 0 | { |
1700 | 0 | c=(*p++); |
1701 | 0 | length--; |
1702 | 0 | if (length == 0) |
1703 | 0 | break; |
1704 | 0 | if (c == 0x1c) |
1705 | 0 | marker=MagickTrue; |
1706 | 0 | else |
1707 | 0 | if (marker) |
1708 | 0 | break; |
1709 | 0 | else |
1710 | 0 | continue; |
1711 | 0 | info_length++; |
1712 | | /* |
1713 | | Found the 0x1c tag; skip the dataset and record number tags. |
1714 | | */ |
1715 | 0 | c=(*p++); /* should be 2 */ |
1716 | 0 | length--; |
1717 | 0 | if (length == 0) |
1718 | 0 | break; |
1719 | 0 | if ((info_length == 1) && (c != 2)) |
1720 | 0 | goto iptc_find; |
1721 | 0 | info_length++; |
1722 | 0 | c=(*p++); /* should be 0 */ |
1723 | 0 | length--; |
1724 | 0 | if (length == 0) |
1725 | 0 | break; |
1726 | 0 | if ((info_length == 2) && (c != 0)) |
1727 | 0 | goto iptc_find; |
1728 | 0 | info_length++; |
1729 | | /* |
1730 | | Decode the length of the block that follows - ssize_t or short format. |
1731 | | */ |
1732 | 0 | c=(*p++); |
1733 | 0 | length--; |
1734 | 0 | if (length == 0) |
1735 | 0 | break; |
1736 | 0 | info_length++; |
1737 | 0 | if ((c & 0x80) != 0) |
1738 | 0 | { |
1739 | | /* |
1740 | | Long format. |
1741 | | */ |
1742 | 0 | tag_length=0; |
1743 | 0 | for (i=0; i < 4; i++) |
1744 | 0 | { |
1745 | 0 | tag_length<<=8; |
1746 | 0 | tag_length|=(*p++); |
1747 | 0 | length--; |
1748 | 0 | if (length == 0) |
1749 | 0 | break; |
1750 | 0 | info_length++; |
1751 | 0 | } |
1752 | 0 | } |
1753 | 0 | else |
1754 | 0 | { |
1755 | | /* |
1756 | | Short format. |
1757 | | */ |
1758 | 0 | tag_length=(size_t) (c << 8); |
1759 | 0 | c=(*p++); |
1760 | 0 | length--; |
1761 | 0 | if (length == 0) |
1762 | 0 | break; |
1763 | 0 | info_length++; |
1764 | 0 | tag_length|=(unsigned int) c; |
1765 | 0 | } |
1766 | 0 | if (tag_length > length) |
1767 | 0 | break; |
1768 | 0 | p+=(ptrdiff_t) tag_length; |
1769 | 0 | length-=tag_length; |
1770 | 0 | if (length == 0) |
1771 | 0 | break; |
1772 | 0 | info_length+=tag_length; |
1773 | 0 | } |
1774 | 0 | return(info_length); |
1775 | 0 | } |
1776 | | |
1777 | | static void formatString(Image *ofile, const char *s, ssize_t len) |
1778 | 0 | { |
1779 | 0 | char |
1780 | 0 | temp[MagickPathExtent]; |
1781 | |
|
1782 | 0 | (void) WriteBlobByte(ofile,'"'); |
1783 | 0 | for (; len > 0; len--, s++) { |
1784 | 0 | int c = (*s) & 255; |
1785 | 0 | switch (c) { |
1786 | 0 | case '&': |
1787 | 0 | (void) WriteBlobString(ofile,"&"); |
1788 | 0 | break; |
1789 | | #ifdef HANDLE_GT_LT |
1790 | | case '<': |
1791 | | (void) WriteBlobString(ofile,"<"); |
1792 | | break; |
1793 | | case '>': |
1794 | | (void) WriteBlobString(ofile,">"); |
1795 | | break; |
1796 | | #endif |
1797 | 0 | case '"': |
1798 | 0 | (void) WriteBlobString(ofile,"""); |
1799 | 0 | break; |
1800 | 0 | default: |
1801 | 0 | if (isprint((int) ((unsigned char) c)) != 0) |
1802 | 0 | (void) WriteBlobByte(ofile,(unsigned char) *s); |
1803 | 0 | else |
1804 | 0 | { |
1805 | 0 | (void) FormatLocaleString(temp,MagickPathExtent,"&#%d;", c & 255); |
1806 | 0 | (void) WriteBlobString(ofile,temp); |
1807 | 0 | } |
1808 | 0 | break; |
1809 | 0 | } |
1810 | 0 | } |
1811 | | #if defined(MAGICKCORE_WINDOWS_SUPPORT) |
1812 | | (void) WriteBlobString(ofile,"\"\r\n"); |
1813 | | #else |
1814 | 0 | (void) WriteBlobString(ofile,"\"\n"); |
1815 | 0 | #endif |
1816 | 0 | } |
1817 | | |
1818 | | typedef struct _tag_spec |
1819 | | { |
1820 | | const short |
1821 | | id; |
1822 | | |
1823 | | const char |
1824 | | *name; |
1825 | | } tag_spec; |
1826 | | |
1827 | | static const tag_spec tags[] = { |
1828 | | { 5, "Image Name" }, |
1829 | | { 7, "Edit Status" }, |
1830 | | { 10, "Priority" }, |
1831 | | { 15, "Category" }, |
1832 | | { 20, "Supplemental Category" }, |
1833 | | { 22, "Fixture Identifier" }, |
1834 | | { 25, "Keyword" }, |
1835 | | { 30, "Release Date" }, |
1836 | | { 35, "Release Time" }, |
1837 | | { 40, "Special Instructions" }, |
1838 | | { 45, "Reference Service" }, |
1839 | | { 47, "Reference Date" }, |
1840 | | { 50, "Reference Number" }, |
1841 | | { 55, "Created Date" }, |
1842 | | { 60, "Created Time" }, |
1843 | | { 65, "Originating Program" }, |
1844 | | { 70, "Program Version" }, |
1845 | | { 75, "Object Cycle" }, |
1846 | | { 80, "Byline" }, |
1847 | | { 85, "Byline Title" }, |
1848 | | { 90, "City" }, |
1849 | | { 92, "Sub-Location" }, |
1850 | | { 95, "Province State" }, |
1851 | | { 100, "Country Code" }, |
1852 | | { 101, "Country" }, |
1853 | | { 103, "Original Transmission Reference" }, |
1854 | | { 105, "Headline" }, |
1855 | | { 110, "Credit" }, |
1856 | | { 115, "Source" }, |
1857 | | { 116, "Copyright String" }, |
1858 | | { 120, "Caption" }, |
1859 | | { 121, "Image Orientation" }, |
1860 | | { 122, "Caption Writer" }, |
1861 | | { 131, "Local Caption" }, |
1862 | | { 200, "Custom Field 1" }, |
1863 | | { 201, "Custom Field 2" }, |
1864 | | { 202, "Custom Field 3" }, |
1865 | | { 203, "Custom Field 4" }, |
1866 | | { 204, "Custom Field 5" }, |
1867 | | { 205, "Custom Field 6" }, |
1868 | | { 206, "Custom Field 7" }, |
1869 | | { 207, "Custom Field 8" }, |
1870 | | { 208, "Custom Field 9" }, |
1871 | | { 209, "Custom Field 10" }, |
1872 | | { 210, "Custom Field 11" }, |
1873 | | { 211, "Custom Field 12" }, |
1874 | | { 212, "Custom Field 13" }, |
1875 | | { 213, "Custom Field 14" }, |
1876 | | { 214, "Custom Field 15" }, |
1877 | | { 215, "Custom Field 16" }, |
1878 | | { 216, "Custom Field 17" }, |
1879 | | { 217, "Custom Field 18" }, |
1880 | | { 218, "Custom Field 19" }, |
1881 | | { 219, "Custom Field 20" } |
1882 | | }; |
1883 | | |
1884 | | static void formatIPTC(Image *ifile, Image *ofile) |
1885 | 0 | { |
1886 | 0 | char |
1887 | 0 | temp[MagickPathExtent]; |
1888 | |
|
1889 | 0 | unsigned int |
1890 | 0 | foundiptc; |
1891 | |
|
1892 | 0 | unsigned char |
1893 | 0 | recnum, |
1894 | 0 | dataset; |
1895 | |
|
1896 | 0 | unsigned char |
1897 | 0 | *readable, |
1898 | 0 | *str; |
1899 | |
|
1900 | 0 | ssize_t |
1901 | 0 | tagindx, |
1902 | 0 | taglen; |
1903 | |
|
1904 | 0 | int |
1905 | 0 | i, |
1906 | 0 | tagcount = (int) (sizeof(tags) / sizeof(tags[0])); |
1907 | |
|
1908 | 0 | int |
1909 | 0 | c; |
1910 | |
|
1911 | 0 | foundiptc = 0; /* found the IPTC-Header */ |
1912 | |
|
1913 | 0 | c=ReadBlobByte(ifile); |
1914 | 0 | while (c != EOF) |
1915 | 0 | { |
1916 | 0 | if (c == 0x1c) |
1917 | 0 | foundiptc = 1; |
1918 | 0 | else |
1919 | 0 | { |
1920 | 0 | if (foundiptc) |
1921 | 0 | return; |
1922 | 0 | else |
1923 | 0 | { |
1924 | 0 | c=ReadBlobByte(ifile); |
1925 | 0 | continue; |
1926 | 0 | } |
1927 | 0 | } |
1928 | | |
1929 | | /* we found the 0x1c tag and now grab the dataset and record number tags */ |
1930 | 0 | c=ReadBlobByte(ifile); |
1931 | 0 | if (c == EOF) |
1932 | 0 | return; |
1933 | 0 | dataset = (unsigned char) c; |
1934 | 0 | c=ReadBlobByte(ifile); |
1935 | 0 | if (c == EOF) |
1936 | 0 | return; |
1937 | 0 | recnum = (unsigned char) c; |
1938 | | /* try to match this record to one of the ones in our named table */ |
1939 | 0 | for (i=0; i< tagcount; i++) |
1940 | 0 | { |
1941 | 0 | if (tags[i].id == (short) recnum) |
1942 | 0 | break; |
1943 | 0 | } |
1944 | 0 | if (i < tagcount) |
1945 | 0 | readable = (unsigned char *) tags[i].name; |
1946 | 0 | else |
1947 | 0 | readable = (unsigned char *) ""; |
1948 | | /* |
1949 | | We decode the length of the block that follows - ssize_t or short fmt. |
1950 | | */ |
1951 | 0 | c=ReadBlobByte(ifile); |
1952 | 0 | if (c == EOF) |
1953 | 0 | return; |
1954 | 0 | if (c & (unsigned char) 0x80) |
1955 | 0 | return; |
1956 | 0 | else |
1957 | 0 | { |
1958 | 0 | int |
1959 | 0 | c0; |
1960 | |
|
1961 | 0 | c0=ReadBlobByte(ifile); |
1962 | 0 | if (c0 == EOF) |
1963 | 0 | return; |
1964 | 0 | taglen = (c << 8) | c0; |
1965 | 0 | } |
1966 | 0 | if (taglen < 0) |
1967 | 0 | return; |
1968 | | /* make a buffer to hold the tag datand snag it from the input stream */ |
1969 | 0 | str=(unsigned char *) AcquireQuantumMemory((size_t) (taglen+ |
1970 | 0 | MagickPathExtent),sizeof(*str)); |
1971 | 0 | if (str == (unsigned char *) NULL) |
1972 | 0 | return; |
1973 | 0 | for (tagindx=0; tagindx<taglen; tagindx++) |
1974 | 0 | { |
1975 | 0 | c=ReadBlobByte(ifile); |
1976 | 0 | if (c == EOF) |
1977 | 0 | { |
1978 | 0 | str=(unsigned char *) RelinquishMagickMemory(str); |
1979 | 0 | return; |
1980 | 0 | } |
1981 | 0 | str[tagindx] = (unsigned char) c; |
1982 | 0 | } |
1983 | 0 | str[taglen] = 0; |
1984 | | |
1985 | | /* now finish up by formatting this binary data into ASCII equivalent */ |
1986 | 0 | if (strlen((char *)readable) > 0) |
1987 | 0 | (void) FormatLocaleString(temp,MagickPathExtent,"%d#%d#%s=", |
1988 | 0 | (unsigned int) dataset, (unsigned int) recnum, readable); |
1989 | 0 | else |
1990 | 0 | (void) FormatLocaleString(temp,MagickPathExtent,"%d#%d=", |
1991 | 0 | (unsigned int) dataset,(unsigned int) recnum); |
1992 | 0 | (void) WriteBlobString(ofile,temp); |
1993 | 0 | formatString( ofile, (char *)str, taglen ); |
1994 | 0 | str=(unsigned char *) RelinquishMagickMemory(str); |
1995 | 0 | c=ReadBlobByte(ifile); |
1996 | 0 | } |
1997 | 0 | } |
1998 | | |
1999 | | static int readWordFromBuffer(char **s, ssize_t *len) |
2000 | 0 | { |
2001 | 0 | unsigned char |
2002 | 0 | buffer[2]; |
2003 | |
|
2004 | 0 | int |
2005 | 0 | i, |
2006 | 0 | c; |
2007 | |
|
2008 | 0 | for (i=0; i<2; i++) |
2009 | 0 | { |
2010 | 0 | c = *(*s)++; (*len)--; |
2011 | 0 | if (*len < 0) return -1; |
2012 | 0 | buffer[i] = (unsigned char) c; |
2013 | 0 | } |
2014 | 0 | return (((int) buffer[ 0 ]) << 8) | |
2015 | 0 | (((int) buffer[ 1 ])); |
2016 | 0 | } |
2017 | | |
2018 | | static int formatIPTCfromBuffer(Image *ofile, char *s, ssize_t len) |
2019 | 0 | { |
2020 | 0 | char |
2021 | 0 | temp[MagickPathExtent]; |
2022 | |
|
2023 | 0 | unsigned int |
2024 | 0 | foundiptc, |
2025 | 0 | tagsfound; |
2026 | |
|
2027 | 0 | unsigned char |
2028 | 0 | recnum, |
2029 | 0 | dataset; |
2030 | |
|
2031 | 0 | unsigned char |
2032 | 0 | *readable, |
2033 | 0 | *str; |
2034 | |
|
2035 | 0 | ssize_t |
2036 | 0 | tagindx, |
2037 | 0 | taglen; |
2038 | |
|
2039 | 0 | int |
2040 | 0 | i, |
2041 | 0 | tagcount = (int) (sizeof(tags) / sizeof(tags[0])); |
2042 | |
|
2043 | 0 | int |
2044 | 0 | c; |
2045 | |
|
2046 | 0 | foundiptc = 0; /* found the IPTC-Header */ |
2047 | 0 | tagsfound = 0; /* number of tags found */ |
2048 | |
|
2049 | 0 | while (len > 0) |
2050 | 0 | { |
2051 | 0 | c = *s++; len--; |
2052 | 0 | if (c == 0x1c) |
2053 | 0 | foundiptc = 1; |
2054 | 0 | else |
2055 | 0 | { |
2056 | 0 | if (foundiptc) |
2057 | 0 | return -1; |
2058 | 0 | else |
2059 | 0 | continue; |
2060 | 0 | } |
2061 | | /* |
2062 | | We found the 0x1c tag and now grab the dataset and record number tags. |
2063 | | */ |
2064 | 0 | c = *s++; len--; |
2065 | 0 | if (len < 0) return -1; |
2066 | 0 | dataset = (unsigned char) c; |
2067 | 0 | c = *s++; len--; |
2068 | 0 | if (len < 0) return -1; |
2069 | 0 | recnum = (unsigned char) c; |
2070 | | /* try to match this record to one of the ones in our named table */ |
2071 | 0 | for (i=0; i< tagcount; i++) |
2072 | 0 | if (tags[i].id == (short) recnum) |
2073 | 0 | break; |
2074 | 0 | if (i < tagcount) |
2075 | 0 | readable=(unsigned char *) tags[i].name; |
2076 | 0 | else |
2077 | 0 | readable=(unsigned char *) ""; |
2078 | | /* |
2079 | | We decode the length of the block that follows - ssize_t or short fmt. |
2080 | | */ |
2081 | 0 | c=(*s++); |
2082 | 0 | len--; |
2083 | 0 | if (len < 0) |
2084 | 0 | return(-1); |
2085 | 0 | if (c & (unsigned char) 0x80) |
2086 | 0 | return(0); |
2087 | 0 | else |
2088 | 0 | { |
2089 | 0 | s--; |
2090 | 0 | len++; |
2091 | 0 | taglen=readWordFromBuffer(&s, &len); |
2092 | 0 | } |
2093 | 0 | if (taglen < 0) |
2094 | 0 | return(-1); |
2095 | 0 | if (taglen > 65535) |
2096 | 0 | return(-1); |
2097 | | /* make a buffer to hold the tag datand snag it from the input stream */ |
2098 | 0 | str=(unsigned char *) AcquireQuantumMemory((size_t) (taglen+ |
2099 | 0 | MagickPathExtent),sizeof(*str)); |
2100 | 0 | if (str == (unsigned char *) NULL) |
2101 | 0 | { |
2102 | 0 | (void) printf("MemoryAllocationFailed"); |
2103 | 0 | return 0; |
2104 | 0 | } |
2105 | 0 | for (tagindx=0; tagindx<taglen; tagindx++) |
2106 | 0 | { |
2107 | 0 | c = *s++; len--; |
2108 | 0 | if (len < 0) |
2109 | 0 | { |
2110 | 0 | str=(unsigned char *) RelinquishMagickMemory(str); |
2111 | 0 | return(-1); |
2112 | 0 | } |
2113 | 0 | str[tagindx]=(unsigned char) c; |
2114 | 0 | } |
2115 | 0 | str[taglen]=0; |
2116 | | |
2117 | | /* now finish up by formatting this binary data into ASCII equivalent */ |
2118 | 0 | if (strlen((char *)readable) > 0) |
2119 | 0 | (void) FormatLocaleString(temp,MagickPathExtent,"%d#%d#%s=", |
2120 | 0 | (unsigned int) dataset,(unsigned int) recnum, readable); |
2121 | 0 | else |
2122 | 0 | (void) FormatLocaleString(temp,MagickPathExtent,"%d#%d=", |
2123 | 0 | (unsigned int) dataset,(unsigned int) recnum); |
2124 | 0 | (void) WriteBlobString(ofile,temp); |
2125 | 0 | formatString( ofile, (char *)str, taglen ); |
2126 | 0 | str=(unsigned char *) RelinquishMagickMemory(str); |
2127 | |
|
2128 | 0 | tagsfound++; |
2129 | 0 | } |
2130 | 0 | return ((int) tagsfound); |
2131 | 0 | } |
2132 | | |
2133 | | static int format8BIM(Image *ifile, Image *ofile) |
2134 | 0 | { |
2135 | 0 | char |
2136 | 0 | temp[MagickPathExtent]; |
2137 | |
|
2138 | 0 | unsigned int |
2139 | 0 | foundOSType; |
2140 | |
|
2141 | 0 | int |
2142 | 0 | ID, |
2143 | 0 | resCount, |
2144 | 0 | i, |
2145 | 0 | c; |
2146 | |
|
2147 | 0 | ssize_t |
2148 | 0 | count; |
2149 | |
|
2150 | 0 | unsigned char |
2151 | 0 | *PString, |
2152 | 0 | *str; |
2153 | |
|
2154 | 0 | resCount=0; |
2155 | 0 | foundOSType=0; /* found the OSType */ |
2156 | 0 | (void) foundOSType; |
2157 | 0 | c=ReadBlobByte(ifile); |
2158 | 0 | while (c != EOF) |
2159 | 0 | { |
2160 | 0 | if (c == '8') |
2161 | 0 | { |
2162 | 0 | unsigned char |
2163 | 0 | buffer[5]; |
2164 | |
|
2165 | 0 | buffer[0]=(unsigned char) c; |
2166 | 0 | for (i=1; i<4; i++) |
2167 | 0 | { |
2168 | 0 | c=ReadBlobByte(ifile); |
2169 | 0 | if (c == EOF) |
2170 | 0 | return(-1); |
2171 | 0 | buffer[i] = (unsigned char) c; |
2172 | 0 | } |
2173 | 0 | buffer[4]=0; |
2174 | 0 | if (strcmp((const char *)buffer, "8BIM") == 0) |
2175 | 0 | foundOSType=1; |
2176 | 0 | else |
2177 | 0 | continue; |
2178 | 0 | } |
2179 | 0 | else |
2180 | 0 | { |
2181 | 0 | c=ReadBlobByte(ifile); |
2182 | 0 | continue; |
2183 | 0 | } |
2184 | | /* |
2185 | | We found the OSType (8BIM) and now grab the ID, PString, and Size fields. |
2186 | | */ |
2187 | 0 | ID=ReadBlobMSBSignedShort(ifile); |
2188 | 0 | if (ID < 0) |
2189 | 0 | return(-1); |
2190 | 0 | { |
2191 | 0 | unsigned char |
2192 | 0 | plen; |
2193 | |
|
2194 | 0 | c=ReadBlobByte(ifile); |
2195 | 0 | if (c == EOF) |
2196 | 0 | return(-1); |
2197 | 0 | plen = (unsigned char) c; |
2198 | 0 | PString=(unsigned char *) AcquireQuantumMemory((size_t) (plen+ |
2199 | 0 | MagickPathExtent),sizeof(*PString)); |
2200 | 0 | if (PString == (unsigned char *) NULL) |
2201 | 0 | return 0; |
2202 | 0 | for (i=0; i<plen; i++) |
2203 | 0 | { |
2204 | 0 | c=ReadBlobByte(ifile); |
2205 | 0 | if (c == EOF) |
2206 | 0 | { |
2207 | 0 | PString=(unsigned char *) RelinquishMagickMemory(PString); |
2208 | 0 | return -1; |
2209 | 0 | } |
2210 | 0 | PString[i] = (unsigned char) c; |
2211 | 0 | } |
2212 | 0 | PString[ plen ] = 0; |
2213 | 0 | if ((plen & 0x01) == 0) |
2214 | 0 | { |
2215 | 0 | c=ReadBlobByte(ifile); |
2216 | 0 | if (c == EOF) |
2217 | 0 | { |
2218 | 0 | PString=(unsigned char *) RelinquishMagickMemory(PString); |
2219 | 0 | return -1; |
2220 | 0 | } |
2221 | 0 | } |
2222 | 0 | } |
2223 | 0 | count=(ssize_t) ReadBlobMSBSignedLong(ifile); |
2224 | 0 | if ((count < 0) || (count > (ssize_t) GetBlobSize(ifile))) |
2225 | 0 | { |
2226 | 0 | PString=(unsigned char *) RelinquishMagickMemory(PString); |
2227 | 0 | return -1; |
2228 | 0 | } |
2229 | | /* make a buffer to hold the data and snag it from the input stream */ |
2230 | 0 | str=(unsigned char *) AcquireQuantumMemory((size_t) count+1,sizeof(*str)); |
2231 | 0 | if (str == (unsigned char *) NULL) |
2232 | 0 | { |
2233 | 0 | PString=(unsigned char *) RelinquishMagickMemory(PString); |
2234 | 0 | return 0; |
2235 | 0 | } |
2236 | 0 | for (i=0; i < (ssize_t) count; i++) |
2237 | 0 | { |
2238 | 0 | c=ReadBlobByte(ifile); |
2239 | 0 | if (c == EOF) |
2240 | 0 | { |
2241 | 0 | str=(unsigned char *) RelinquishMagickMemory(str); |
2242 | 0 | PString=(unsigned char *) RelinquishMagickMemory(PString); |
2243 | 0 | return -1; |
2244 | 0 | } |
2245 | 0 | str[i]=(unsigned char) c; |
2246 | 0 | } |
2247 | | |
2248 | | /* we currently skip thumbnails, since it does not make |
2249 | | * any sense preserving them in a real world application |
2250 | | */ |
2251 | 0 | if (ID != THUMBNAIL_ID) |
2252 | 0 | { |
2253 | | /* now finish up by formatting this binary data into |
2254 | | * ASCII equivalent |
2255 | | */ |
2256 | 0 | if (strlen((const char *)PString) > 0) |
2257 | 0 | (void) FormatLocaleString(temp,MagickPathExtent,"8BIM#%d#%s=",ID, |
2258 | 0 | PString); |
2259 | 0 | else |
2260 | 0 | (void) FormatLocaleString(temp,MagickPathExtent,"8BIM#%d=",ID); |
2261 | 0 | (void) WriteBlobString(ofile,temp); |
2262 | 0 | if (ID == IPTC_ID) |
2263 | 0 | { |
2264 | 0 | formatString(ofile, "IPTC", 4); |
2265 | 0 | formatIPTCfromBuffer(ofile, (char *)str, (ssize_t) count); |
2266 | 0 | } |
2267 | 0 | else |
2268 | 0 | formatString(ofile, (char *)str, (ssize_t) count); |
2269 | 0 | } |
2270 | 0 | str=(unsigned char *) RelinquishMagickMemory(str); |
2271 | 0 | PString=(unsigned char *) RelinquishMagickMemory(PString); |
2272 | 0 | resCount++; |
2273 | 0 | c=ReadBlobByte(ifile); |
2274 | 0 | } |
2275 | 0 | return resCount; |
2276 | 0 | } |
2277 | | |
2278 | | static MagickBooleanType WriteMETAImage(const ImageInfo *image_info, |
2279 | | Image *image,ExceptionInfo *exception) |
2280 | 0 | { |
2281 | 0 | const StringInfo |
2282 | 0 | *profile; |
2283 | |
|
2284 | 0 | MagickBooleanType |
2285 | 0 | status; |
2286 | |
|
2287 | 0 | size_t |
2288 | 0 | length; |
2289 | | |
2290 | | /* |
2291 | | Open image file. |
2292 | | */ |
2293 | 0 | assert(image_info != (const ImageInfo *) NULL); |
2294 | 0 | assert(image_info->signature == MagickCoreSignature); |
2295 | 0 | assert(image != (Image *) NULL); |
2296 | 0 | assert(image->signature == MagickCoreSignature); |
2297 | 0 | if (IsEventLogging() != MagickFalse) |
2298 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
2299 | 0 | if (LocaleCompare(image_info->magick,"8BIM") == 0) |
2300 | 0 | { |
2301 | | /* |
2302 | | Write 8BIM image. |
2303 | | */ |
2304 | 0 | profile=GetImageProfile(image,"8bim"); |
2305 | 0 | if (profile == (StringInfo *) NULL) |
2306 | 0 | ThrowWriterException(CoderError,"No8BIMDataIsAvailable"); |
2307 | 0 | assert(exception != (ExceptionInfo *) NULL); |
2308 | 0 | assert(exception->signature == MagickCoreSignature); |
2309 | 0 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); |
2310 | 0 | if (status == MagickFalse) |
2311 | 0 | return(status); |
2312 | 0 | (void) WriteBlob(image,GetStringInfoLength(profile), |
2313 | 0 | GetStringInfoDatum(profile)); |
2314 | 0 | (void) CloseBlob(image); |
2315 | 0 | return(MagickTrue); |
2316 | 0 | } |
2317 | 0 | if (LocaleCompare(image_info->magick,"iptc") == 0) |
2318 | 0 | { |
2319 | 0 | unsigned char |
2320 | 0 | *info; |
2321 | |
|
2322 | 0 | profile=GetImageProfile(image,"iptc"); |
2323 | 0 | if (profile == (StringInfo *) NULL) |
2324 | 0 | profile=GetImageProfile(image,"8bim"); |
2325 | 0 | if (profile == (StringInfo *) NULL) |
2326 | 0 | ThrowWriterException(CoderError,"No8BIMDataIsAvailable"); |
2327 | 0 | assert(exception != (ExceptionInfo *) NULL); |
2328 | 0 | assert(exception->signature == MagickCoreSignature); |
2329 | 0 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); |
2330 | 0 | if (status == MagickFalse) |
2331 | 0 | return(status); |
2332 | 0 | info=GetStringInfoDatum(profile); |
2333 | 0 | length=GetStringInfoLength(profile); |
2334 | 0 | length=GetIPTCStream(&info,length); |
2335 | 0 | if (length == 0) |
2336 | 0 | ThrowWriterException(CoderError,"NoIPTCProfileAvailable"); |
2337 | 0 | (void) WriteBlob(image,length,info); |
2338 | 0 | (void) CloseBlob(image); |
2339 | 0 | return(MagickTrue); |
2340 | 0 | } |
2341 | 0 | if (LocaleCompare(image_info->magick,"8BIMTEXT") == 0) |
2342 | 0 | { |
2343 | 0 | Image |
2344 | 0 | *buff; |
2345 | |
|
2346 | 0 | profile=GetImageProfile(image,"8bim"); |
2347 | 0 | if (profile == (StringInfo *) NULL) |
2348 | 0 | ThrowWriterException(CoderError,"No8BIMDataIsAvailable"); |
2349 | 0 | assert(exception != (ExceptionInfo *) NULL); |
2350 | 0 | assert(exception->signature == MagickCoreSignature); |
2351 | 0 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); |
2352 | 0 | if (status == MagickFalse) |
2353 | 0 | return(status); |
2354 | 0 | buff=AcquireImage((ImageInfo *) NULL,exception); |
2355 | 0 | if (buff == (Image *) NULL) |
2356 | 0 | ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); |
2357 | 0 | AttachBlob(buff->blob,GetStringInfoDatum(profile), |
2358 | 0 | GetStringInfoLength(profile)); |
2359 | 0 | format8BIM(buff,image); |
2360 | 0 | (void) DetachBlob(buff->blob); |
2361 | 0 | buff=DestroyImage(buff); |
2362 | 0 | (void) CloseBlob(image); |
2363 | 0 | return(MagickTrue); |
2364 | 0 | } |
2365 | 0 | if (LocaleCompare(image_info->magick,"8BIMWTEXT") == 0) |
2366 | 0 | return(MagickFalse); |
2367 | 0 | if (LocaleCompare(image_info->magick,"IPTCTEXT") == 0) |
2368 | 0 | { |
2369 | 0 | Image |
2370 | 0 | *buff; |
2371 | |
|
2372 | 0 | unsigned char |
2373 | 0 | *info; |
2374 | |
|
2375 | 0 | profile=GetImageProfile(image,"8bim"); |
2376 | 0 | if (profile == (StringInfo *) NULL) |
2377 | 0 | ThrowWriterException(CoderError,"No8BIMDataIsAvailable"); |
2378 | 0 | info=GetStringInfoDatum(profile); |
2379 | 0 | length=GetStringInfoLength(profile); |
2380 | 0 | length=GetIPTCStream(&info,length); |
2381 | 0 | if (length == 0) |
2382 | 0 | ThrowWriterException(CoderError,"NoIPTCProfileAvailable"); |
2383 | 0 | assert(exception != (ExceptionInfo *) NULL); |
2384 | 0 | assert(exception->signature == MagickCoreSignature); |
2385 | 0 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); |
2386 | 0 | if (status == MagickFalse) |
2387 | 0 | return(status); |
2388 | 0 | buff=AcquireImage((ImageInfo *) NULL,exception); |
2389 | 0 | if (buff == (Image *) NULL) |
2390 | 0 | ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); |
2391 | 0 | AttachBlob(buff->blob,info,length); |
2392 | 0 | formatIPTC(buff,image); |
2393 | 0 | (void) DetachBlob(buff->blob); |
2394 | 0 | buff=DestroyImage(buff); |
2395 | 0 | (void) CloseBlob(image); |
2396 | 0 | return(MagickTrue); |
2397 | 0 | } |
2398 | 0 | if (LocaleCompare(image_info->magick,"IPTCWTEXT") == 0) |
2399 | 0 | return(MagickFalse); |
2400 | 0 | if ((LocaleCompare(image_info->magick,"APP1") == 0) || |
2401 | 0 | (LocaleCompare(image_info->magick,"EXIF") == 0) || |
2402 | 0 | (LocaleCompare(image_info->magick,"XMP") == 0)) |
2403 | 0 | { |
2404 | | /* |
2405 | | (void) Write APP1 image. |
2406 | | */ |
2407 | 0 | profile=GetImageProfile(image,image_info->magick); |
2408 | 0 | if (profile == (StringInfo *) NULL) |
2409 | 0 | ThrowWriterException(CoderError,"NoAPP1DataIsAvailable"); |
2410 | 0 | assert(exception != (ExceptionInfo *) NULL); |
2411 | 0 | assert(exception->signature == MagickCoreSignature); |
2412 | 0 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); |
2413 | 0 | if (status == MagickFalse) |
2414 | 0 | return(status); |
2415 | 0 | (void) WriteBlob(image,GetStringInfoLength(profile), |
2416 | 0 | GetStringInfoDatum(profile)); |
2417 | 0 | (void) CloseBlob(image); |
2418 | 0 | return(MagickTrue); |
2419 | 0 | } |
2420 | 0 | if ((LocaleCompare(image_info->magick,"ICC") == 0) || |
2421 | 0 | (LocaleCompare(image_info->magick,"ICM") == 0)) |
2422 | 0 | { |
2423 | | /* |
2424 | | Write ICM image. |
2425 | | */ |
2426 | 0 | profile=GetImageProfile(image,"icc"); |
2427 | 0 | if (profile == (StringInfo *) NULL) |
2428 | 0 | ThrowWriterException(CoderError,"NoColorProfileIsAvailable"); |
2429 | 0 | assert(exception != (ExceptionInfo *) NULL); |
2430 | 0 | assert(exception->signature == MagickCoreSignature); |
2431 | 0 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); |
2432 | 0 | if (status == MagickFalse) |
2433 | 0 | return(status); |
2434 | 0 | (void) WriteBlob(image,GetStringInfoLength(profile), |
2435 | 0 | GetStringInfoDatum(profile)); |
2436 | 0 | (void) CloseBlob(image); |
2437 | 0 | return(MagickTrue); |
2438 | 0 | } |
2439 | 0 | return(MagickFalse); |
2440 | 0 | } |