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