graphicsdeviceinterface/gdi/sgdi/PRINTGDI.CPP
changeset 0 5d03bc08d59c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graphicsdeviceinterface/gdi/sgdi/PRINTGDI.CPP	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,906 @@
+// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include <gdi.h>
+#include <f32file.h>
+#include <s32file.h>
+#include <bautils.h>
+#include <barsc.h>
+#include <barsread.h>
+#include "GDIPANIC.h"
+
+_LIT(KPdrExtension,"*.PDR"); // must be capitalized
+_LIT(KPdlExtension,".PDL"); // must be capitalized
+_LIT(KUdlExtension,".UDL"); // must be capitalized
+_LIT(KRscExtension,".RSC");
+_LIT(KGdiPrintPanic,"GDI - PRINT");
+
+_LIT(KGDIPanicDesc1, "GDI Pdr internal Panic %S, in file %S @ line %i");
+_LIT(KGDIPanicDesc2, "Assert condition = \"%S\"");
+
+enum TPdrStorePanic
+	{
+	EPdrModelIndexOutOfRange,
+	EPdrModelUidNotFound,
+	EPdrDirectoryIndexOutOfRange,
+	EPdrFileIndexOutOfRange,
+	EPdrPrinterDeviceExists,
+	EPdrPrinterDeviceDoesNotExist,
+	};
+
+void Panic(TPdrStorePanic aPanic)
+	{
+	User::Panic(KGdiPrintPanic,aPanic);
+	}
+	
+void PanicWithCondAndInfo(TPdrStorePanic aError, const TDesC& aCondition, const TDesC& aFileName, const TDesC& aPanicName, TInt aLine)
+	{
+	TBuf<256> buf;
+	buf.Format(KGDIPanicDesc1, &aPanicName, &aFileName, aLine);
+	RDebug::Print(buf);
+
+	buf.Format(KGDIPanicDesc2, &aCondition);
+	RDebug::Print(buf);
+	Panic(aError);
+	}
+
+//
+// TPrinterModelEntry
+//
+
+
+EXPORT_C void TPrinterModelEntry::InternalizeL(RReadStream& aStream)
+
+/** Internalises a printer model entry from a read stream. 
+
+The presence of this function means that the standard templated stream operator>>(), 
+defined in s32strm.h, is available to internalise objects of this class.
+
+@param aStream The read stream. */
+    {
+	aStream >> iModelName;
+	iRequiresPrinterPort=aStream.ReadUint8L();
+	aStream >> iUid;
+	}
+
+
+EXPORT_C void TPrinterModelEntry::ExternalizeL(RWriteStream& aStream) const
+/** Externalises the printer model entry to a write stream.
+
+The presence of this function means that the standard templated stream operator<<(), 
+defined in s32strm.h, is available to externalise objects of this class.
+
+@param aStream The write stream. */
+	{
+	aStream << iModelName;
+	aStream.WriteUint8L((TUint8) iRequiresPrinterPort);
+	aStream << iUid;
+	}
+
+//
+// TPrinterModelHeader
+//
+
+
+EXPORT_C void TPrinterModelHeader::InternalizeL(RReadStream& aStream)
+/** Internalises a printer model header from a read stream. 
+
+The presence of this function means that the standard templated stream operator>>(), 
+defined in s32strm.h, is available to internalise objects of this class.
+
+@param aStream The read stream. */
+ 	{
+	aStream >> iEntry;
+	aStream >> iModelDataStreamId;
+	}
+
+
+EXPORT_C void TPrinterModelHeader::ExternalizeL(RWriteStream& aStream) const
+ 
+/** Externalises the printer model header to a write stream.
+
+The presence of this function means that the standard templated stream operator<<(), 
+defined in s32strm.h, is available to externalise objects of this class.
+@param aStream The write stream. */
+    {
+	aStream << iEntry;
+	aStream << iModelDataStreamId;
+	}
+
+//
+// CPrinterDevice
+//
+
+EXPORT_C CPrinterDevice::CPrinterDevice():
+	CGraphicsDevice(),
+	iCurrentPageSpecInTwips()
+/** Standard constructor. */
+	{}
+
+
+EXPORT_C CPrinterDevice::~CPrinterDevice()
+
+/** Destructor.
+It frees all resources owned by the object, prior to its destruction. */
+	{
+	delete iControl;
+	}
+
+
+EXPORT_C void CPrinterDevice::SelectPageSpecInTwips(const TPageSpec& aPageSpecInTwips)
+/** Sets the page specification in twips.
+@param  aPageSpec The page specification in twips. */	
+    {
+	iCurrentPageSpecInTwips=aPageSpecInTwips;
+	}
+
+
+EXPORT_C TRect CPrinterDevice::PrintablePageInPixels() const
+/** Gets the dimensions of the area to which the printer device can print.
+
+These dimensions are normally less than those returned by TPageSpec::OrientedPageSize() 
+because a margin exists between the boundary of the printable page and the 
+absolute extent of the page.
+
+@return The dimensions of the printer device area in pixels, respecting the 
+page orientation */
+	{
+	return TRect(SizeInPixels());
+	}
+
+
+EXPORT_C void CPrinterDevice::DeleteControl()
+ /** Deletes the printer control owned by this object.
+
+The function sets the iControl member to NULL. */
+    {
+	delete iControl;
+	iControl=NULL;
+	}
+
+
+EXPORT_C void CPrinterDevice::RestorePropertiesL()
+/** Restores printer properties. */	
+    {
+	_LIT(KSystemIniFileNameSpec,"Z:\\System\\System.ini");
+
+	RFs fs;
+	User::LeaveIfError(fs.Connect());
+	CleanupClosePushL(fs);
+	
+	TDriveUnit drive(static_cast<TUint>(RFs::GetSystemDrive()));
+	TParse systemIniFileName;
+	systemIniFileName.Set(drive.Name(), &KSystemIniFileNameSpec, NULL);
+	
+	TUint atts = 0;
+	TInt ret = fs.Att(systemIniFileName.FullName(), atts);
+	if (ret == KErrNone)
+		{
+		CDictionaryStore* dictionarystore = NULL;
+		TRAPD(err,dictionarystore = CDictionaryFileStore::SystemL(fs));
+		if (err == KErrNone)
+			{
+			CleanupStack::PushL(dictionarystore);
+			if (dictionarystore->IsPresentL(Model().iUid))
+				{
+				RDictionaryReadStream stream;
+				stream.OpenLC(*dictionarystore,Model().iUid);
+				InternalizePropertiesL(stream);
+				CleanupStack::PopAndDestroy(); // stream
+				}
+			CleanupStack::PopAndDestroy(); // dictionarystore
+			}
+		}
+	CleanupStack::PopAndDestroy(); // fs
+	}
+
+
+EXPORT_C void CPrinterDevice::StorePropertiesL() const
+/**  Stores the printer properties. */
+    {
+	RFs fs;
+	User::LeaveIfError(fs.Connect());
+	CleanupClosePushL(fs);
+	CDictionaryStore* dictionarystore = CDictionaryFileStore::SystemLC(fs);
+	RDictionaryWriteStream stream;
+	stream.AssignLC(*dictionarystore,Model().iUid);
+	ExternalizePropertiesL(stream);
+	stream.CommitL();
+	CleanupStack::PopAndDestroy(); // stream
+	dictionarystore->CommitL();
+	CleanupStack::PopAndDestroy(2); // dictionarystore, fs
+	}
+
+//
+// CPrinterControl
+//
+
+
+EXPORT_C CPrinterControl::~CPrinterControl()
+/**  Destructor.
+
+It frees all resources owned by the object, prior to its destruction. */
+ {
+	delete iPrinterPort;
+	}
+
+EXPORT_C CPrinterControl::CPrinterControl(CPrinterPort* aPrinterPort):
+	CBase(),
+	iState(ENotPrinting),
+	iPrinterPort(aPrinterPort)
+	{}
+
+//
+// TPageSpec
+//
+
+
+EXPORT_C TPageSpec::TPageSpec():
+	iPortraitPageSize(TSize(0,0)),
+	iOrientation(EPortrait)
+/** Default constructor. 
+
+Initialises the page orientation to portrait and the page height and width 
+to zero. */
+	{}
+
+
+EXPORT_C TPageSpec::TPageSpec(TPageOrientation anOrientation,const TSize& aSize):
+	iPortraitPageSize(aSize),
+	iOrientation(anOrientation)
+/** Constructor with page orientation and size. 
+
+@param aOrientation Specifies the page orientation. 
+@param aSize Specifies the page size. */
+ 	{}
+
+
+EXPORT_C void TPageSpec::InternalizeL(RReadStream& aStream)
+/** Internalises a page specification object from a read stream. 
+
+The presence of this function means that the standard templated stream operator>>(), 
+defined in s32strm.h, is available to internalise objects of this class.
+
+@param aStream The read stream. */
+ 	{
+	iPortraitPageSize.iWidth = aStream.ReadInt32L();
+	iPortraitPageSize.iHeight = aStream.ReadInt32L();
+	iOrientation=(TPageSpec::TPageOrientation)aStream.ReadInt8L();
+	}
+
+
+EXPORT_C void TPageSpec::ExternalizeL(RWriteStream& aStream) const
+/** Externalises the page specification object to a write stream.
+
+The presence of this function means that the standard templated stream operator<<(), 
+defined in s32strm.h, is available to externalise objects of this class.
+@param aStream The write stream. */
+ 	{
+	aStream.WriteInt32L(iPortraitPageSize.iWidth);
+	aStream.WriteInt32L(iPortraitPageSize.iHeight);
+	aStream.WriteInt8L(iOrientation);
+	}
+
+
+EXPORT_C TSize TPageSpec::OrientedPageSize()const
+/** Gets the oriented page size.
+
+The oriented page size is the absolute width and height of the page, respecting 
+the page orientation.
+@return The oriented page size (in pixels or twips). */
+  	{
+	if(iOrientation==EPortrait)
+		return(iPortraitPageSize);
+	return(TSize(iPortraitPageSize.iHeight,iPortraitPageSize.iWidth));
+	}
+
+
+EXPORT_C TBool TPageSpec::operator==(const TPageSpec& aPageSpec) const
+/** Equality operator. 
+
+This operator compares page specifications for equality. Two page specifications 
+are equal if both their orientations and portrait page sizes are equal.
+
+@param aPageSpec Page specification to be compared.
+@return ETrue, if the page specifications are equal; EFalse, otherwise. */
+   {
+	return(iPortraitPageSize==aPageSpec.iPortraitPageSize &&
+		iOrientation==aPageSpec.iOrientation);
+	}
+
+ 
+EXPORT_C TBool TPageSpec::operator!=(const TPageSpec& aPageSpec) const
+/** Inequality operator.
+
+This operator compares two page specifications for inequality. Two page specifications 
+are unequal if one or both of their orientations and portrait page sizes differ.
+
+@param aPageSpec Page specification to be compared.
+@return ETrue, if the page specifications differ; EFalse, otherwise. */
+	{
+	return(!(*this==aPageSpec));
+	}
+
+
+// TMargins
+
+EXPORT_C void TMargins::InternalizeL(RReadStream& aStream)
+/** Internalises a set of margins from a read stream.
+
+The presence of this function means that the standard templated stream operator>>() 
+is available to internalise objects of this class.
+
+@param aStream Stream from which the object is internalised. */
+	{
+	iLeft = aStream.ReadInt32L();
+	iRight = aStream.ReadInt32L();
+	iTop = aStream.ReadInt32L();
+	iBottom = aStream.ReadInt32L();
+	}
+
+EXPORT_C void TMargins::ExternalizeL(RWriteStream& aStream) const
+/** Externalises a set of margins to a write stream.
+
+The presence of this function means that the standard templated stream operator<<() 
+is available to externalise objects of this class.
+
+@param aStream Stream to which the object is externalised. */
+	{
+	aStream.WriteInt32L(iLeft);
+	aStream.WriteInt32L(iRight);
+	aStream.WriteInt32L(iTop);
+	aStream.WriteInt32L(iBottom);
+	}
+
+EXPORT_C TBool TMargins::operator==(const TMargins& aMargins) const
+/** Tests margins for equality.
+
+@param aMargins The margin to be compared with this margin. 
+@return ETrue, if the margins are equal; EFalse, otherwise. */
+	{
+	return(iLeft==aMargins.iLeft && iRight==aMargins.iRight &&
+		iTop==aMargins.iTop && iBottom==aMargins.iBottom);
+	}
+
+EXPORT_C TBool TMargins::operator!=(const TMargins& aMargins) const
+/** Tests margins for inequality.
+
+@param aMargins The margin to be compared with this margin. 
+@return ETrue, if the margins are unequal; EFalse, otherwise. */
+	{
+	return(!(*this==aMargins));
+	}
+
+//
+// CPrinterDriverUI
+//
+
+EXPORT_C CPrinterDriverUI::CPrinterDriverUI()
+	{
+	__DECLARE_NAME(_S("CPrinterDriverUI"));
+	}
+
+
+EXPORT_C TBool CPrinterDriverUI::BeforePrintL()
+ /** Provides an opportunity for a dialog to be put up before printing begins.
+
+@return ETrue, if printing is to continue; EFalse, if printing is to be cancelled. 
+The default implementation returns ETrue. */
+  	{
+	return ETrue;
+	}
+
+
+EXPORT_C void CPrinterDriverUI::AfterPrintL()
+ /** Provides an opportunity for a dialog to be put up after printing is complete.
+The default implementation is empty. */
+	{
+	}
+
+
+EXPORT_C void CPrinterDriverUI::SetPropertiesL()
+/** Provides an opportunity for a dialog to be put up to capture or change printer 
+properties.
+The default implementation is empty. */
+	{
+	}
+
+
+EXPORT_C TBool CPrinterDriverUI::CanSetProperties()
+/** Tests whether printer properties can be set.
+
+@return ETrue, if printer properties can be set; EFalse, otherwise. The default 
+implementation returns EFalse. */
+    {
+	return EFalse;
+	}
+
+//
+// CPrinterDriver
+//
+
+
+EXPORT_C CPrinterDriver* CPrinterDriver::NewL()
+/** Constructs, and returns a pointer to a new instance for accessing a printer 
+specification data store.
+
+@return Pointer to the object for accessing a printer specification data store. */
+	{
+	CPrinterDriver* printerdriver=new(ELeave) CPrinterDriver;
+	CleanupStack::PushL(printerdriver);
+	User::LeaveIfError(printerdriver->iFs.Connect());
+	CleanupStack::Pop();
+	return printerdriver;
+	}
+
+
+EXPORT_C CPrinterDriver::~CPrinterDriver()
+/** Destructor.
+
+It frees all resources owned by the object, prior to its destruction. In particular, 
+it closes the printer specification data store and any open session with the file server.  */	
+    {
+	Close();
+	iFs.Close();
+	}
+
+
+EXPORT_C void CPrinterDriver::OpenPdrL(const TDesC &aName)
+/**  Opens the specified printer specification data store.
+
+@return  The name of the printer specification data store. This must be a 
+valid printer specification data store,otherwise the function leaves with
+KErrNotSupported. */	
+    {
+	Close();
+	TRAPD(ret,DoOpenPdrL(aName));
+	if (ret!=KErrNone)
+		{
+		Close();
+		User::Leave(ret);
+		}
+	}
+
+EXPORT_C void CPrinterDriver::Close()
+/** Closes the printer specification data store and frees resources.
+
+An open session with the file server remains open. */
+	{
+	delete iPdrStore,
+	iPdrStore=NULL;
+	iNumModels=0;
+	delete[] iModelList;
+	iModelList=NULL;
+	DeletePrinterDevice();
+	}
+
+
+EXPORT_C TInt CPrinterDriver::NumModels() const
+ /** Gets the number of printer models defined by the printer specification.
+
+@return The number of printer models. */
+ 	{
+	return iNumModels;
+	}
+
+
+EXPORT_C TPrinterModelEntry CPrinterDriver::Model(TInt aNum) const
+/** Gets the specified printer model.
+
+@param aNum An index into the list of printer models defined in the printer 
+specification data.
+@return Model specific information. */
+ 	{
+	GDI_ASSERT_DEBUG(aNum>=0,EPdrModelIndexOutOfRange);
+	GDI_ASSERT_DEBUG(aNum<iNumModels,EPdrModelIndexOutOfRange);
+	return iModelList[aNum].iEntry;
+	}
+
+
+EXPORT_C CPrinterDevice* CPrinterDriver::CreatePrinterDeviceL(TUid aModelUid)
+/** Creates the physical graphics device to be used for printing.
+
+@param aModelUid The UID of a specific model which is defined in the printer 
+specification data.
+@return The physical graphics device to be used for printing.  */	
+    {
+	GDI_ASSERT_DEBUG(!iPrinterDevice,EPdrPrinterDeviceExists);
+	TRAPD(ret,DoCreatePrinterDeviceL(aModelUid));
+	if (ret!=KErrNone)
+		{
+		DeletePrinterDevice();
+		User::Leave(ret);
+		}
+	return iPrinterDevice;
+	}
+
+void CPrinterDriver::LoadLibraryL(RLibrary& aLibrary,const TDesC& aExt,TUid aUid2)
+	{
+	TFileName filename=iPdlName;
+	filename.Append(aExt);
+
+	User::LeaveIfError(aLibrary.Load(filename));
+	TUidType type=aLibrary.Type();
+	if (type[1]!=aUid2 && type[2]!=iPdlUid)
+		{
+		aLibrary.Close();
+		User::Leave(KErrNotSupported);
+		}
+	if (type[1]!=aUid2)
+		{
+		aLibrary.Close();
+		User::Leave(KErrNotFound);
+		}
+	}
+
+
+EXPORT_C CPrinterDriverUI* CPrinterDriver::CreatePrinterDriverUIL()
+/** Constructs a printer specific user interface.
+
+The user interface object is optional, but if it exists, it is implemented 
+as part of a UDL (i.e. a UI DLL).
+
+@return A pointer to the printer specific user interface, or NULL if there is 
+none. */
+    {
+	GDI_ASSERT_DEBUG(iPrinterDevice,EPdrPrinterDeviceDoesNotExist);
+	if (iUdlLibrary.Handle()==0)
+		{
+		TRAPD(ret,LoadLibraryL(iUdlLibrary,KUdlExtension,TUid::Uid(KUdlUidVal)));
+		if (ret==KErrNotFound)
+			return NULL;
+		else
+			User::LeaveIfError(ret);
+		}
+	TLibraryFunction f = iUdlLibrary.Lookup(1);
+	CPrinterDriverUI* printerdriverui=(CPrinterDriverUI*)((*f)());
+	CleanupStack::PushL(printerdriverui);
+	User::LeaveIfError(printerdriverui->SetPrinterDevice(iPrinterDevice));
+	CleanupStack::Pop();
+	return printerdriverui;
+	}
+
+CPrinterDriver::CPrinterDriver()
+	{}
+
+void CPrinterDriver::DeletePrinterDevice()
+	{
+	iUdlLibrary.Close();
+	delete iPrinterDevice;
+	iPrinterDevice=NULL;
+	iPdlLibrary.Close();
+	}
+
+void CPrinterDriver::DoOpenPdrL(const TDesC &aName)
+	{
+	Close();
+	iPdrStore=CDirectFileStore::OpenL(iFs,aName,EFileStream|EFileRead|EFileShareReadersOnly);
+	if (iPdrStore->Type()[1]!=TUid::Uid(KPdrStoreFileUidVal))
+		User::Leave(KErrNotSupported);
+	TStreamId headerid = iPdrStore->Root();
+	RStoreReadStream stream;
+	stream.OpenLC(*iPdrStore,headerid);
+		stream >> iPdlName;
+	stream >> iPdlUid;
+	iNumModels = stream.ReadInt32L();
+	iModelList = new(ELeave) TPrinterModelHeader[iNumModels];
+	for (TInt i=0; i<iNumModels; i++)
+		iModelList[i].InternalizeL(stream);
+	CleanupStack::PopAndDestroy();
+	}
+
+void CPrinterDriver::DoCreatePrinterDeviceL(TUid aModelUid)
+	{
+	if (!iPdlName.Length())
+		User::Leave(KErrGeneral); // !! find a better error number
+	LoadLibraryL(iPdlLibrary,KPdlExtension,TUid::Uid(KPdlUidVal));
+	TLibraryFunction f = iPdlLibrary.Lookup(1);
+	iPrinterDevice=(CPrinterDevice*)((*f)());
+	TInt i;
+	for (i=0; (i<iNumModels) && (aModelUid!=iModelList[i].iEntry.iUid); i++)
+		{
+		}
+	GDI_ASSERT_DEBUG(i<iNumModels,EPdrModelUidNotFound);
+	User::LeaveIfError(iPrinterDevice->SetModel(iModelList[i],*iPdrStore));
+	iPrinterDevice->RestorePropertiesL();
+	}
+
+//
+// CPdrModelList
+//
+
+
+EXPORT_C CPdrModelList* CPdrModelList::NewL()
+/** Constructs, and returns a pointer to a new instance of the printer model 
+list interface.
+@return Pointer to the new printer model list interface object. */
+    {
+	CPdrModelList* modellist=new(ELeave) CPdrModelList();
+	CleanupStack::PushL(modellist);
+	modellist->ConstructL();
+	CleanupStack::Pop();
+	return modellist;
+	}
+
+
+EXPORT_C CPdrModelList::~CPdrModelList()
+/** Virtual destructor.
+Frees resources owned by the object, prior to its destruction. */
+	{
+	delete iModelArray;
+	delete iFileArray;
+	if (iDirectoryArray)
+		{// delete all the HBufC's
+		for (TInt i=iDirectoryArray->Count()-1 ; i>=0 ; i--)
+			delete (*iDirectoryArray)[i];
+		delete iDirectoryArray;
+		}
+	iFileServer.Close();
+	}
+
+
+EXPORT_C TInt CPdrModelList::ModelCount() const
+/** Gets the number of printer models in the printer model list.
+@return The number of printer models. */
+    {
+	return iModelArray->Count();
+	}
+
+
+EXPORT_C const TPrinterModelEntry CPdrModelList::operator [] (TInt anIndex)
+/** Gets printer model name.
+
+This is the name of the printer model at the specified index within the list 
+of printer models.
+
+@param anIndex The index of the printer model within the array of printer 
+models. Note that this number must be between zero and ModelCount(). 
+
+@return Name of printer model, up to 32 characters long */
+ 	{
+	GDI_ASSERT_DEBUG(anIndex>=0,EPdrModelIndexOutOfRange);
+	GDI_ASSERT_DEBUG(anIndex<iModelArray->Count(),EPdrModelIndexOutOfRange);
+
+	return (*iModelArray)[anIndex].iEntry;
+	}
+
+
+EXPORT_C TInt CPdrModelList::UidToNum(TUid aModelUid) const
+/** Gets a printer model's index within the model list from its UID.
+
+@param aModelUid The UID of the printer model.
+@return The index of the printer model within the array of printer models if 
+found; KErrNotFound, otherwise. */
+    {
+	TInt i,count=iModelArray->Count();
+	for (i=0; (i<count) && (aModelUid!=(*iModelArray)[i].iEntry.iUid); i++)
+		{
+		}
+
+	if (i==count)
+		i=KErrNotFound;
+
+	return i;
+	}
+
+
+EXPORT_C void CPdrModelList::AddDirectoryL(const TDesC& aDir)
+/** Adds a directory to the list of directories to be scanned for printer models.
+
+@param aDir The directory to be added to the list. */
+	{
+	HBufC* buf = HBufC::NewL(aDir.Length());
+	CleanupStack::PushL(buf);
+	*buf = aDir;
+	iDirectoryArray->AppendL(buf);
+	CleanupStack::Pop(); //buf
+	}
+
+LOCAL_C void DereferenceAndDeleteHBufC8(TAny* aPointerToPointerToHBufC8)
+	{
+	delete *STATIC_CAST(HBufC8**, aPointerToPointerToHBufC8);
+	}
+
+
+EXPORT_C CPrinterModelList* CPdrModelList::ScanForModelsL()
+/** Scans through through the list of directories for all .pdr files and generates 
+a list of printer models.
+
+@return The list of model names. */
+	{
+	iModelArray->Reset();
+	iFileArray->Reset();
+	// check that there is at least one directory to parse?
+	// get a list of *.pdr files in all directories specified (using AddDirectory())
+	for (TInt index=iDirectoryArray->Count()-1 ; index>=0 ; index--)
+		ScanDirectoryL(index);
+ 	// then go through the files one at a time, adding all models to the list
+	TParse* parser = new(ELeave) TParse;
+	CleanupStack::PushL(parser);
+	TFileName* nameOfLoadedResourceFile=new(ELeave) TFileName;
+	CleanupStack::PushL(nameOfLoadedResourceFile);
+	TFileName* tempFileName=new(ELeave) TFileName;
+	CleanupStack::PushL(tempFileName);
+	RResourceFile resourceFile;
+	CleanupClosePushL(resourceFile);
+	HBufC8* resource=NULL;
+	CleanupStack::PushL(TCleanupItem(DereferenceAndDeleteHBufC8, &resource));
+	for (TInt fileNum=iFileArray->Count()-1 ; fileNum>=0 ; fileNum--)
+		ListModelsL(fileNum, *parser, *nameOfLoadedResourceFile, *tempFileName, resourceFile, resource);
+	CleanupStack::PopAndDestroy(5); // resource, resourceFile, tempFileName, nameOfLoadedResourceFile and parser
+	// return a handle to the array of model names
+	return this;
+	}
+
+
+EXPORT_C CPrinterDriver* CPdrModelList::CreatePrinterDriverL(TInt anIndex)
+/** Creates an object for accessing the specified store that contains printer specification 
+data.
+
+@param anIndex An index into a list of files containing printer specification 
+data. The files are the complete set of .pdr files found in the directories 
+known to this object.
+@return A pointer to the object representing the store containing the printer 
+specification data. */
+ 	{
+	GDI_ASSERT_DEBUG(anIndex>=0,EPdrModelIndexOutOfRange);
+	GDI_ASSERT_DEBUG(anIndex<iModelArray->Count(),EPdrModelIndexOutOfRange);
+
+	CPrinterDriver* driver = CPrinterDriver::NewL();
+	CleanupStack::PushL(driver);
+	HBufC* file = NewPathBufL(*((*iModelArray)[anIndex].iFile));
+	CleanupStack::PushL(file);
+	driver->OpenPdrL(*file);
+	driver->CreatePrinterDeviceL((*iModelArray)[anIndex].iEntry.iUid);
+	CleanupStack::PopAndDestroy();
+	CleanupStack::Pop();
+	return driver;
+	}
+
+ 
+ CPdrModelList::CPdrModelList():
+	iModelArray(NULL),
+	iFileArray(NULL),
+	iDirectoryArray(NULL)
+	{
+	}
+ 
+ void CPdrModelList::ConstructL()
+	{
+	__DECLARE_NAME(_S("CPdrModelList"));
+	iModelArray = new(ELeave) CArrayFixSeg<TModelEntry>(5);
+	iFileArray = new(ELeave) CArrayFixFlat<TFileEntry>(5);
+	iDirectoryArray = new(ELeave) CArrayFixFlat<HBufC*>(1);
+	User::LeaveIfError(iFileServer.Connect());
+	}
+
+void CPdrModelList::ScanDirectoryL(TInt aDirIndex)
+/** Scans the given directory, parsing all files found
+ If a file is of the correct type it is appended to the file list*/
+	{
+	GDI_ASSERT_DEBUG(aDirIndex>=0,EPdrDirectoryIndexOutOfRange);
+	GDI_ASSERT_DEBUG(aDirIndex<iDirectoryArray->Count(),EPdrDirectoryIndexOutOfRange);
+
+	TDesC* dir = (*iDirectoryArray)[aDirIndex];
+	TParse path;
+	path.Set(KPdrExtension,dir,NULL);
+	CDir* fileList;
+	TInt ret = iFileServer.GetDir(path.FullName(),KEntryAttNormal,ESortByName,fileList);
+	if (ret == KErrNone)
+		{
+		CleanupStack::PushL(fileList);
+		for (TInt i=fileList->Count()-1 ; i>=0 ; i--) 
+			{
+			TFileEntry& entry = iFileArray->ExtendL();
+			entry.iFileName = (*fileList)[i].iName;
+			entry.iDirectory = dir;
+			}
+		CleanupStack::PopAndDestroy(); // fileList
+		}
+	else if (ret == KErrNoMemory) // Ignore errors other than KErrNoMemory
+		User::LeaveNoMemory();
+	}
+
+void CPdrModelList::ListModelsL(TInt aFileIndex, TParse& aParser, TFileName& aNameOfLoadedResourceFile, TFileName& aTempFileName, RResourceFile& aResourceFile, HBufC8*& aResource)
+/** given a pdr file list all the models it contains in the model array */
+	{
+	GDI_ASSERT_DEBUG(aFileIndex>=0,EPdrFileIndexOutOfRange);
+	GDI_ASSERT_DEBUG(aFileIndex<iFileArray->Count(),EPdrFileIndexOutOfRange);
+
+	CPrinterDriver* driver = CPrinterDriver::NewL() ;
+	CleanupStack::PushL(driver);
+	// open the file
+	HBufC* fullPath = NewPathBufL((*iFileArray)[aFileIndex]);
+	TRAPD(ret,driver->OpenPdrL(*fullPath));
+	delete fullPath;
+	if ((ret!=KErrNone) && (ret!=KErrNotSupported))
+		User::Leave(ret);
+	// get info on the models one by one and insert them into the array
+	if (ret==KErrNone)
+		{
+		TModelEntry modelentry;
+		modelentry.iFile = &(*iFileArray)[aFileIndex]; // set the file pointer for the entry
+		const TInt numberOfModels = driver->NumModels();
+		for (TInt i=0 ; i<numberOfModels ; i++)
+			{
+			modelentry.iEntry=driver->Model(i);
+			if (UidToNum(modelentry.iEntry.iUid)==KErrNotFound)
+				{
+				User::LeaveIfError(aParser.SetNoWild(KRscExtension, &modelentry.iFile->iFileName, modelentry.iFile->iDirectory));
+				aTempFileName=aParser.FullName();
+				BaflUtils::NearestLanguageFile(iFileServer, aTempFileName);
+				if (aNameOfLoadedResourceFile.CompareF(aTempFileName)!=0)
+					{
+					if (!BaflUtils::FileExists(iFileServer, aTempFileName))
+						{
+						iModelArray->AppendL(modelentry); // no resource file found, so reverting to old behaviour (i.e. where the model-name is set from the PDR file)
+						continue;
+						}
+					aNameOfLoadedResourceFile=KNullDesC;
+					aResourceFile.OpenL(iFileServer, aTempFileName);
+					HBufC8* resource=aResourceFile.AllocReadL(aResourceFile.Offset()+2); // read the first resource after the RSS_SIGNATURE resource
+					delete aResource;
+					aResource=resource;
+					aNameOfLoadedResourceFile=aTempFileName;
+					}
+				TResourceReader resourceReader;
+				resourceReader.SetBuffer(aResource);
+				for (TInt j=resourceReader.ReadUint16()-1; ; --j)
+					{
+					if (j<0)
+						{
+						iModelArray->AppendL(modelentry); // no matching uid found in the resource file, so reverting to old behaviour (i.e. where the model-name is set from the PDR file)
+						break;
+						}
+					TInt uid=resourceReader.ReadInt32();
+					TPtrC name=resourceReader.ReadTPtrC();
+					if (uid==modelentry.iEntry.iUid.iUid)
+						{
+						if (name.Length()>0)
+							{
+							modelentry.iEntry.iModelName=name;
+							iModelArray->AppendL(modelentry);
+							}
+						break;
+						}
+					}
+				}
+			}
+		}
+	CleanupStack::PopAndDestroy(); // driver
+	}
+
+
+HBufC* CPdrModelList::NewPathBufL(const TFileEntry& aFileEntry)  
+/** Create a buf of the right length and... 
+ set its contents to the full filename of model aModel */
+	{
+	// Create a buf of the right length
+	HBufC* buf = HBufC::NewL(aFileEntry.iFileName.Length()+aFileEntry.iDirectory->Length());
+	// Insert the file path
+	TPtr filePtr = buf->Des();
+	filePtr.Append(*aFileEntry.iDirectory);
+	filePtr.Append(aFileEntry.iFileName);
+	return buf;
+	}
+
+// !!!!
+// Retained for binary compatibility only: remove if we make a binary incompatible release
+//
+
+IMPORT_C void GDI_Reserved();
+EXPORT_C void GDI_Reserved()
+	{}
+