/*******************************************************************/
/*                                                                 */
/*                      ADOBE CONFIDENTIAL                         */
/*                   _ _ _ _ _ _ _ _ _ _ _ _ _                     */
/*                                                                 */
/* Copyright 1993 - 1999 Adobe Systems Incorporated                */
/* All Rights Reserved.                                            */
/*                                                                 */
/* NOTICE:  All information contained herein is, and remains the   */
/* property of Adobe Systems Incorporated and its suppliers, if    */
/* any.  The intellectual and technical concepts contained         */
/* herein are proprietary to Adobe Systems Incorporated and its    */
/* suppliers and may be covered by U.S. and Foreign Patents,       */
/* patents in process, and are protected by trade secret or        */
/* copyright law.  Dissemination of this information or            */
/* reproduction of this material is strictly forbidden unless      */
/* prior written permission is obtained from Adobe Systems         */
/* Incorporated.                                                   */
/*                                                                 */
/*******************************************************************/
//-------------------------------------------------------------------
//-------------------------------------------------------------------------------
//
//	File:
//		CryTIFPlugin.h
//
//	Description:
//		This file contains the header prototypes and macros for the
//		File Format module CryTIFPlugin, 
//		which writes a flat file with merged document pixels.
//
//	Use:
//		Format modules are called from the Save, Save as,
//		and Save a copy dialogs.
//
//	Version history:
//		Version 1.0.0	1/1/1993	Created for Photoshop 3.0.
//			Written by Mark Hamburg
//
//		Version 2.0.0	5/27/1996	Updated for Photoshop 4.0.
//			Scripting added.
//
//		Version 2.1.0	6/28/1997	Updated for Photoshop 4.0.1.
//			Updated for new version of Photoshop and projects
//			moved to CodeWarrior Pro.
//
//-------------------------------------------------------------------------------

//-------------------------------------------------------------------------------
//	Includes
//-------------------------------------------------------------------------------

#include "PIDefines.h"
#include "CryTIFPlugin.h"
#include <stdio.h>														// sprintf()
#include <assert.h>														// assert()

#include "../Win/ResourceCompilerLink.h"

#define	__STDC__															// needed to compile TIFFLib together with AdobeSDK
#include "../Win/TiffLib/include/tiffio.h"		// TIFF library
#include "PIProperties.h"											// propURL,prop...
#include "../Win/RegTools.h"									// Registry stuff for the resource compiler

#define REG_APPNAME		"CryTIFPlugin"






char g_szFileName[512]={0};		// without path, 512 is enough as Photoshop max path is 256

//-------------------------------------------------------------------------------
//	Prototypes
//-------------------------------------------------------------------------------

static void DoReadPrepare (GPtr globals);
static void DoReadStart (GPtr globals);
static void DoReadContinue (GPtr globals);
static void DoReadFinish (GPtr globals);
static void DoOptionsPrepare (GPtr globals);
static void DoOptionsStart (GPtr globals);
static void DoOptionsContinue (GPtr globals);
static void DoOptionsFinish (GPtr globals);
static void DoEstimatePrepare (GPtr globals);
static void DoEstimateStart (GPtr globals);
static void DoEstimateContinue (GPtr globals);
static void DoEstimateFinish (GPtr globals);
static void DoWritePrepare (GPtr globals);
static void DoWriteStart (GPtr globals);
static void DoWriteContinue (GPtr globals);
static void DoWriteFinish (GPtr globals);
static void DoFilterFile (GPtr globals);

static void AddComment (GPtr globals);

static Boolean CheckForServices (GPtr globals);
static int32 RowBytes (GPtr globals);
static Boolean AllocatePixelBuffer (GPtr globals);
static void DisposePixelBuffer(GPtr globals);
static void ShowAboutDialog();

static void DisposeImageResources (GPtr globals);

//-------------------------------------------------------------------------------
//	Globals -- Define global variables for plug-in scope.
//-------------------------------------------------------------------------------

// Windows global for plug-in (considered a Dynamically Linked Library).
// Leave NULL for Macintosh; many cross-platform library utilities require
// something passed in for hDllInstance:
HANDLE hDllInstance = NULL;

//-------------------------------------------------------------------------------
//
//	PluginMain / main
//
//	All calls to the plug-in module come through this routine.
//	It must be placed first in the resource.  To achieve this,
//	most development systems require this be the first routine
//	in the source.
//
//	The entrypoint will be "pascal void" for Macintosh,
//	"void" for Windows.
//
//	Inputs:
//		const short selector						Host provides selector indicating
//													what command to do.
//
//		FormatRecord *formatParamBlock				Host provides pointer to parameter
//													block containing pertinent data
//													and callbacks from the host.
//													See PIFormat.h.
//
//	Outputs:
//		FormatRecord *formatParamBlock				Host provides pointer to parameter
//													block containing pertinent data
//													and callbacks from the host.
//													See PIFormat.h.
//
//		long *data									Use this to store a handle to our
//													global parameters structure, which
//													is maintained by the host between
//													calls to the plug-in.
//
//		short *result								Return error result or noErr.  Some
//													errors are handled by the host, some
//													are silent, and some you must handle.
//													See PIGeneral.h.
//
//-------------------------------------------------------------------------------

