1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%                  IIIII  N   N  L      IIIII  N   N  EEEEE                   %
7%                    I    NN  N  L        I    NN  N  E                       %
8%                    I    N N N  L        I    N N N  EEE                     %
9%                    I    N  NN  L        I    N  NN  E                       %
10%                  IIIII  N   N  LLLLL  IIIII  N   N  EEEEE                   %
11%                                                                             %
12%                                                                             %
13%                            Read Inline Images                               %
14%                                                                             %
15%                              Software Design                                %
16%                                   Cristy                                    %
17%                                 July 1992                                   %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2016 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%    http://www.imagemagick.org/script/license.php                            %
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/client.h"
46#include "MagickCore/constitute.h"
47#include "MagickCore/display.h"
48#include "MagickCore/exception.h"
49#include "MagickCore/exception-private.h"
50#include "MagickCore/image.h"
51#include "MagickCore/image-private.h"
52#include "MagickCore/list.h"
53#include "MagickCore/magick.h"
54#include "MagickCore/memory_.h"
55#include "MagickCore/option.h"
56#include "MagickCore/quantum-private.h"
57#include "MagickCore/static.h"
58#include "MagickCore/string_.h"
59#include "MagickCore/module.h"
60#include "MagickCore/utility.h"
61#include "MagickCore/xwindow.h"
62#include "MagickCore/xwindow-private.h"
63
64/*
65  Forward declarations.
66*/
67static MagickBooleanType
68  WriteINLINEImage(const ImageInfo *,Image *,ExceptionInfo *);
69
70/*
71%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
72%                                                                             %
73%                                                                             %
74%                                                                             %
75%   R e a d I N L I N E I m a g e                                             %
76%                                                                             %
77%                                                                             %
78%                                                                             %
79%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80%
81%  ReadINLINEImage() reads base64-encoded inlines images.
82%
83%  The format of the ReadINLINEImage method is:
84%
85%      Image *ReadINLINEImage(const ImageInfo *image_info,
86%        ExceptionInfo *exception)
87%
88%  A description of each parameter follows:
89%
90%    o image_info: the image info.
91%
92%    o exception: return any errors or warnings in this structure.
93%
94*/
95static Image *ReadINLINEImage(const ImageInfo *image_info,
96  ExceptionInfo *exception)
97{
98  Image
99    *image;
100
101  MagickBooleanType
102    status;
103
104  register size_t
105    i;
106
107  size_t
108    quantum;
109
110  ssize_t
111    count;
112
113  unsigned char
114    *inline_image;
115
116  /*
117    Open image file.
118  */
119  assert(image_info != (const ImageInfo *) NULL);
120  assert(image_info->signature == MagickCoreSignature);
121  if (image_info->debug != MagickFalse)
122    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
123      image_info->filename);
124  assert(exception != (ExceptionInfo *) NULL);
125  assert(exception->signature == MagickCoreSignature);
126  if (LocaleCompare(image_info->magick,"DATA") == 0)
127    {
128      char
129        *filename;
130
131      Image
132        *data_image;
133
134      filename=AcquireString("data:");
135      (void) ConcatenateMagickString(filename,image_info->filename,
136        MagickPathExtent);
137      data_image=ReadInlineImage(image_info,filename,exception);
138      filename=DestroyString(filename);
139      return(data_image);
140    }
141  image=AcquireImage(image_info,exception);
142  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
143  if (status == MagickFalse)
144    {
145      image=DestroyImageList(image);
146      return((Image *) NULL);
147    }
148  quantum=MagickMin((size_t) GetBlobSize(image),MagickMaxBufferExtent);
149  if (quantum == 0)
150    quantum=MagickMaxBufferExtent;
151  inline_image=(unsigned char *) AcquireQuantumMemory(quantum,
152    sizeof(*inline_image));
153  count=0;
154  for (i=0; inline_image != (unsigned char *) NULL; i+=count)
155  {
156    count=(ssize_t) ReadBlob(image,quantum,inline_image+i);
157    if (count <= 0)
158      {
159        count=0;
160        if (errno != EINTR)
161          break;
162      }
163    if (~((size_t) i) < (quantum+1))
164      {
165        inline_image=(unsigned char *) RelinquishMagickMemory(inline_image);
166        break;
167      }
168    inline_image=(unsigned char *) ResizeQuantumMemory(inline_image,i+count+
169      quantum+1,sizeof(*inline_image));
170  }
171  if (inline_image == (unsigned char *) NULL)
172    {
173      (void) ThrowMagickException(exception,GetMagickModule(),
174        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
175      return((Image *) NULL);
176    }
177  inline_image[i+count]='\0';
178  image=DestroyImageList(image);
179  image=ReadInlineImage(image_info,(char *) inline_image,exception);
180  inline_image=(unsigned char *) RelinquishMagickMemory(inline_image);
181  return(image);
182}
183
184/*
185%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
186%                                                                             %
187%                                                                             %
188%                                                                             %
189%   R e g i s t e r I N L I N E I m a g e                                     %
190%                                                                             %
191%                                                                             %
192%                                                                             %
193%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
194%
195%  RegisterINLINEImage() adds attributes for the INLINE image format to
196%  the list of supported formats.  The attributes include the image format
197%  tag, a method to read and/or write the format, whether the format
198%  supports the saving of more than one frame to the same file or blob,
199%  whether the format supports native in-memory I/O, and a brief
200%  description of the format.
201%
202%  The format of the RegisterINLINEImage method is:
203%
204%      size_t RegisterINLINEImage(void)
205%
206*/
207ModuleExport size_t RegisterINLINEImage(void)
208{
209  MagickInfo
210    *entry;
211
212  entry=AcquireMagickInfo("DATA","INLINE","Base64-encoded inline images");
213  entry->decoder=(DecodeImageHandler *) ReadINLINEImage;
214  entry->encoder=(EncodeImageHandler *) WriteINLINEImage;
215  entry->format_type=ImplicitFormatType;
216  (void) RegisterMagickInfo(entry);
217  entry=AcquireMagickInfo("INLINE","INLINE","Base64-encoded inline images");
218  entry->decoder=(DecodeImageHandler *) ReadINLINEImage;
219  entry->encoder=(EncodeImageHandler *) WriteINLINEImage;
220  entry->format_type=ImplicitFormatType;
221  (void) RegisterMagickInfo(entry);
222  return(MagickImageCoderSignature);
223}
224
225/*
226%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
227%                                                                             %
228%                                                                             %
229%                                                                             %
230%   U n r e g i s t e r I N L I N E I m a g e                                 %
231%                                                                             %
232%                                                                             %
233%                                                                             %
234%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
235%
236%  UnregisterINLINEImage() removes format registrations made by the
237%  INLINE module from the list of supported formats.
238%
239%  The format of the UnregisterINLINEImage method is:
240%
241%      UnregisterINLINEImage(void)
242%
243*/
244ModuleExport void UnregisterINLINEImage(void)
245{
246  (void) UnregisterMagickInfo("INLINE");
247  (void) UnregisterMagickInfo("DATA");
248}
249
250/*
251%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
252%                                                                             %
253%                                                                             %
254%                                                                             %
255%   W r i t e I N L I N E I m a g e                                           %
256%                                                                             %
257%                                                                             %
258%                                                                             %
259%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
260%
261%  WriteINLINEImage() writes an image to a file in INLINE format (Base64).
262%
263%  The format of the WriteINLINEImage method is:
264%
265%      MagickBooleanType WriteINLINEImage(const ImageInfo *image_info,
266%        Image *image,ExceptionInfo *exception)
267%
268%  A description of each parameter follows.
269%
270%    o image_info: the image info.
271%
272%    o image:  The image.
273%
274%    o exception: return any errors or warnings in this structure.
275%
276*/
277static MagickBooleanType WriteINLINEImage(const ImageInfo *image_info,
278  Image *image,ExceptionInfo *exception)
279{
280  char
281    *base64,
282    message[MagickPathExtent];
283
284  const MagickInfo
285    *magick_info;
286
287  Image
288    *write_image;
289
290  ImageInfo
291    *write_info;
292
293  MagickBooleanType
294    status;
295
296  size_t
297    blob_length,
298    encode_length;
299
300  unsigned char
301    *blob;
302
303  /*
304    Convert image to base64-encoding.
305  */
306  assert(image_info != (const ImageInfo *) NULL);
307  assert(image_info->signature == MagickCoreSignature);
308  assert(image != (Image *) NULL);
309  assert(image->signature == MagickCoreSignature);
310  if (image->debug != MagickFalse)
311    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
312  write_info=CloneImageInfo(image_info);
313  (void) SetImageInfo(write_info,1,exception);
314  if (LocaleCompare(write_info->magick,"INLINE") == 0)
315    (void) CopyMagickString(write_info->magick,image->magick,MagickPathExtent);
316  magick_info=GetMagickInfo(write_info->magick,exception);
317  if ((magick_info == (const MagickInfo *) NULL) ||
318      (GetMagickMimeType(magick_info) == (const char *) NULL))
319    ThrowWriterException(CorruptImageError,"ImageTypeNotSupported");
320  (void) CopyMagickString(image->filename,write_info->filename,
321    MagickPathExtent);
322  blob_length=2048;
323  write_image=CloneImage(image,0,0,MagickTrue,exception);
324  if (write_image == (Image *) NULL)
325    {
326      write_info=DestroyImageInfo(write_info);
327      return(MagickTrue);
328    }
329  blob=(unsigned char *) ImageToBlob(write_info,write_image,&blob_length,
330    exception);
331  write_image=DestroyImage(write_image);
332  write_info=DestroyImageInfo(write_info);
333  if (blob == (unsigned char *) NULL)
334    return(MagickFalse);
335  encode_length=0;
336  base64=Base64Encode(blob,blob_length,&encode_length);
337  blob=(unsigned char *) RelinquishMagickMemory(blob);
338  if (base64 == (char *) NULL)
339    ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
340  /*
341    Write base64-encoded image.
342  */
343  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
344  if (status == MagickFalse)
345    {
346      base64=DestroyString(base64);
347      return(status);
348    }
349  (void) FormatLocaleString(message,MagickPathExtent,"data:%s;base64,",
350    GetMagickMimeType(magick_info));
351  (void) WriteBlobString(image,message);
352  (void) WriteBlobString(image,base64);
353  base64=DestroyString(base64);
354  return(MagickTrue);
355}
356