1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%                        X   X  TTTTT  RRRR   N   N                           %
7%                         X X     T    R   R  NN  N                           %
8%                          X      T    RRRR   N N N                           %
9%                         X X     T    R R    N  NN                           %
10%                        X   X    T    R  R   N   N                           %
11%                                                                             %
12%                                                                             %
13%                    ImageMagickObject BLOB Interface.                        %
14%                                                                             %
15%                              Software Design                                %
16%                             William Radcliffe                               %
17%                                 May 2001                                    %
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%  This coder is a kind of backdoor used by the COM object that allows it to  %
38%  pass blobs back and forth using the coder interface. It simply encodes and %
39%  decodes the filename as a comma delimited string and extracts the info it  %
40%  needs. The five methods of passing images are:                             %
41%                                                                             %
42%     FILE   - same thing as filename so it should be a NOP                   %
43%     IMAGE  - passes an image and image info structure                       %
44%     BLOB   - passes binary blob containining the image                      %
45%     STREAM - passes pointers to stream hooks in and does the hooking        %
46%     ARRAY  - passes a pointer to a Win32 smart array and streams to it      %
47%                                                                             %
48%  Of all of these, the only one getting any real use at the moment is the    %
49%  ARRAY handler. It is the primary way that images are shuttled back and     %
50%  forth as blobs via COM since this is what VB and VBSCRIPT use internally   %
51%  for this purpose.                                                          %
52%
53%
54*/
55
56/*
57  Include declarations.
58*/
59#include "MagickCore/studio.h"
60#include "MagickCore/blob.h"
61#include "MagickCore/blob-private.h"
62#include "MagickCore/constitute.h"
63#include "MagickCore/delegate.h"
64#include "MagickCore/exception.h"
65#include "MagickCore/exception-private.h"
66#include "MagickCore/image.h"
67#include "MagickCore/image-private.h"
68#include "MagickCore/list.h"
69#include "MagickCore/MagickCore.h"
70#include "MagickCore/memory_.h"
71#include "MagickCore/string_.h"
72#if defined(MAGICKCORE_WINDOWS_SUPPORT)
73#define WIN32_LEAN_AND_MEAN
74#define VC_EXTRALEAN
75#include <windows.h>
76#include <ole2.h>
77
78/*
79  Forward declarations.
80*/
81static MagickBooleanType
82  WriteXTRNImage(const ImageInfo *,Image *,ExceptionInfo *exception);
83#endif
84
85/*
86%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
87%                                                                             %
88%                                                                             %
89%                                                                             %
90%   R e a d X T R N I m a g e                                                 %
91%                                                                             %
92%                                                                             %
93%                                                                             %
94%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
95%
96%  ReadXTRNImage() reads a XTRN image file and returns it.  It
97%  allocates the memory necessary for the new Image structure and returns a
98%  pointer to the new image.
99%
100%  The format of the ReadXTRNImage method is:
101%
102%      Image *ReadXTRNImage(const ImageInfo *image_info,
103%        ExceptionInfo *exception)
104%
105%  A description of each parameter follows:
106%
107%    o image_info: Specifies a pointer to an ImageInfo structure.
108%
109%    o exception: return any errors or warnings in this structure.
110%
111*/
112#if defined(MAGICKCORE_WINDOWS_SUPPORT)
113#  pragma warning(disable : 4477)
114static Image *ReadXTRNImage(const ImageInfo *image_info,
115  ExceptionInfo *exception)
116{
117  Image
118    *image;
119
120  ImageInfo
121    *clone_info;
122
123  void
124    *param1,
125    *param2,
126    *param3;
127
128  param1 = param2 = param3 = (void *) NULL;
129  image = (Image *) NULL;
130  clone_info=CloneImageInfo(image_info);
131  if (clone_info->filename == NULL)
132    {
133      clone_info=DestroyImageInfo(clone_info);
134      ThrowReaderException(FileOpenWarning,"No filename specified");
135    }
136  if (LocaleCompare(image_info->magick,"XTRNFILE") == 0)
137    {
138      image=ReadImage(clone_info,exception);
139      CatchException(exception);
140    }
141  else if (LocaleCompare(image_info->magick,"XTRNIMAGE") == 0)
142    {
143      Image
144        **image_ptr;
145
146#ifdef ALL_IMAGEINFO
147      ImageInfo
148        **image_info_ptr;
149#endif
150
151      (void) sscanf(clone_info->filename,"%lx,%lx",&param1,&param2);
152      image_ptr=(Image **) param2;
153      if (*image_ptr != (Image *) NULL)
154        image=CloneImage(*image_ptr,0,0,MagickFalse,exception);
155#ifdef ALL_IMAGEINFO
156      image_info_ptr=(ImageInfo **) param1;
157      if (*image_info_ptr != (ImageInfo *) NULL)
158        image_info=*image_info_ptr;
159#endif
160    }
161  else if (LocaleCompare(image_info->magick,"XTRNBLOB") == 0)
162    {
163      char
164        **blob_data;
165
166      size_t
167        *blob_length;
168
169      char
170        filename[MagickPathExtent];
171
172      (void) sscanf(clone_info->filename,"%lx,%lx,%2048s",&param1,&param2,
173        filename);
174      blob_data=(char **) param1;
175      blob_length=(size_t *) param2;
176      image=BlobToImage(clone_info,*blob_data,*blob_length,exception);
177      CatchException(exception);
178    }
179  else if (LocaleCompare(image_info->magick,"XTRNARRAY") == 0)
180    {
181      char
182        *blob_data,
183        filename[MagickPathExtent];
184
185      HRESULT
186        hr;
187
188      long
189        lBoundl,
190        lBoundu;
191
192      SAFEARRAY
193        *pSafeArray;
194
195      size_t
196        blob_length;
197
198      *filename='\0';
199      (void) sscanf(clone_info->filename,"%lx,%2048s",&param1,filename);
200      hr=S_OK;
201      pSafeArray=(SAFEARRAY *) param1;
202      if (pSafeArray)
203        {
204          hr = SafeArrayGetLBound(pSafeArray, 1, &lBoundl);
205          if (SUCCEEDED(hr))
206            {
207              hr = SafeArrayGetUBound(pSafeArray, 1, &lBoundu);
208              if (SUCCEEDED(hr))
209                {
210                  blob_length = lBoundu - lBoundl + 1;
211                  hr = SafeArrayAccessData(pSafeArray,(void**) &blob_data);
212                  if(SUCCEEDED(hr))
213                    {
214                      *clone_info->filename='\0';
215                      *clone_info->magick='\0';
216                      if (*filename != '\0')
217                        (void) CopyMagickString(clone_info->filename,filename,
218                          MagickPathExtent);
219                      image=BlobToImage(clone_info,blob_data,blob_length,
220                        exception);
221                      hr=SafeArrayUnaccessData(pSafeArray);
222                      CatchException(exception);
223                    }
224                }
225            }
226        }
227    }
228  clone_info=DestroyImageInfo(clone_info);
229  return(image);
230}
231#  pragma warning(default : 4477)
232#endif
233
234/*
235%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
236%                                                                             %
237%                                                                             %
238%                                                                             %
239%   R e g i s t e r X T R N I m a g e                                         %
240%                                                                             %
241%                                                                             %
242%                                                                             %
243%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
244%
245%  RegisterXTRNImage() adds attributes for the XTRN image format to
246%  the list of supported formats.  The attributes include the image format
247%  tag, a method to read and/or write the format, whether the format
248%  supports the saving of more than one frame to the same file or blob,
249%  whether the format supports native in-memory I/O, and a brief
250%  description of the format.
251%
252%  The format of the RegisterXTRNImage method is:
253%
254%      size_t RegisterXTRNImage(void)
255%
256*/
257ModuleExport size_t RegisterXTRNImage(void)
258{
259  MagickInfo
260    *entry;
261
262  entry=AcquireMagickInfo("XTRN","XTRNFILE","External transfer of a file");
263#if defined(MAGICKCORE_WINDOWS_SUPPORT)
264  entry->decoder=ReadXTRNImage;
265  entry->encoder=WriteXTRNImage;
266#endif
267  entry->flags^=CoderAdjoinFlag;
268  entry->flags|=CoderStealthFlag;
269  RegisterMagickInfo(entry);
270  entry=AcquireMagickInfo("XTRN","XTRNIMAGE",
271    "External transfer of a image in memory");
272#if defined(MAGICKCORE_WINDOWS_SUPPORT)
273  entry->decoder=ReadXTRNImage;
274  entry->encoder=WriteXTRNImage;
275#endif
276  entry->flags^=CoderAdjoinFlag;
277  entry->flags|=CoderStealthFlag;
278  RegisterMagickInfo(entry);
279  entry=AcquireMagickInfo("XTRN","XTRNBLOB",
280    "IExternal transfer of a blob in memory");
281#if defined(MAGICKCORE_WINDOWS_SUPPORT)
282  entry->decoder=ReadXTRNImage;
283  entry->encoder=WriteXTRNImage;
284#endif
285  entry->flags^=CoderAdjoinFlag;
286  entry->flags|=CoderStealthFlag;
287  RegisterMagickInfo(entry);
288  entry=AcquireMagickInfo("XTRN","XTRNARRAY",
289    "External transfer via a smart array interface");
290#if defined(MAGICKCORE_WINDOWS_SUPPORT)
291  entry->decoder=ReadXTRNImage;
292  entry->encoder=WriteXTRNImage;
293#endif
294  entry->flags^=CoderAdjoinFlag;
295  entry->flags|=CoderStealthFlag;
296  RegisterMagickInfo(entry);
297  return(MagickImageCoderSignature);
298}
299
300/*
301%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
302%                                                                             %
303%                                                                             %
304%                                                                             %
305%   U n r e g i s t e r X T R N I m a g e                                     %
306%                                                                             %
307%                                                                             %
308%                                                                             %
309%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
310%
311%  UnregisterXTRNImage() removes format registrations made by the
312%  XTRN module from the list of supported formats.
313%
314%  The format of the UnregisterXTRNImage method is:
315%
316%      UnregisterXTRNImage(void)
317%
318*/
319ModuleExport void UnregisterXTRNImage(void)
320{
321  UnregisterMagickInfo("XTRNFILE");
322  UnregisterMagickInfo("XTRNIMAGE");
323  UnregisterMagickInfo("XTRNBLOB");
324  UnregisterMagickInfo("XTRNARRAY");
325}
326
327/*
328%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
329%                                                                             %
330%                                                                             %
331%                                                                             %
332%   W r i t e X T R N I m a g e                                               %
333%                                                                             %
334%                                                                             %
335%                                                                             %
336%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
337%
338%  WriteXTRNImage() writes an image in the XTRN encoded image format.
339%  We use GIF because it is the only format that is compressed without
340%  requiring additional optional delegates (TIFF, ZIP, etc).
341%
342%  The format of the WriteXTRNImage method is:
343%
344%      MagickBooleanType WriteXTRNImage(const ImageInfo *image_info,
345%        Image *image,ExceptionInfo *exception)
346%
347%  A description of each parameter follows.
348%
349%    o image_info: Specifies a pointer to an ImageInfo structure.
350%
351%    o image:  A pointer to a Image structure.
352%
353%    o exception: return any errors or warnings in this structure.
354%
355*/
356
357#if defined(MAGICKCORE_WINDOWS_SUPPORT)
358static size_t SafeArrayFifo(const Image *image,const void *data,
359  const size_t length)
360{
361  SAFEARRAYBOUND NewArrayBounds[1];  /* 1 Dimension */
362  size_t tlen=length;
363  SAFEARRAY *pSafeArray = (SAFEARRAY *)image->client_data;
364  if (pSafeArray != NULL)
365  {
366    long lBoundl, lBoundu, lCount;
367    HRESULT hr = S_OK;
368    /* First see how big the buffer currently is */
369    hr = SafeArrayGetLBound(pSafeArray, 1, &lBoundl);
370    if (FAILED(hr))
371      return MagickFalse;
372    hr = SafeArrayGetUBound(pSafeArray, 1, &lBoundu);
373    if (FAILED(hr))
374      return MagickFalse;
375    lCount = lBoundu - lBoundl + 1;
376
377    if (length>0)
378    {
379      unsigned char       *pReturnBuffer = NULL;
380      NewArrayBounds[0].lLbound = 0;   /* Start-Index 0 */
381      NewArrayBounds[0].cElements = (unsigned long) (length+lCount);  /* # Elemente */
382      hr = SafeArrayRedim(pSafeArray, NewArrayBounds);
383      if (FAILED(hr))
384        return 0;
385      hr = SafeArrayAccessData(pSafeArray, (void**)&pReturnBuffer);
386      if( FAILED(hr) )
387        return 0;
388      (void) memcpy(pReturnBuffer+lCount,(unsigned char *) data,length);
389      hr=SafeArrayUnaccessData(pSafeArray);
390      if(FAILED(hr))
391        return 0;
392    }
393    else
394    {
395      /* Adjust the length of the buffer to fit */
396    }
397  }
398  return(tlen);
399}
400#endif
401
402#if defined(MAGICKCORE_WINDOWS_SUPPORT)
403#  pragma warning(disable : 4477)
404static MagickBooleanType WriteXTRNImage(const ImageInfo *image_info,
405  Image *image,ExceptionInfo *exception)
406{
407  Image *
408    p;
409
410  ImageInfo
411    *clone_info;
412
413  int
414    scene;
415
416  MagickBooleanType
417    status;
418
419  void
420    *param1,
421    *param2,
422    *param3;
423
424  param1 = param2 = param3 = (void *) NULL;
425  status=MagickTrue;
426  if (LocaleCompare(image_info->magick,"XTRNFILE") == 0)
427    {
428      clone_info=CloneImageInfo(image_info);
429      *clone_info->magick='\0';
430      status=WriteImage(clone_info,image,exception);
431      if (status == MagickFalse)
432        CatchImageException(image);
433      clone_info=DestroyImageInfo(clone_info);
434    }
435  else if (LocaleCompare(image_info->magick,"XTRNIMAGE") == 0)
436    {
437      Image
438        **image_ptr;
439
440      ImageInfo
441        **image_info_ptr;
442
443      clone_info=CloneImageInfo(image_info);
444      if (clone_info->filename[0])
445        {
446          (void) sscanf(clone_info->filename,"%lx,%lx",&param1,&param2);
447          image_info_ptr=(ImageInfo **) param1;
448          image_ptr=(Image **) param2;
449          if ((image_info_ptr != (ImageInfo **) NULL) &&
450              (image_ptr != (Image **) NULL))
451            {
452              *image_ptr=CloneImage(image,0,0,MagickFalse,exception);
453              *image_info_ptr=clone_info;
454            }
455        }
456    }
457  else if (LocaleCompare(image_info->magick,"XTRNBLOB") == 0)
458    {
459      char
460        **blob_data;
461
462      size_t
463        *blob_length;
464
465      char
466        filename[MagickPathExtent];
467
468      clone_info=CloneImageInfo(image_info);
469      if (clone_info->filename[0])
470        {
471          (void) sscanf(clone_info->filename,"%lx,%lx,%2048s",
472            &param1,&param2,filename);
473
474          blob_data=(char **) param1;
475          blob_length=(size_t *) param2;
476          scene = 0;
477          (void) CopyMagickString(clone_info->filename,filename,
478            MagickPathExtent);
479          for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
480          {
481            (void) CopyMagickString(p->filename,filename,MagickPathExtent);
482            p->scene=scene++;
483          }
484          SetImageInfo(clone_info,1,exception);
485          (void) CopyMagickString(image->magick,clone_info->magick,
486            MagickPathExtent);
487          if (*blob_length == 0)
488            *blob_length=8192;
489          *blob_data=(char *) ImageToBlob(clone_info,image,blob_length,
490            exception);
491          if (*blob_data == NULL)
492            status=MagickFalse;
493          if (status == MagickFalse)
494            CatchImageException(image);
495        }
496      clone_info=DestroyImageInfo(clone_info);
497    }
498  else if (LocaleCompare(image_info->magick,"XTRNARRAY") == 0)
499    {
500      char
501        filename[MagickPathExtent];
502
503      size_t
504        blob_length;
505
506      unsigned char
507        *blob_data;
508
509      clone_info=CloneImageInfo(image_info);
510      if (*clone_info->filename != '\0')
511        {
512          (void) sscanf(clone_info->filename,"%lx,%2048s",&param1,filename);
513          image->client_data=param1;
514          scene=0;
515          (void) CopyMagickString(clone_info->filename,filename,
516            MagickPathExtent);
517          for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
518          {
519            (void) CopyMagickString(p->filename,filename,MagickPathExtent);
520            p->scene=scene++;
521          }
522          SetImageInfo(clone_info,1,exception);
523          (void) CopyMagickString(image->magick,clone_info->magick,
524            MagickPathExtent);
525          blob_data=ImageToBlob(clone_info,image,&blob_length,
526            exception);
527          if (blob_data == (unsigned char *) NULL)
528            status=MagickFalse;
529          else
530            SafeArrayFifo(image,blob_data,blob_length);
531          if (status == MagickFalse)
532            CatchImageException(image);
533        }
534      clone_info=DestroyImageInfo(clone_info);
535    }
536  return(MagickTrue);
537}
538#  pragma warning(default : 4477)
539#endif
540