DLLExport MACPASCAL void PluginMain (const short selector,
						             FormatRecord *formatParamBlock,
						             long *data,
						             short *result)
{
	//---------------------------------------------------------------------------
	//	(1) Enter code resource if Mac 68k.
	//---------------------------------------------------------------------------
	
	#ifdef UseA4				// Are we in 68k Mac MW?
		EnterCodeResource(); 	// A4-globals
	#endif
	
	//---------------------------------------------------------------------------
	//	(2) Check for about box request.
	//
	// 	The about box is a special request; the parameter block is not filled
	// 	out, none of the callbacks or standard data is available.  Instead,
	// 	the parameter block points to an AboutRecord, which is used
	// 	on Windows.
	//---------------------------------------------------------------------------

	if (selector == formatSelectorAbout)
	{
		ShowAboutDialog();
//		DoAbout((AboutRecordPtr)formatParamBlock);
	}
	else
	{ // do the rest of the process as normal:

		//-----------------------------------------------------------------------
		//	(3) Initialize function and global pointers.
		//
		// 	Initialize function pointer routine dispatcher. We use this to jump
		// 	to the different routines, instead of a long obnoxious switch
		// 	statement.  All routines are expected to have the same prototype
		// 	of "void RoutineName (globals)".  Returns any errors in gResult.
		//
		// 	WARNING: These better be in the order of the selector AND there
		// 	better be a routine for every selector call.
		//-----------------------------------------------------------------------
		
	 	static const FProc routineForSelector [] =
		{
			/* formatSelectorAbout  				DoAbout, */
			
			/* formatSelectorReadPrepare */			DoReadPrepare,
			/* formatSelectorReadStart */			DoReadStart,
			/* formatSelectorReadContinue */		DoReadContinue,
			/* formatSelectorReadFinish */			DoReadFinish,
			
			/* formatSelectorOptionsPrepare */		DoOptionsPrepare,
			/* formatSelectorOptionsStart */		DoOptionsStart,
			/* formatSelectorOptionsContinue */		DoOptionsContinue,
			/* formatSelectorOptionsFinish */		DoOptionsFinish,
			
			/* formatSelectorEstimatePrepare */		DoEstimatePrepare,
			/* formatSelectorEstimateStart */		DoEstimateStart,
			/* formatSelectorEstimateContinue */	DoEstimateContinue,
			/* formatSelectorEstimateFinish */		DoEstimateFinish,
			
			/* formatSelectorWritePrepare */		DoWritePrepare,
			/* formatSelectorWriteStart */			DoWriteStart,
			/* formatSelectorWriteContinue */		DoWriteContinue,
			/* formatSelectorWriteFinish */			DoWriteFinish,
			
			/* formatSelectorFilterFile */			DoFilterFile
		};
		
		Ptr globalPtr = NULL;		// Pointer for global structure
		GPtr globals = NULL; 		// actual globals

		//-----------------------------------------------------------------------
		//	(4) Allocate and initalize globals.
		//
		// 	AllocateGlobals requires the pointer to result, the pointer to the
		// 	parameter block, a pointer to the handle procs, the size of our local
		// 	"Globals" structure, a pointer to the long *data, a Function
		// 	Proc (FProc) to the InitGlobals routine.  It automatically sets-up,
		// 	initializes the globals (if necessary), results result to 0, and
		// 	returns with a valid pointer to the locked globals handle or NULL.
		//-----------------------------------------------------------------------
		
		globalPtr = AllocateGlobals ((uint32)result,
									 (uint32)formatParamBlock,
									 formatParamBlock->handleProcs,
									 sizeof(Globals),
						 			 data,
						 			 InitGlobals);
		
		if (globalPtr == NULL)
		{ // Something bad happened if we couldn't allocate our pointer.
		  // Fortunately, everything's already been cleaned up,
		  // so all we have to do is report an error.
		  
		  *result = memFullErr;
		  return;
		}
		
		// Get our "globals" variable assigned as a Global Pointer struct with the
		// data we've returned:
		globals = (GPtr)globalPtr;

		//-----------------------------------------------------------------------
		//	(5) Dispatch selector.
		//-----------------------------------------------------------------------

		if (selector > formatSelectorAbout && selector <= formatSelectorFilterFile)
			(routineForSelector[selector-1])(globals); // dispatch using jump table
		else
			gResult = formatBadParameters;
			
		//-----------------------------------------------------------------------
		//	(6) Unlock data, and exit resource.
		//
		//	Result is automatically returned in *result, which is
		//	pointed to by gResult.
		//-----------------------------------------------------------------------	
		
		// unlock handle pointing to parameter block and data so it can move
		// if memory gets shuffled:
		if ((Handle)*data != NULL)
			PIUnlockHandle((Handle)*data);
	
	} // about selector special		
	
	#ifdef UseA4			// Are we in 68k Mac MW?
		ExitCodeResource(); // A4-globals
	#endif
	
} // end PluginMain

