1 /* ************************************************************************** */
2 /* *                                                                        * */
3 /* * COPYRIGHT NOTICE:                                                      * */
4 /* *                                                                        * */
5 /* * Copyright (c) 2000-2002 Gerard Juyn (gerard@libmng.com)                * */
6 /* * [You may insert additional notices after this sentence if you modify   * */
7 /* *  this source]                                                          * */
8 /* *                                                                        * */
9 /* * For the purposes of this copyright and license, "Contributing Authors" * */
10 /* * is defined as the following set of individuals:                        * */
11 /* *                                                                        * */
12 /* *    Gerard Juyn                                                         * */
13 /* *    (hopefully some more to come...)                                    * */
14 /* *                                                                        * */
15 /* * The MNG Library is supplied "AS IS".  The Contributing Authors         * */
16 /* * disclaim all warranties, expressed or implied, including, without      * */
17 /* * limitation, the warranties of merchantability and of fitness for any   * */
18 /* * purpose.  The Contributing Authors assume no liability for direct,     * */
19 /* * indirect, incidental, special, exemplary, or consequential damages,    * */
20 /* * which may result from the use of the MNG Library, even if advised of   * */
21 /* * the possibility of such damage.                                        * */
22 /* *                                                                        * */
23 /* * Permission is hereby granted to use, copy, modify, and distribute this * */
24 /* * source code, or portions hereof, for any purpose, without fee, subject * */
25 /* * to the following restrictions:                                         * */
26 /* *                                                                        * */
27 /* * 1. The origin of this source code must not be misrepresented;          * */
28 /* *    you must not claim that you wrote the original software.            * */
29 /* *                                                                        * */
30 /* * 2. Altered versions must be plainly marked as such and must not be     * */
31 /* *    misrepresented as being the original source.                        * */
32 /* *                                                                        * */
33 /* * 3. This Copyright notice may not be removed or altered from any source * */
34 /* *    or altered source distribution.                                     * */
35 /* *                                                                        * */
36 /* * The Contributing Authors specifically permit, without fee, and         * */
37 /* * encourage the use of this source code as a component to supporting     * */
38 /* * the MNG and JNG file format in commercial products.  If you use this   * */
39 /* * source code in a product, acknowledgment would be highly appreciated.  * */
40 /* *                                                                        * */
41 /* ************************************************************************** */
42 /* *                                                                        * */
43 /* * project   : mngrepair                                                  * */
44 /* * file      : mngrepair.cpp             copyright (c) 2002 G.Juyn        * */
45 /* * version   : 1.0.0                                                      * */
46 /* *                                                                        * */
47 /* * purpose   : main project file                                          * */
48 /* *                                                                        * */
49 /* * author    : G.Juyn                                                     * */
50 /* * web       : http://www.3-t.com                                         * */
51 /* * email     : mailto:info@3-t.com                                        * */
52 /* *                                                                        * */
53 /* * comment   : mngrepair iterates tries to fix a couple of 'common'       * */
54 /* *             MNG encoding errors (such as in JASC Animation Shop)       * */
55 /* *                                                                        * */
56 /* * changes   :                                                            * */
57 /* *                                                                        * */
58 /* ************************************************************************** */
59 
60 #define HAVE_BOOLEAN
61 
62 #include <windows.h>
63 #pragma hdrstop
64 #include <condefs.h>
65 
66 #include "libmng.h"
67 
68 /* ************************************************************************** */
69 
70 USERES("mngrepair.res");
71 USEUNIT("..\..\libmng_hlapi.c");
72 USEUNIT("..\..\libmng_callback_xs.c");
73 USEUNIT("..\..\libmng_prop_xs.c");
74 USEUNIT("..\..\libmng_chunk_xs.c");
75 USEUNIT("..\..\libmng_object_prc.c");
76 USEUNIT("..\..\libmng_chunk_prc.c");
77 USEUNIT("..\..\libmng_chunk_io.c");
78 USEUNIT("..\..\libmng_read.c");
79 USEUNIT("..\..\libmng_write.c");
80 USEUNIT("..\..\libmng_display.c");
81 USEUNIT("..\..\libmng_dither.c");
82 USEUNIT("..\..\libmng_pixels.c");
83 USEUNIT("..\..\libmng_filter.c");
84 USEUNIT("..\..\libmng_error.c");
85 USEUNIT("..\..\libmng_trace.c");
86 USEUNIT("..\..\libmng_cms.c");
87 USEUNIT("..\..\libmng_zlib.c");
88 USEUNIT("..\..\libmng_jpeg.c");
89 USEUNIT("..\..\..\zlib\adler32.c");
90 USEUNIT("..\..\..\zlib\compress.c");
91 USEUNIT("..\..\..\zlib\crc32.c");
92 USEUNIT("..\..\..\zlib\deflate.c");
93 USEUNIT("..\..\..\zlib\infblock.c");
94 USEUNIT("..\..\..\zlib\infcodes.c");
95 USEUNIT("..\..\..\zlib\inffast.c");
96 USEUNIT("..\..\..\zlib\inflate.c");
97 USEUNIT("..\..\..\zlib\inftrees.c");
98 USEUNIT("..\..\..\zlib\infutil.c");
99 USEUNIT("..\..\..\zlib\trees.c");
100 USEUNIT("..\..\..\zlib\uncompr.c");
101 USEUNIT("..\..\..\zlib\zutil.c");
102 //---------------------------------------------------------------------------
103 typedef struct user_struct {
104 
105           FILE        *hFileI;         /* input file handle */
106           FILE        *hFileO;         /* output file handle */
107           mng_handle  hHandleI;        /* input mng handle */
108           mng_handle  hHandleO;        /* output mng handle */
109           mng_bool    bHasSAVE;        /* indicates a SAVE in the input */
110           mng_bool    bHasTERM;        /* indicates we saved the TERM */
111           mng_bool    bIsJASC;         /* indicates if this is an AS file */
112           mng_chunkid iLastchunk;      /* last processed chunk */
113           mng_retcode iError;          /* errorcode from function in callback */
114           mng_uint8   iTermaction;     /* saved TERM parameters */
115           mng_uint8   iIteraction;
116           mng_uint32  iDelay;
117           mng_uint32  iItermax;
118 
119         } userdata;
120 
121 typedef userdata * userdatap;
122 
123 /* ************************************************************************** */
124 
125 #define MY_DECL                        /* get the right callback convention */
126 
127 /* ************************************************************************** */
128 
myalloc(mng_size_t iSize)129 mng_ptr MY_DECL myalloc (mng_size_t iSize)
130 {                                      /* duh! */
131   return (mng_ptr)calloc (1, (size_t)iSize);
132 }
133 
134 /* ************************************************************************** */
135 
136 #pragma argsused
myfree(mng_ptr pPtr,mng_size_t iSize)137 void MY_DECL myfree (mng_ptr pPtr, mng_size_t iSize)
138 {
139   free (pPtr);                         /* duh! */
140   return;
141 }
142 
143 /* ************************************************************************** */
144 
145 #pragma argsused
myopenstream(mng_handle hMNG)146 mng_bool MY_DECL myopenstream (mng_handle hMNG)
147 {
148   return MNG_TRUE;                     /* already opened in main function */
149 }
150 
151 /* ************************************************************************** */
152 
153 #pragma argsused
myclosestream(mng_handle hMNG)154 mng_bool MY_DECL myclosestream (mng_handle hMNG)
155 {
156   return MNG_TRUE;                     /* gets closed in main function */
157 }
158 
159 /* ************************************************************************** */
160 
myreaddata(mng_handle hMNG,mng_ptr pBuf,mng_uint32 iSize,mng_uint32 * iRead)161 mng_bool MY_DECL myreaddata (mng_handle hMNG,
162                              mng_ptr    pBuf,
163                              mng_uint32 iSize,
164                              mng_uint32 *iRead)
165 {                                      /* get to my file handle */
166   userdatap pMydata = (userdatap)mng_get_userdata (hMNG);
167                                        /* read it */
168   *iRead = fread (pBuf, 1, iSize, pMydata->hFileI);
169                                        /* iRead will indicate EOF */
170   return MNG_TRUE;
171 }
172 
173 /* ************************************************************************** */
174 
mywritedata(mng_handle hMNG,mng_ptr pBuf,mng_uint32 iSize,mng_uint32 * iWritten)175 mng_bool MY_DECL mywritedata (mng_handle hMNG,
176                               mng_ptr    pBuf,
177                               mng_uint32 iSize,
178                               mng_uint32 *iWritten)
179 {                                      /* get to my file handle */
180   userdatap pMydata = (userdatap)mng_get_userdata (hMNG);
181                                        /* write it */
182   *iWritten = fwrite (pBuf, 1, iSize, pMydata->hFileO);
183                                        /* iWritten will indicate errors */
184   return MNG_TRUE;
185 }
186 
187 /* ************************************************************************** */
188 
myprocesserror(mng_handle hMNG,mng_int32 iErrorcode,mng_int8 iSeverity,mng_chunkid iChunkname,mng_uint32 iChunkseq,mng_int32 iExtra1,mng_int32 iExtra2,mng_pchar zErrortext)189 mng_bool MY_DECL myprocesserror (mng_handle  hMNG,
190                                  mng_int32   iErrorcode,
191                                  mng_int8    iSeverity,
192                                  mng_chunkid iChunkname,
193                                  mng_uint32  iChunkseq,
194                                  mng_int32   iExtra1,
195                                  mng_int32   iExtra2,
196                                  mng_pchar   zErrortext)
197 {                                      /* sequence error for TERM we ignore ! */
198   if ((iErrorcode == MNG_SEQUENCEERROR) && (iChunkname == MNG_UINT_TERM))
199     return MNG_TRUE;
200 
201   return MNG_FALSE;                    /* all others get dumped ! */
202 }
203 
204 /* ************************************************************************** */
205 
206 #pragma argsused
myiterchunk(mng_handle hMNG,mng_handle hChunk,mng_chunkid iChunktype,mng_uint32 iChunkseq)207 mng_bool MY_DECL myiterchunk (mng_handle  hMNG,
208                               mng_handle  hChunk,
209                               mng_chunkid iChunktype,
210                               mng_uint32  iChunkseq)
211 {
212   mng_uint32  iWidth;                  /* temps for IHDR processing */
213   mng_uint32  iHeight;
214   mng_uint8   iBitdepth;
215   mng_uint8   iColortype;
216   mng_uint8   iCompression;
217   mng_uint8   iFilter;
218   mng_uint8   iInterlace;
219 
220   mng_bool    bEmpty;                  /* temps for FRAM processing */
221   mng_uint8   iMode;
222   mng_uint32  iNamesize;
223   mng_pchar   zName;
224   mng_uint8   iChangedelay;
225   mng_uint8   iChangetimeout;
226   mng_uint8   iChangeclipping;
227   mng_uint8   iChangesyncid;
228   mng_uint32  iDelay;
229   mng_uint32  iTimeout;
230   mng_uint8   iBoundarytype;
231   mng_int32   iBoundaryl;
232   mng_int32   iBoundaryr;
233   mng_int32   iBoundaryt;
234   mng_int32   iBoundaryb;
235   mng_uint32  iCount;
236   mng_uint32p pSyncids;
237                                        /* get to my userdata */
238   userdatap  pMydata = (userdatap)mng_get_userdata (hMNG);
239 
240   if (pMydata->hFileO)                 /* are we writing this time ? */
241   {                                    /* do we need to 'forget' the TERM ? */
242     if ((iChunktype == MNG_UINT_TERM) && (pMydata->bHasTERM))
243       ;
244     else
245     {                                  /* fix JASC AS frame_type ? */
246       if ((iChunktype == MNG_UINT_FRAM) && (pMydata->bIsJASC))
247       {
248         if ((pMydata->iError = mng_getchunk_fram (hMNG, hChunk,
249                                                   &bEmpty, &iMode, &iNamesize, &zName,
250                                                   &iChangedelay, &iChangetimeout,
251                                                   &iChangeclipping, &iChangesyncid,
252                                                   &iDelay, &iTimeout, &iBoundarytype,
253                                                   &iBoundaryl, &iBoundaryr,
254                                                   &iBoundaryt, &iBoundaryb,
255                                                   &iCount, &pSyncids)) != 0)
256         {
257           fprintf (stderr, "Cannot get FRAM fields.\n");
258           return MNG_FALSE;            /* stop the process ! */
259         }
260 
261         if (iMode == 1)                /* really ? */
262           iMode = 3;
263 
264         if ((pMydata->iError = mng_putchunk_fram (pMydata->hHandleO,
265                                                   bEmpty, iMode, iNamesize, zName,
266                                                   iChangedelay, iChangetimeout,
267                                                   iChangeclipping, iChangesyncid,
268                                                   iDelay, iTimeout, iBoundarytype,
269                                                   iBoundaryl, iBoundaryr,
270                                                   iBoundaryt, iBoundaryb,
271                                                   iCount, pSyncids)) != 0)
272         {
273           fprintf (stderr, "Cannot write FRAM chunk.\n");
274           return MNG_FALSE;            /* stop the process ! */
275         }
276       }
277       else
278       {
279         if ((pMydata->iError = mng_copy_chunk (hMNG, hChunk, pMydata->hHandleO)) != 0)
280         {
281           fprintf (stderr, "Cannot copy the chunk.\n");
282           return MNG_FALSE;            /* stop the process ! */
283         }
284       }
285     }
286                                        /* need to insert TERM in the proper place ? */
287     if ((iChunktype == MNG_UINT_MHDR) && (pMydata->bHasTERM))
288     {
289       if ((pMydata->iError = mng_putchunk_term (pMydata->hHandleO,
290                                                 pMydata->iTermaction,
291                                                 pMydata->iIteraction,
292                                                 pMydata->iDelay,
293                                                 pMydata->iItermax)) != 0)
294       {
295         fprintf (stderr, "Cannot write TERM chunk.\n");
296         return MNG_FALSE;              /* stop the process ! */
297       }
298     }
299   }
300   else                                 /* first iteration; just checking stuff */
301   {
302     if (iChunktype == MNG_UINT_SAVE)  /* SAVE ? */
303     {
304       pMydata->bHasSAVE = MNG_TRUE;    /* we got a SAVE ! */
305       pMydata->bIsJASC  = MNG_FALSE;   /* so it's definitely not an invalid AS file */
306     }
307     else
308     {                                 /* TERM ? */
309       if (iChunktype == MNG_UINT_TERM)
310       {                               /* is it in the wrong place ? */
311         if ((pMydata->iLastchunk != MNG_UINT_MHDR) ||
312             (pMydata->iLastchunk != MNG_UINT_SAVE)    )
313         {
314           pMydata->bHasTERM = MNG_TRUE;
315 
316           if ((pMydata->iError = mng_getchunk_term (hMNG, hChunk,
317                                                     &pMydata->iTermaction,
318                                                     &pMydata->iIteraction,
319                                                     &pMydata->iDelay,
320                                                     &pMydata->iItermax)) != 0)
321           {
322             fprintf (stderr, "Cannot get TERM fields.\n");
323             return MNG_FALSE;          /* stop the process ! */
324           }
325         }
326       }
327       else
328       {                                /* IHDR ? */
329         if (iChunktype == MNG_UINT_IHDR)
330         {
331           if ((pMydata->iError = mng_getchunk_ihdr (hMNG, hChunk,
332                                                     &iWidth, &iHeight, &iBitdepth,
333                                                     &iColortype, &iCompression,
334                                                     &iFilter, &iInterlace)) != 0)
335           {
336             fprintf (stderr, "Cannot get IHDR fields.\n");
337             return MNG_FALSE;          /* stop the process ! */
338           }
339                                        /* is it not a typical JASC AS file */
340           if ((iBitdepth != 8) || (iColortype != 6))
341             pMydata->bIsJASC = MNG_FALSE;
342         }
343       }
344     }
345 
346     pMydata->iLastchunk = iChunktype;
347   }
348 
349   return MNG_TRUE;                     /* keep'm coming... */
350 }
351 
352 /* ************************************************************************** */
353 
fixit(char * zFilenameI,char * zFilenameO)354 int fixit (char * zFilenameI,
355            char * zFilenameO)
356 {
357   userdatap pMydata;
358   mng_retcode iRC;
359                                        /* get a data buffer */
360   pMydata = (userdatap)calloc (1, sizeof (userdata));
361 
362   if (pMydata == NULL)                 /* oke ? */
363   {
364     fprintf (stderr, "Cannot allocate a data buffer.\n");
365     return 1;
366   }
367 
368   pMydata->hFileO      = 0;            /* initialize some stuff! */
369   pMydata->hHandleI    = MNG_NULL;
370   pMydata->hHandleO    = MNG_NULL;
371   pMydata->bHasSAVE    = MNG_FALSE;
372   pMydata->bHasTERM    = MNG_FALSE;
373   pMydata->bIsJASC     = MNG_TRUE;
374   pMydata->iLastchunk  = MNG_UINT_HUH;
375   pMydata->iTermaction = 0;
376   pMydata->iIteraction = 0;
377   pMydata->iDelay      = 0;
378   pMydata->iItermax    = 0;
379                                        /* can we open the input file ? */
380   if ((pMydata->hFileI = fopen (zFilenameI, "rb")) == NULL)
381   {                                    /* error out if we can't */
382     fprintf (stderr, "Cannot open input file %s.\n", zFilenameI);
383     return 1;
384   }
385                                        /* let's initialize the library */
386   pMydata->hHandleI = mng_initialize ((mng_ptr)pMydata, myalloc, myfree, MNG_NULL);
387 
388   if (!pMydata->hHandleI)              /* did that work out ? */
389   {
390     fprintf (stderr, "Cannot initialize libmng.\n");
391     iRC = 1;
392   }
393   else
394   {                                    /* some informatory messages */
395     fprintf (stderr, "Compiled with libmng %s.\n", MNG_VERSION_TEXT);
396     fprintf (stderr, "Running with libmng %s.\n", mng_version_text());
397                                        /* setup callbacks */
398     if ( ((iRC = mng_setcb_openstream  (pMydata->hHandleI, myopenstream  )) != 0) ||
399          ((iRC = mng_setcb_closestream (pMydata->hHandleI, myclosestream )) != 0) ||
400          ((iRC = mng_setcb_readdata    (pMydata->hHandleI, myreaddata    )) != 0) ||
401          ((iRC = mng_setcb_errorproc   (pMydata->hHandleI, myprocesserror)) != 0)    )
402       fprintf (stderr, "Cannot set callbacks for libmng.\n");
403     else
404     {                                  /* reaad the file into memory */
405       if ((iRC = mng_read (pMydata->hHandleI)) != 0)
406         fprintf (stderr, "Cannot read the input file.\n");
407       else
408       {                                /* run through the chunk list to get TERM */
409         if ((iRC = mng_iterate_chunks (pMydata->hHandleI, 0, myiterchunk)) != 0)
410           fprintf (stderr, "Cannot iterate the chunks.\n");
411         else
412         {
413           if (pMydata->iError)         /* did the iteration fail somehow ? */
414             iRC = pMydata->iError;
415           else
416           {                            /* can we open the output file ? */
417             if ((pMydata->hFileO = fopen (zFilenameO, "wb")) == NULL)
418             {                            /* error out if we can't */
419               fprintf (stderr, "Cannot open output file %s.\n", zFilenameO);
420               iRC = 1;
421             }
422             else
423             {                          /* let's initialize the library */
424               pMydata->hHandleO = mng_initialize ((mng_ptr)pMydata, myalloc, myfree, MNG_NULL);
425 
426               if (!pMydata->hHandleO)  /* did that work out ? */
427               {
428                 fprintf (stderr, "Cannot initialize libmng.\n");
429                 iRC = 1;
430               }
431               else
432               {                        /* setup callbacks */
433                 if ( ((iRC = mng_setcb_openstream  (pMydata->hHandleO, myopenstream )) != 0) ||
434                      ((iRC = mng_setcb_closestream (pMydata->hHandleO, myclosestream)) != 0) ||
435                      ((iRC = mng_setcb_writedata   (pMydata->hHandleO, mywritedata  )) != 0)    )
436                   fprintf (stderr, "Cannot set callbacks for libmng.\n");
437                 else
438                 {
439                   if ((iRC = mng_create (pMydata->hHandleO)) != 0)
440                     fprintf (stderr, "Cannot create a new MNG.\n");
441                   else
442                   {                    /* run through the chunk again and create the new file */
443                     if ((iRC = mng_iterate_chunks (pMydata->hHandleI, 0, myiterchunk)) != 0)
444                       fprintf (stderr, "Cannot iterate the chunks.\n");
445                     else
446                     {                  /* did the iteration fail somehow ? */
447                       if (pMydata->iError)
448                         iRC = pMydata->iError;
449                       else
450                       {                /* now write the created new file !! */
451                         if ((iRC = mng_write (pMydata->hHandleO)) != 0)
452                           fprintf (stderr, "Cannot write the output file.\n");
453                       }
454                     }
455                   }
456                 }
457                                        /* cleanup the library */
458                 mng_cleanup (&pMydata->hHandleO);
459               }
460                                        /* cleanup output file */
461               fclose (pMydata->hFileO);
462             }
463           }
464         }
465       }
466     }
467 
468     mng_cleanup (&pMydata->hHandleI);  /* cleanup the library */
469   }
470 
471   fclose (pMydata->hFileI);            /* cleanup input file and userdata */
472   free (pMydata);
473 
474   return iRC;
475 }
476 
477 /* ************************************************************************** */
478 
main(int argc,char * argv[])479 int main(int argc, char *argv[])
480 {
481   if (argc > 2)                  /* need two (2) parameters ! */
482     return fixit (argv[1], argv[2]);
483   else
484     fprintf (stdout, "\nUsage: mngrepair <input.mng> <output.mng>\n\n");
485 
486   return 0;
487 }
488 
489 /* ************************************************************************** */
490