//-------------------------------------------------------------------------------
//
//	InitGlobals
//	
//	Initalize any global values here.  Called only once when global
//	space is reserved for the first time.
//
//	Inputs:
//		Ptr globalPtr		Standard pointer to a global structure.
//
//	Outputs:
//		Initializes any global values with their defaults.
//
//-------------------------------------------------------------------------------

void InitGlobals (Ptr globalPtr)
{	
	// create "globals" as a our struct global pointer so that any
	// macros work:
	GPtr globals = (GPtr)globalPtr;
	
	// Initialize global variables:
	gQueryForParameters = true;
	ValidateParameters (globals);
	
} // end InitGlobals

//-------------------------------------------------------------------------------
//
//	ValidateParameters
//
//	Initialize parameters to default values.
//
//	Inputs:
//		GPtr globals		Pointer to global structure.
//
//	Outputs:
//		gWhatShape			Default: iShapeTriangle.
//
//		gCreate				Default: iCreateSelection.
//
//		gIdleAmount			Default: 2.0 seconds.
//
//-------------------------------------------------------------------------------

void ValidateParameters (GPtr globals)
{
	gPixelBuffer = NULL;
	gPixelData = NULL;
	
	gRowBytes = 0;
	
	gFooRead = false;
	gBarWrite = true;
	
	PIResetString(gHistory);

} // end ValidateParameters




/*****************************************************************************/

static Boolean CheckForServices (GPtr globals)
{
	return WarnBufferProcsAvailable () &&
		   WarnAdvanceStateAvailable ();
	// handle procs have upgraded for 6.0 but we want to run in 5.5
	// WarnHandleProcsAvailable ();
}

/*****************************************************************************/

static int32 RowBytes( GPtr globals )
{
	return gStuff->planes *( (gStuff->imageSize.h * (int32) gStuff->depth + 7) >> 3 );
}

/*****************************************************************************/

static Boolean AllocatePixelBuffer (GPtr globals)
{
	BufferID buffer;
	
	if (gResult != noErr) return FALSE;

	/* We will want a buffer that is one line wide. */
	
	gPixelBuffer = 0;
	
	gRowBytes = RowBytes (globals);
	
	if (!TSR (AllocateBuffer (gRowBytes, &buffer))) return FALSE;
	
	gPixelBuffer = buffer;
	
	gPixelData = LockBuffer (gPixelBuffer, FALSE);
	
	return TRUE;
}

/*****************************************************************************/

static void DisposePixelBuffer( GPtr globals )
{
	if(gPixelBuffer)
	{
		FreeBuffer(gPixelBuffer);
		
		gPixelBuffer = 0;
		gPixelData = 0;
	}
}

/*****************************************************************************/

static void DoReadPrepare (GPtr globals)
{
	gStuff->maxData = 0;		// we don't need andy extra memory from photoshop
}


/*****************************************************************************/

static void DisposeImageResources( GPtr globals )
{
	if(gStuff->imageRsrcData)
	{
		PIDisposeHandle (gStuff->imageRsrcData);
		gStuff->imageRsrcData = NULL;
		gStuff->imageRsrcSize = 0;
	}
}



/*****************************************************************************/
// get the file name as C string
static const char *GetFileName( GPtr globals )
{
	// convert Pascal string to C++ string
	static char szFileName[2048];

	strncpy(szFileName,(char *)&gStuff->fileSpec->name[1],*gStuff->fileSpec->name);
	szFileName[*gStuff->fileSpec->name]=0;
	return szFileName;

//	return g_szFileName;		// DoOptionsStart() needs to be called before
}


/*****************************************************************************/
// start the loading of the TIFF file
static void DoReadStart( GPtr globals )
{
	assert(!globals->m_pTiffFile);

	globals->m_pTiffFile = TIFFOpen(GetFileName(globals),"r");

	if(globals->m_pTiffFile) 
	{
		uint16 wWidth, wHeight,wPlanes;

		TIFFGetField(globals->m_pTiffFile, TIFFTAG_IMAGEWIDTH, &wWidth);
		TIFFGetField(globals->m_pTiffFile, TIFFTAG_IMAGELENGTH, &wHeight);
		TIFFGetField(globals->m_pTiffFile, TIFFTAG_SAMPLESPERPIXEL, &wPlanes);

		if(wPlanes==1)
			wPlanes=3;			// luminance only become RGB

		gStuff->imageMode = plugInModeRGBColor;	//	Bitmap=0; Grayscale=1; Indexed=2; RGB=3 Multichannel=7; Duotone=8; Lab=9.
		gStuff->imageSize.h = wWidth;
		gStuff->imageSize.v = wHeight;
		gStuff->depth = 8;
		gStuff->planes = wPlanes;

		// meta data
		{	
			char *pPtr;
			unsigned int wc;

			if(TIFFGetField(globals->m_pTiffFile,TIFFTAG_PHOTOSHOP,&wc,&pPtr))
			{
				Handle complex = PINewHandle(wc);

				if(complex != NULL)					// got a handle.
				{
					char *pPtr2 = PILockHandle(complex, FALSE);			assert(pPtr2);

					if(pPtr2)
					{
						memcpy(pPtr2,pPtr,wc);

						PIUnlockHandle(complex);

						gStuff->imageRsrcData=complex;
						gStuff->imageRsrcSize=wc;
					}
					else PIDisposeHandle(complex);
				}
			}
		}

		gResult=noErr;							// file can be loaded
	}
	else gResult = formatCannotRead;		// file cannot be loaded
}

/*****************************************************************************/

static void DoReadContinue (GPtr globals)
{
	assert(globals->m_pTiffFile);

	int32 done,total;

	uint32 dwWidth = gStuff->imageSize.h;
	uint32 dwHeight = gStuff->imageSize.v;
	uint32 dwPlanes = gStuff->planes;

	// Dispose of the image resource data if it exists.
	DisposeImageResources (globals);

	// Set up the progress variables.
	done=0;total=dwPlanes*dwHeight;

	// Next, we will allocate the pixel buffer (one line)
	AllocatePixelBuffer(globals);

	// Set up to start returning chunks of data
	gStuff->theRect.left = 0;
	gStuff->theRect.right = gStuff->imageSize.h;
	gStuff->colBytes = (gStuff->depth + 7) >> 3;
	gStuff->rowBytes = gRowBytes;
	gStuff->planeBytes = 0;
	gStuff->data = gPixelData;
	if (gStuff->depth == 16)
		gStuff->maxValue = 0x8000;

	size_t npixels = dwWidth * dwHeight;
	uint32* raster = (uint32*) _TIFFmalloc((tsize_t)(npixels * sizeof (uint32)));

	if(raster) 
	{
		if(TIFFReadRGBAImage(globals->m_pTiffFile, dwWidth, dwHeight, raster, 0)) 
		{
			for(uint32 row = 0; gResult == noErr && row < dwHeight; ++row)
			{
				gStuff->theRect.top = (int16)row;
				gStuff->theRect.bottom = (int16)row+1;

				unsigned char *pSrc = (unsigned char *)&raster[dwWidth*(dwHeight-1-row)];

				for(uint32 dwPlaneNo=0;dwPlaneNo<dwPlanes;++dwPlaneNo)					// plane
				{
					gStuff->loPlane = gStuff->hiPlane = (uint16)dwPlaneNo;

					unsigned char *Dst = (unsigned char *)gPixelData;

					for(uint32 dwI=0;dwI<dwWidth;++dwI)
						*Dst++=pSrc[dwI*4+dwPlaneNo];

					gResult=AdvanceState();

					if(gResult!=noErr)
					{
						_TIFFfree(raster);
						gStuff->data = NULL;
						DisposePixelBuffer(globals);
						return;
					}

					UpdateProgress (++done, total);
				}
			}
		}

		_TIFFfree(raster);raster=0;
	}


	gStuff->data = NULL;
	DisposePixelBuffer(globals);
}

/*****************************************************************************/

static void DoReadFinish( GPtr globals )
{
	assert(globals->m_pTiffFile);

	TIFFClose(globals->m_pTiffFile); globals->m_pTiffFile=0;

	/* Dispose of the image resource data if it exists. */
	
	DisposeImageResources (globals);
	WriteScriptParamsOnRead (globals); // should be different for read/write
	AddComment (globals); // write a history comment
}

/*****************************************************************************/

static void DoOptionsPrepare( GPtr globals )
{
	gStuff->maxData = 0;
}

/*****************************************************************************/


static void DoOptionsStart( GPtr globals )
{
	/* Check for the needed services. */

	// get filename
	{
		char *filepath = (char *)&globals->formatParamBlock->fileSpec->name[1];

		char *p=filepath, *szNameStart=filepath;

		while(*p!=0)
		{
			if(*p==':' || *p=='/' || *p=='\\')
				szNameStart=p+1;

			++p;
		}

		strcpy(g_szFileName,szNameStart);
	}

	if (!TSC ((Boolean)(!CheckForServices (globals)))) return;

	gStuff->data = NULL;
}

/*****************************************************************************/

static void DoOptionsContinue (GPtr globals)
{
	#ifdef __PIMWCW__
		#pragma unused (globals) // remove this when you write this routine
	#endif
}

/*****************************************************************************/

static void DoOptionsFinish (GPtr globals)
{
	#ifdef __PIMWCW__
		#pragma unused (globals) // remove this when you write this routine
	#endif
}

/*****************************************************************************/

static void DoEstimatePrepare (GPtr globals)
{
	gStuff->maxData = 0;

}

/*****************************************************************************/

static void DoEstimateStart (GPtr globals)
{
/*	int32 dataBytes;
	
	// Check for the needed services.
	
	if (!TSC ((Boolean)(!CheckForServices (globals)))) return;

	dataBytes = sizeof (FileHeader) +
				gStuff->imageRsrcSize +
				RowBytes (globals) * gStuff->planes * gStuff->imageSize.v;
					  
	if (gStuff->imageMode == plugInModeIndexedColor)
		dataBytes += 3 * sizeof (LookUpTable);
		
	gStuff->minDataBytes = dataBytes;
	gStuff->maxDataBytes = dataBytes;
	
	gStuff->data = NULL;
*/
}

/*****************************************************************************/

static void DoEstimateContinue (GPtr globals)
{
	#ifdef __PIMWCW__
		#pragma unused (globals) // remove this when you write this routine
	#endif
}

/*****************************************************************************/

static void DoEstimateFinish (GPtr globals)
{
	#ifdef __PIMWCW__
		#pragma unused (globals) // remove this when you write this routine
	#endif
}

/*****************************************************************************/

static void DoWritePrepare( GPtr globals )
{
	gStuff->maxData = 0;	
}



#include "../win/CryTIFPlugin-sym.h"








// \param szSpecialInstructions zero terminted string,must not be 0
void GlobalsToProperties( GPtr globals, unsigned char *szSpecialInstructions )
{
	assert(szSpecialInstructions);
/*
	{
		Handle complex;

		GetComplex(propCaption,0,&complex);

		if(complex)
		{
			char *pPtr2 = PILockHandle(complex, FALSE);

			PIUnlockHandle (complex);
		}
	}
*/
	char pPtr[100];

	pPtr[0]=28;
	pPtr[1]=2;
	pPtr[2]=40;		// SpecialInstructions

	// size
	pPtr[3]=0;
	pPtr[4]=3;

	pPtr[5]='A';
	pPtr[6]='b';
	pPtr[7]='c';

	Handle complex = PINewHandle (8);

	char *pPtr2 = PILockHandle(complex, FALSE);

	memcpy(pPtr2,pPtr,8);

	PIUnlockHandle (complex);

	//	Handle complex = PIPString2Handle((const unsigned char *)pPtr);

	if (complex != NULL)
	{ // got a handle.
		PutComplex(propCaption,0, complex);		// 40=SpecialInstructions
		PIDisposeHandle(complex);
		complex = NULL;
	}
/*
	{
		Handle complex;

		GetComplex(propCaption,0,&complex);

		if(complex)
		{
			char *pPtr2 = PILockHandle(complex, FALSE);

			PIUnlockHandle (complex);
		}
	}
*/
}



/*****************************************************************************/

// Tags
//   0=unknown
//   120=Caption
//   122=CaptionWriter
//   105=Headline
//   40=SpecialInstructions
// free data with delete
// \return 0 if failed, zero terminated string otherwise
static unsigned char *GetSpecialInstructionsFromPhotoshopCaption( unsigned char *pPtr, unsigned int dwSize )
{
	for(unsigned int i=0;i<dwSize;)
	{
		// 0x28 0x2 Tag SizeHi SizeLow

		if(dwSize-i>3																																							// at least 5 bytes to go
			&& pPtr[i]==28 && pPtr[i+1]==2)																													// starts with the right header
		{
			unsigned char Tag = (unsigned char)pPtr[i+2];																						// tag number

			unsigned short wSize = (((unsigned short)pPtr[i+3])<<8) | ((unsigned short)pPtr[i+4]);	// size

			i+=5;

			if(Tag==40)		// special instructions
			{
				unsigned char *pRet=new unsigned char[wSize+1];

				memcpy(pRet,(char *)&pPtr[i],wSize);
				pRet[wSize]=0;

				return pRet;
			}

			i+=wSize;
		}
		else
		{
			assert(0);		// unknown format
		}
	}

	return 0;
}

/*****************************************************************************/
// free data with delete
// \return 0 if failed, zero terminated string otherwise
static unsigned char *GetSpecialInstructionsFromTIFF( TIFF *tif )
{
	// get image metadata
	{
		unsigned char *pPtr;
		unsigned int wc;

		if(TIFFGetField(tif,TIFFTAG_PHOTOSHOP,&wc,&pPtr))		// 34377 IPTC TAG
		{
			unsigned char *pPtrEnd = pPtr + wc;

			while(pPtr!=pPtrEnd)
			{
				if(pPtr[0]=='8' && pPtr[1]=='B' && pPtr[2]=='I' && pPtr[3]=='M')
				{
					pPtr+=4;

					unsigned short Id = ((unsigned short)(pPtr[0])<<8) | (unsigned short)pPtr[1];

					pPtr+=2;

					// get pascal string 
					unsigned int dwNameSize = (unsigned int)pPtr[0];

					pPtr++;

					char szName[256];

					strncpy(szName,(char *)pPtr,dwNameSize);
					szName[dwNameSize]=0;

					//					OutputDebugString("Tag:");
					//					OutputDebugString(szName);
					//					OutputDebugString(": ");

					pPtr+=dwNameSize;

					// align 2 bytes
					if((dwNameSize%2)==0)
						pPtr++;

					unsigned int dwSize = ((unsigned int)(pPtr[0])<<24) | ((unsigned int)(pPtr[1])<<16) | ((unsigned int)(pPtr[2])<<8) |(unsigned int)pPtr[3];
					pPtr+=4;

					if(strcmp(szName,"Caption")==0)
						return GetSpecialInstructionsFromPhotoshopCaption((unsigned char *)pPtr,dwSize);

					pPtr+=dwSize;

					// align 2 bytes
					if((dwSize%2)!=0)
						pPtr++;
				}
				else
				{
					assert(0);
				}
			}
		}
	}

	return 0;
}

/*****************************************************************************/
// free data with delete
// \return 0 if failed, zero terminated string otherwise
static unsigned char *GetSpecialInstructionsFromFile( const char *lpszPathName )
{
	TIFF* tif = TIFFOpen(lpszPathName,"r");

	if(tif) 
	{
		unsigned char * pRet = GetSpecialInstructionsFromTIFF(tif);

		TIFFClose(tif);

		return pRet;
	}

	return 0;
}


/*****************************************************************************/

BOOL CALLBACK WndProcDriverDialog(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{
	case WM_COMMAND:
		switch(LOWORD(wParam))
		{
			/*		case IDC_HELPMGA:
			MessageBox(0,"the 4k tech test is free to copy\nadditional information can be found at www.4Kelvin.de\n4Kelvin - just a bit of it - (tech test) alpha","4K Info Window",MB_OK|MB_ICONINFORMATION);
			return(TRUE);

			case IDC_TRYGAME:
			SystemTimer.SetFlagLetTimeGo(FALSE);
			MyConfig.StartedInMode=2;
			MyConfig.fStartIt=TRUE;PlayMode=1;MyConfig.FlagEditMode=FALSE;
			MyConfig.FlagRender3DScene=FALSE;
			MyConfig.FlagMouseAbsoluteMode=TRUE;
			MyConfig.FlagPaintMenu=TRUE;
			ActualPlayerMenu=&prenotingamemenu;           // Aktuelles Menü setzten
			PostQuitMessage(0);
			return(TRUE);

			case IDC_OBJEDIT:
			MyConfig.StartedInMode=0;
			MyConfig.fStartIt=TRUE;PlayMode=0;MyConfig.FlagEditMode=TRUE;
			MyConfig.FlagRender3DScene=TRUE;
			MyConfig.FlagPaintMenu=FALSE;
			MyConfig.FlagMouseAbsoluteMode=FALSE;
			ActualPlayerMenu=&mymenu;           // Aktuelles Menü setzten
			PostQuitMessage(0);
			return(TRUE);
			*/
		case IDOK:							// Ok
			{
				char RCExePath[1024];

				GetWindowText(GetDlgItem(hwnd,IDC_RC_PATH),RCExePath,1024);
				SetDataToRegistry(REG_APPNAME,RCExePath,IsDlgButtonChecked(hwnd,IDC_SHOWCONSOLEWINDOW)!=0,IsDlgButtonChecked(hwnd,IDC_HIDECUSTOM)!=0);
			}
			PostQuitMessage(0);
			return TRUE;

		case IDCANCEL:
			PostQuitMessage(0);
			return TRUE;
			/*
			case IDC_DRIVERNAME:
			if(HIWORD(wParam)==CBN_SELCHANGE)
			{
			ReleaseDirect3D();
			GetDriverFromCombo();
			RefreshResolutionsList();
			return(TRUE);
			}
			*/
		}
		return 0L;

	case WM_CLOSE:
		PostQuitMessage(0);
		return(TRUE);
	}

	return(FALSE);
}

/*****************************************************************************/

static void ShowAboutDialog()
{
	HWND hParent = ::GetActiveWindow();

	CallResourceCompilerUI(hParent);

	/*HWND hParent = ::GetActiveWindow();

	HWND hOptionsWnd = CreateDialog((HINSTANCE)hDllInstance,MAKEINTRESOURCE(FORMATPARAMS),hParent,&WndProcDriverDialog);

	bool bShowWindow=false, bHideCustom=true;		// defaults

	SetWindowText(GetDlgItem(hOptionsWnd,IDC_RC_PATH),GetDataFromRegistry(REG_APPNAME,bShowWindow,bHideCustom));

	CheckDlgButton(hOptionsWnd,IDC_SHOWCONSOLEWINDOW,bShowWindow);
	CheckDlgButton(hOptionsWnd,IDC_HIDECUSTOM,bHideCustom);
	

	ShowWindow(hOptionsWnd,SW_SHOW);

	MSG msg;

	// Pre Message Loop
	while(GetMessage(&msg, NULL, 0U, 0U))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	DestroyWindow(hOptionsWnd);*/
}



/*****************************************************************************/
static void DoWriteStart( GPtr globals )
{
	assert(!globals->m_pTiffFile);

	if( gStuff->depth!=8
	|| (gStuff->imageMode!=plugInModeRGBColor && gStuff->imageMode!=plugInModeGrayScale)	//	Bitmap=0; Grayscale=1; Indexed=2; RGB=3 Multichannel=7; Duotone=8; Lab=9.
	|| (gStuff->planes!=1 && gStuff->planes!=3 && gStuff->planes!=4))		// grey,RGB,RGBA
	{
		Str255 errString = "*the input format is currently not supported";

		errString[0]=strlen((char *)&errString[1]);	// pascal string, could be done better

		gResult = PIReportError(errString);
		return;
	}

	globals->m_pTiffFile = TIFFOpen(GetFileName(globals),"w");

	if(globals->m_pTiffFile) 
	{
		uint32 dwWidth = gStuff->imageSize.h;
		uint32 dwHeight = gStuff->imageSize.v;
		uint32 dwPlanes = gStuff->planes;
		uint32 dwBitsPerSample = 8;

		int32 done=0, total=dwHeight*dwPlanes;

		// We need to set some values for basic tags before we can add any data
		TIFFSetField(globals->m_pTiffFile, TIFFTAG_IMAGEWIDTH, dwWidth);
		TIFFSetField(globals->m_pTiffFile, TIFFTAG_IMAGELENGTH, dwHeight);	
		TIFFSetField(globals->m_pTiffFile, TIFFTAG_SAMPLESPERPIXEL, dwPlanes);
		TIFFSetField(globals->m_pTiffFile, TIFFTAG_BITSPERSAMPLE, 8); 
		TIFFSetField(globals->m_pTiffFile, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize( globals->m_pTiffFile, -1 ) ); 
		TIFFSetField(globals->m_pTiffFile, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
		TIFFSetField(globals->m_pTiffFile, TIFFTAG_PHOTOMETRIC, gStuff->planes==1?PHOTOMETRIC_MINISBLACK:PHOTOMETRIC_RGB);
		TIFFSetField(globals->m_pTiffFile, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
		TIFFSetField(globals->m_pTiffFile, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);

		// image meta data
		if(gStuff->imageRsrcData)
		{
			char *pPtr = PILockHandle(gStuff->imageRsrcData, FALSE);

			unsigned int wc=gStuff->imageRsrcSize;

			// Tag  contains  Photoshop captioning information and
			// metadata. Photoshop uses  in  parallel  and  redun­
			// dantly alongside IPTCNEWSPHOTO information.
			TIFFSetField(globals->m_pTiffFile, TIFFTAG_PHOTOSHOP, wc, pPtr);		// 34377 IPTC TAG

			PIUnlockHandle(gStuff->imageRsrcData);
		}


		// Next, we will allocate the pixel buffer
		AllocatePixelBuffer (globals);

		gStuff->theRect.left = 0;
		gStuff->theRect.right = (short)dwWidth;
		gStuff->colBytes = (short)((dwBitsPerSample + 7) >> 3);
		gStuff->rowBytes = dwWidth*dwBitsPerSample/8;
		gStuff->planeBytes = 0;
		gStuff->data = gPixelData;
		gStuff->loPlane=0;
		gStuff->hiPlane=(int16)dwPlanes;

		size_t npixels = dwWidth * dwHeight;
		uint8 *raster = (uint8*) _TIFFmalloc((tsize_t)(npixels * sizeof (uint32)));


		for(uint32 row = 0; gResult == noErr && row < dwHeight; ++row)
		{
			gStuff->theRect.top = (int16)row;
			gStuff->theRect.bottom = (int16)row+1;

			for(uint32 dwPlaneNo=0;dwPlaneNo<dwPlanes;++dwPlaneNo)					// plane
			{
				unsigned char *pDst = &raster[dwWidth*row*dwPlanes] + dwPlaneNo;

				gStuff->loPlane = gStuff->hiPlane = (uint16)dwPlaneNo;

				gResult=AdvanceState();

				if(gResult!=noErr)
				{
					_TIFFfree(raster);
					gStuff->data = NULL;
					DisposePixelBuffer(globals);
					return;
				}

				unsigned char *pSrc = (unsigned char *)gPixelData;

				for(uint32 dwI=0;dwI<dwWidth;++dwI)
				{
					*pDst=pSrc[dwI];pDst+=dwPlanes;
				}
	
				UpdateProgress(++done, total);
			}
			int err = TIFFWriteScanline(globals->m_pTiffFile, &raster[dwWidth*row*dwPlanes], row, 0);
			assert( err >= 0 );

		}


		//TIFFWriteEncodedStrip(globals->m_pTiffFile,0,raster,dwWidth*dwHeight*dwPlanes);		// ABGR
		
		_TIFFfree(raster);raster=0;

		gResult=noErr;							// file was saved successfully
	}
	else gResult = writErr;		// file cannot be saved

	gStuff->data = NULL;
	DisposePixelBuffer(globals);

	assert(globals->m_pTiffFile);

	TIFFClose(globals->m_pTiffFile); globals->m_pTiffFile=0;


	char szoptions[521];

	sprintf(szoptions,"\"/overwritefilename=%s\" /overwriteextension=tif",g_szFileName);

//	if(!InvokeResourceCompiler(GetFileName(globals),"/overwriteextension=tif"))
	if(!InvokeResourceCompiler(GetFileName(globals),szoptions))
	{
		ShowAboutDialog();
		return;
	}

	/*
		Str255 errString = "*failed to start rc.exe";

		errString[0]=strlen((char *)&errString[1]);	// pascal string, could be done better

		gResult = PIReportError(errString);
		return;
	}*/

/*	// read back the special instructions
	{
		unsigned char *pSpecialInstructions = GetSpecialInstructionsFromFile(GetFileName(globals));	

		if(pSpecialInstructions)
		{
			// debug
			OutputDebugString("\nRead back SpecialInstructions from TIFF: '");
			OutputDebugString((char *)pSpecialInstructions);		
			OutputDebugString("'\n");

//			GlobalsToProperties(globals,pSpecialInstructions);

			delete pSpecialInstructions;
		}
		else
		{
			// no special instructions included
		}
	}
*/
}

/*****************************************************************************/

static void DoWriteContinue( GPtr globals )
{
	assert(!globals->m_pTiffFile);

	#ifdef __PIMWCW__
		#pragma unused (globals) // remove this when you write this routine
	#endif
}

/*****************************************************************************/

static void DoWriteFinish( GPtr globals )
{
	assert(!globals->m_pTiffFile);

	WriteScriptParamsOnWrite (globals); // should be different for read/write
}

/*****************************************************************************/

static void DoFilterFile( GPtr globals )
{
	// check if the file s a valid TIFF file

	TIFF* tif = TIFFOpen(GetFileName(globals),"r");

	if(tif) 
	{
		TIFFClose(tif);
		gResult=noErr;							// file can be loaded
		return;					
	}

	gResult = formatCannotRead;		// file cannot be loaded
}

/*****************************************************************************/

/* This routine adds a history entry to the file when incoming. */

static void AddComment (GPtr globals)
{
	/* We will attempt to add a resource showing that we made this change. */
	
	Str255 s, s0;
	Handle h;
	
	if (!ResourceProcsAvailable (NULL))
		return;
		
	PIGetString(kHistoryEntry, s);
	// Pulls a pascal string from the resource tree.
	
	NumToString(gStuff->dataFork, s0);
	// Need some unique data for this entry
	
	PIParamText(s, s0, NULL, NULL);

	h = PIPString2Handle(s);
		
	if (h != NULL)
	{
		PILockHandle(h, FALSE);
		(void) AddPIResource (histResource, h);
		PIUnlockHandle(h);
		PIDisposeHandle(h);
		h = NULL;
	}
	
	if (gHistory[0] > 0)
	{ // we had an old history.  Write that back out, as well.
		h = PIPString2Handle(gHistory);
		
		if (h != NULL)
		{ // got our handle. Write it out.
			gHistory[ (gHistory[0]=0)+1 ] = 0; // clear string
			PILockHandle(h, FALSE);
			(void) AddPIResource (histResource, h);
			PIUnlockHandle(h);
			PIDisposeHandle(h);
			h = NULL;
		}
	} // no earlier history
} // end AddComment


