/*++ Copyright (c) 1991 Microsoft Corporation Module Name: inflib.c Abstract: Source for inflib.lib that implements functions designed to build a layout context given a layout INF file. This sets up an infrastructure to build tools that will need to reference a layout inf file. Author: Vijesh Shetty (vijeshs) Revision History: --*/ #include #include #include #include #include #include #include #include #include #include #include //#define DEBUG 1 #define LAYOUT_DIR_SECTION TEXT("WinntDirectories") #define MAX_TEMP 500 //Structure to pass parameters to the enumeration callback typedef struct _CALLBACK_PACKAGE{ PLAYOUT_CONTEXT Context; PLAYOUTENUMCALLBACK Callback; DWORD_PTR Param; }CALLBACK_PACKAGE, *PCALLBACK_PACKAGE; //Structure to pass parameters to the enumeration callback typedef struct _WINNT_DIRCODES{ TCHAR Dir[MAX_PATH]; }WINNT_DIRCODES, *PWINNT_DIRCODES; #if DBG VOID AssertFail( IN PSTR FileName, IN UINT LineNumber, IN PSTR Condition ) { int i; CHAR Name[MAX_PATH]; PCHAR p; CHAR Msg[4096]; // // Use dll name as caption // GetModuleFileNameA(NULL,Name,MAX_PATH); if(p = strrchr(Name,'\\')) { p++; } else { p = Name; } wsprintfA( Msg, "Assertion failure at line %u in file %s: %s\n\nCall DebugBreak()?", LineNumber, FileName, Condition ); OutputDebugStringA(Msg); i = MessageBoxA( NULL, Msg, p, MB_YESNO | MB_TASKMODAL | MB_ICONSTOP | MB_SETFOREGROUND ); if(i == IDYES) { DebugBreak(); } } #define MYASSERT(x) if(!(x)) { AssertFail(__FILE__,__LINE__,#x); } #else #define MYASSERT( exp ) #endif // DBG BOOL InternalEnumRoutine( IN PVOID StringTable, IN LONG StringId, IN PCTSTR String, IN PFILE_LAYOUTINFORMATION LayoutInfo, IN UINT LayoutInfoSize, IN LPARAM Param ); BOOL ValidateTextmodeDirCodesSection( PCTSTR LayoutFile, PCTSTR WinntdirSection ) /* Routine to validate the [WinntDirectories] section for a setup layout INF. This checks for errors that maybe encountered when people add/remove stuff from this section. Arguments: LayoutInf - Name of setup layout INF that contains the specified section WinntdirSection - Section that contains dir codes Checks - 1) Looks for duplicate or reused dir codes Return value: TRUE - Validation succeeded FALSE- Validation failed */ { //OPen up the layout file. HINF LayoutInf; PVOID StringTable=NULL; INFCONTEXT LineContext; WINNT_DIRCODES WinntDirs, Buffer; BOOL ret = TRUE; LONG StrID, Size; TCHAR DirCode[4]; LayoutInf = SetupOpenInfFile( LayoutFile, NULL, INF_STYLE_WIN4 | INF_STYLE_CACHE_ENABLE, NULL); if( !LayoutInf || (LayoutInf == INVALID_HANDLE_VALUE)){ _tprintf(TEXT("Error E0000 : Could not open %s\n"), LayoutFile); return FALSE; } //Grovel through the specified section and populate our WINNT_DIRCODES structure if( !SetupFindFirstLine(LayoutInf,WinntdirSection,NULL,&LineContext)){ _tprintf(TEXT("%s : Error E0000 : Can't find section [%s]\n"), LayoutFile, WinntdirSection); return(FALSE); } // Create a stringtable for hashing of the SourceDisksNames section. if( (StringTable=pSetupStringTableInitializeEx( sizeof(WINNT_DIRCODES), 0 )) == NULL ){ _tprintf(TEXT("%s : Error E0000 : Internal error processing [%s] section (1)\n"), LayoutFile, WinntdirSection); return(FALSE); } do{ ZeroMemory( &WinntDirs, sizeof(WINNT_DIRCODES)); if( SetupGetStringField( &LineContext, 0, NULL, 0, &Size) ){ if( SetupGetStringField( &LineContext, 0, DirCode, Size, NULL )){ // // Add the Filename to the StringTable. Look for its presence so that the Count is updated // if(!SetupGetStringField( &LineContext, 1, WinntDirs.Dir, MAX_PATH, NULL)){ _tprintf(TEXT("%s : Error E0000 : Directory missing for Dir ID %s\n"), LayoutFile, DirCode); ret = FALSE; break; } if( pSetupStringTableLookUpStringEx( StringTable, DirCode, STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE, &Buffer, sizeof(WINNT_DIRCODES)) != -1 ){ _tprintf(TEXT("%s : Error E0000 : Duplicate Dir ID found in [%s] section - Dir ID %s reused by %s, %s\n"), LayoutFile, WinntdirSection, DirCode, Buffer.Dir, WinntDirs.Dir); } else{ StrID = pSetupStringTableAddString( StringTable, DirCode, STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE); if( StrID == -1 ){ _tprintf(TEXT("%s : Error E0000 : Internal error processing [%s] section (2)\n"), LayoutFile, WinntdirSection); ret = FALSE; break; } if(!pSetupStringTableSetExtraData( StringTable, StrID, (PVOID)&WinntDirs, sizeof(WINNT_DIRCODES))){ _tprintf(TEXT("%s : Error E0000 : Internal error processing [%s] section (3)\n"), LayoutFile, WinntdirSection); ret = FALSE; break; } } }else _tprintf(TEXT("%s : Error E0000 : Internal error processing [%s] section (4)\n"), LayoutFile, WinntdirSection); }else _tprintf(TEXT("%s : Error E0000 : Internal error processing [%s] section (5)\n"), LayoutFile, WinntdirSection); }while(SetupFindNextLine(&LineContext, &LineContext)); // If we are here and ret=TRUE that means we are done and have suceeded. if( StringTable ) pSetupStringTableDestroy( StringTable ); return ret; } DWORD BuildMediaTagsInformation( IN HINF LayoutInf, IN LPCTSTR SectionName, IN PLAYOUT_CONTEXT LayoutContext, IN UINT Platform_Index) /* Function to populate the stringtable given a handle to the inf and the name of the SourceDisksFiles Section. Arguments : LayoutInf - Handle to a layout file that has the SourceDisksNames Section SectionName - Name of the SourceDisksNames Section (this is so that we can specify decorated sections) LayoutContext - Layout Context that we want to build Platform_Index - Index in the MEDIA_INFO Array */ { DWORD Err = 0; INFCONTEXT LineContext; MEDIA_INFO Media_Info; TCHAR TempStr[500]; LONG StrID; //Grovel through the specified section and populate our MEDIA_TAGS structure if( !SetupFindFirstLine(LayoutInf,SectionName,NULL,&LineContext)) return(ERROR_NOT_ENOUGH_MEMORY); //BUGBUG - Fix error code //StringTableSetConstants( 4096000, 4096000 ); // Create a stringtable for hashing of the SourceDisksNames section. if( (LayoutContext->MediaInfo[Platform_Index]=pSetupStringTableInitializeEx( sizeof(MEDIA_INFO), 0 )) == NULL ) return(ERROR_NOT_ENOUGH_MEMORY); //BUGBUG - Fix error code // Now populate it do{ ZeroMemory( &Media_Info, sizeof(MEDIA_INFO)); if( SetupGetStringField( &LineContext, 0, TempStr, MAX_TEMP, NULL )){ StrID = pSetupStringTableAddString( LayoutContext->MediaInfo[Platform_Index], TempStr, STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE); if( StrID == -1 ){ Err = ERROR_NOT_ENOUGH_MEMORY; _tprintf(TEXT("\nERROR-Could not add string to table\n")); break; } }else return( ERROR_NOT_ENOUGH_MEMORY ); //BUGBUG - Fix error code //_tprintf( TEXT("\nTagID - %s\n"), TempStr ); if( SetupGetStringField( &LineContext, 1, TempStr, MAX_TEMP, NULL) ) lstrcpy(Media_Info.MediaName, TempStr); if( SetupGetStringField( &LineContext, 2, TempStr, MAX_TEMP, NULL) ) lstrcpy(Media_Info.TagFilename, TempStr); if( SetupGetStringField( &LineContext, 4, TempStr, MAX_TEMP, NULL) ) lstrcpy(Media_Info.RootDir, TempStr); /* _tprintf( TEXT("\nMediaName - %s\n"), Media_Info.MediaName ); _tprintf( TEXT("TagFilename - %s\n"), Media_Info.TagFilename ); _tprintf( TEXT("RootDir - %s\n"), Media_Info.RootDir ); */ // // Now add the information to the string table. // if(!pSetupStringTableSetExtraData( LayoutContext->MediaInfo[Platform_Index], StrID, (PVOID)&Media_Info, sizeof(MEDIA_INFO))){ Err = ERROR_NOT_ENOUGH_MEMORY; //BUGBUG - Fix error code _tprintf(TEXT("\nERROR-Could not set extra data for Media Info\n")); break; } }while(SetupFindNextLine(&LineContext, &LineContext)); return Err; } DWORD BuildStringTableForSection( IN HINF LayoutInf, IN LPCTSTR SectionName, IN PLAYOUT_CONTEXT LayoutContext, IN UINT Platform_Index) /* Function to populate the stringtable given a handle to the inf and the name of the SourceDisksFiles Section. Arguments : LayoutInf - Handle to a layout file that has the SourceDisksFiles Section SectionName - Name of the SourceDisksFilesSection (this is so that we can specify decorated sections) LayoutContext - Layout Context that we want to build */ { DWORD Err = 0; INFCONTEXT LineContext, TempContext; DWORD Size; int Temp; LONG StrID; LPTSTR p; TCHAR TempString[MAX_PATH]; FILE_LAYOUTINFORMATION FileInformation; TCHAR FileName[MAX_PATH]; TCHAR Buffer[10]; PVOID LookupBuffer=NULL; PFILE_LAYOUTINFORMATION Lookup; #ifdef DEBUG int count=0; #endif LookupBuffer = pSetupMalloc( LayoutContext->ExtraDataSize ); if( !LookupBuffer ){ Err = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; } //Grovel through the specified section and populate our FILE_LAYOUTINFORMATION structure for each file if( !SetupFindFirstLine(LayoutInf,SectionName,NULL,&LineContext)){ Err = ERROR_NOT_ENOUGH_MEMORY; //BUGBUG - Fix error code goto cleanup; } do{ ZeroMemory( &FileInformation, sizeof(FILE_LAYOUTINFORMATION)); FileInformation.Compression = TRUE; if( SetupGetStringField( &LineContext, 0, NULL, 0, &Size) ){ if( SetupGetStringField( &LineContext, 0, FileName, Size, NULL )){ // // Add the Filename to the StringTable. Look for its presence so that the Count is updated // if( pSetupStringTableLookUpStringEx( LayoutContext->Context, FileName, STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE, LookupBuffer, LayoutContext->ExtraDataSize) != -1 ){ Lookup = (PFILE_LAYOUTINFORMATION)(LookupBuffer); // Check for same platform section if( (Lookup->SectionIndex == Platform_Index) || (Lookup->SectionIndex == LAYOUTPLATFORMINDEX_COMMON)) FileInformation.Count = Lookup->Count + 1; } else FileInformation.Count = 1; StrID = pSetupStringTableAddString( LayoutContext->Context, FileName, STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE); if( StrID == -1 ){ Err = ERROR_NOT_ENOUGH_MEMORY; _tprintf(TEXT("\nERROR-Could not add string to table\n")); break; } // // Now add the other related info for the file as ExtraData // // Get the directory code if( SetupGetIntField( &LineContext, 8, &Temp )){ FileInformation.Directory_Code = Temp; _itot( Temp,Buffer, 10); //Now retrieve the directory Information through a lookup of [WinntDirectories] if( Temp && SetupFindFirstLine( LayoutInf, LAYOUT_DIR_SECTION, Buffer, &TempContext) ){ if( SetupGetStringField( &TempContext, 1, TempString, MAX_PATH, NULL )){ lstrcpy( FileInformation.Directory, TempString ); } } } // // Get the Upgrade and Clean Install Dispositions // FileInformation.UpgradeDisposition = 3; //Default is don't copy if( SetupGetStringField( &LineContext, 9, TempString, MAX_PATH, NULL )){ if( (TempString[0] >= 48) && (TempString[0] <= 57)){ Temp = _ttoi( TempString ); FileInformation.UpgradeDisposition = Temp; } } if( (FileInformation.UpgradeDisposition < 0) || (FileInformation.UpgradeDisposition > 3)) _ftprintf(stderr, TEXT("%s - Bad Upgrade disposition value - Inf maybe corrupt\n"),FileName); FileInformation.CleanInstallDisposition = 3; //Default is don't copy if( SetupGetStringField( &LineContext, 10, TempString, MAX_PATH, NULL )){ if( (TempString[0] >= 48) && (TempString[0] <= 57)){ Temp = _ttoi( TempString ); FileInformation.CleanInstallDisposition = Temp; } } if( (FileInformation.CleanInstallDisposition < 0) || (FileInformation.CleanInstallDisposition > 3)) _ftprintf(stderr, TEXT("%s - Bad Clean Install disposition value - Inf maybe corrupt\n"),FileName); if( SetupGetStringField( &LineContext, 11, TempString, MAX_PATH, NULL )){ lstrcpy( FileInformation.TargetFileName, TempString ); } if( SetupGetStringField( &LineContext, 7, TempString, MAX_PATH, NULL )){ if( *TempString && !_tcschr(TempString, TEXT('_'))){ _ftprintf(stderr, TEXT("\nERROR-Bad Media ID - No _ qualifier - %s\n"), FileName); FileInformation.BootMediaNumber = -1; //Indicates error }else{ // Check for Compression if( TempString[0] == TEXT('_') ) FileInformation.Compression = FALSE; // Look for Boot Media Numbers p = TempString; while( (p[0] == TEXT('_')) ){ p++; } FileInformation.BootMediaNumber = _ttoi(p); } } //Add the Media tag information if( SetupGetStringField( &LineContext, 1, TempString, MAX_PATH, NULL )) lstrcpy(FileInformation.Media_tagID, TempString); FileInformation.SectionIndex = Platform_Index; //Get the file sizes if present if( SetupGetIntField( &LineContext, 3, &Temp )){ FileInformation.Size = (ULONG)Temp; } // // Now add the information to the string table. // if(!pSetupStringTableSetExtraData( LayoutContext->Context, StrID, (PVOID)&FileInformation, sizeof(FILE_LAYOUTINFORMATION))){ Err = ERROR_NOT_ENOUGH_MEMORY; //BUGBUG - Fix error code _tprintf(TEXT("\nERROR-Could not set extra data\n")); break; } /* _tprintf(TEXT("File - %s\n"),FileName); _tprintf(TEXT("Dir Code %d - Dir - %s\n"),FileInformation.Directory_Code, FileInformation.Directory); _tprintf(TEXT("Upgrade Disposition - %d\n"),FileInformation.UpgradeDisposition); _tprintf(TEXT("Textmode Disposition - %d\n"),FileInformation.CleanInstallDisposition); _tprintf(TEXT("Media ID - %s\n"),FileInformation.Media_tagID); if( *(FileInformation.TargetFileName)) _tprintf(TEXT("Target Filename - %s\n"),FileInformation.TargetFileName); if( !FileInformation.Compression ) _tprintf(TEXT("No Compression\n")); if( FileInformation.BootMediaNumber ) _tprintf(TEXT("Boot Media - %d\n"),FileInformation.BootMediaNumber); */ } } #ifdef DEBUG count++; if( (count % 100) == 0) _ftprintf(stderr,TEXT("\b\b\b\b\b%5d"),count); #endif }while(SetupFindNextLine(&LineContext, &LineContext));// while cleanup: if( LookupBuffer ) pSetupFree(LookupBuffer); return Err; } PLAYOUT_CONTEXT BuildLayoutInfContext( IN PCTSTR LayoutInfName, IN DWORD PlatformMask, IN UINT MaxExtraSize ) /* Function to generate a internal representation of files listed in a layout INF file. It returns an opaque context that can be used with other APIs to manipulate/query this representation. The internal representation builds a structure associated with each file that lists its attributes. Arguments : LayoutInfName - Full path to Layout file. PlatFormMask - Can be one of the following.... LAYOUTPLATFORMS_ALL (default) - Grovels through all the platform-specific section LAYOUTPLATFORMS_X86 - Grovels through the SourcedisksFiles.x86 section LAYOUTPLATFORMS_AMD64 - Grovels through the SourcedisksFiles.amd64 section LAYOUTPLATFORMS_IA64 - Grovels through the SourcedisksFiles.ia64 section LAYOUTPLATFORMS_COMMON - Grovels through the SourcedisksFiles section MaxExtraSize - Largest possible extra-data size that we may want to associate with each file Return value : An opaque LAYOUT_CONTEXT used to access the data structure in other calls. Returns NULL if we had a failure. */ { PLAYOUT_CONTEXT LayoutContext; PVOID StringTable; HINF LayoutInf; DWORD Err; // Initialize the string table and set the max extra data size if( (StringTable=pSetupStringTableInitializeEx( (MaxExtraSize+sizeof(FILE_LAYOUTINFORMATION)), 0 )) == NULL ) return NULL; //OPen up the layout file. LayoutInf = SetupOpenInfFile( LayoutInfName, NULL, INF_STYLE_WIN4 | INF_STYLE_CACHE_ENABLE, NULL); if( !LayoutInf || (LayoutInf == INVALID_HANDLE_VALUE)){ pSetupStringTableDestroy( StringTable ); return NULL; } LayoutContext = pSetupMalloc( sizeof(LAYOUT_CONTEXT)); if( !LayoutContext ) goto done; ZeroMemory( LayoutContext, sizeof(LAYOUT_CONTEXT)); LayoutContext->Context = StringTable; LayoutContext->ExtraDataSize = (MaxExtraSize+sizeof(FILE_LAYOUTINFORMATION)); // //Now we need to grovel throught the [SourceDisksFiles] sections // // // Grovel through the decorated sections first as specfied by PlatformMask // if(!PlatformMask) PlatformMask = LAYOUTPLATFORMS_ALL; // // // #ifdef DEBUG _tprintf( TEXT("\nBuilding x86 section\n")); #endif if( PlatformMask & LAYOUTPLATFORMS_X86 ){ // // Build up the [SourceDisksNames.x86] Information // Err = BuildMediaTagsInformation( LayoutInf, TEXT("SourceDisksNames.x86"), LayoutContext, LAYOUTPLATFORMINDEX_X86); // Process [SourceDisksFiles.x86] Err = BuildStringTableForSection( LayoutInf, TEXT("SourceDisksFiles.x86"), LayoutContext, LAYOUTPLATFORMINDEX_X86 ); } #ifdef DEBUG _tprintf( TEXT("\nBuilding amd64 section\n")); #endif if( PlatformMask & LAYOUTPLATFORMS_AMD64 ){ // // Build up the [SourceDisksNames.amd64] Information // Err = BuildMediaTagsInformation( LayoutInf, TEXT("SourceDisksNames.amd64"), LayoutContext, LAYOUTPLATFORMINDEX_AMD64); // Process [SourceDisksFiles.amd64] Err = BuildStringTableForSection( LayoutInf, TEXT("SourceDisksFiles.amd64"), LayoutContext, LAYOUTPLATFORMINDEX_AMD64 ); } #ifdef DEBUG _tprintf( TEXT("\nBuilding ia64 section\n")); #endif if( PlatformMask & LAYOUTPLATFORMS_IA64 ){ // // Build up the [SourceDisksNames.ia64] Information // Err = BuildMediaTagsInformation( LayoutInf, TEXT("SourceDisksNames.ia64"), LayoutContext, LAYOUTPLATFORMINDEX_IA64); // Process [SourceDisksFiles.ia64] Err = BuildStringTableForSection( LayoutInf, TEXT("SourceDisksFiles.ia64"), LayoutContext, LAYOUTPLATFORMINDEX_IA64 ); } #ifdef DEBUG _tprintf( TEXT("\nBuilding common section\n")); #endif if( PlatformMask & LAYOUTPLATFORMS_COMMON ){ // // Build up the [SourceDisksNames] Information. In this case we have // currently set it to the same as x86. Should fix this to do something better - BUGBUG // Err = BuildMediaTagsInformation( LayoutInf, TEXT("SourceDisksNames"), LayoutContext, LAYOUTPLATFORMINDEX_COMMON); // Process [SourceDisksFiles] Err = BuildStringTableForSection( LayoutInf, TEXT("SourceDisksFiles"), LayoutContext, LAYOUTPLATFORMINDEX_COMMON); } done: SetupCloseInfFile( LayoutInf); return(LayoutContext) ; } BOOL EnumerateLayoutInf( IN PLAYOUT_CONTEXT LayoutContext, IN PLAYOUTENUMCALLBACK LayoutEnumCallback, IN DWORD_PTR Param ) /* This function calls the specified callback function for each element in the SourceDisksFilesSection associated with the Layout Inf Context specified. It is required that the user has a LayoutInfContext open from a call to BuildLayoutInfContext. Arguments: Context - A LAYOUT_CONTEXT returned by BuildLayoutInfContext LayoutEnumCallback - specifies a callback function called for each file in the SourceDisksFile section CallerContext - An opaque context pointer passed on to the callback function The callback is of the form: typedef BOOL (CALLBACK *PLAYOUTENUMCALLBACK) ( IN PLAYOUT_CONTEXT Context, IN PCTSTR FileName, IN PFILE_LAYOUTINFORMATION LayoutInformation, IN PVOID ExtraData, IN UINT ExtraDataSize, IN OUT DWORD_PTR Param ); where Context - Pointer to open LAYOUT_CONTEXT FileName - Specifies the individual filename LayoutInformation - Pointer to Layout Information for this file. User should not modify this directly. ExtraData - Pointer to the ExtraData that the caller may have stored. User should not modify this directly. ExtraDataSize - Size in bytes of the ExtraData Param - the opaque param passed into this function is passed into the callback function Return value: TRUE if all the elements were enumerated. If not it returns FALSE and GetLastError() returns ERROR_CANCELLED. If the callback returns FALSE then the enumeration stops but this API returns TRUE. */ { PVOID Buffer; CALLBACK_PACKAGE Package; BOOL ret; if( !LayoutContext || !LayoutContext->Context || !LayoutContext->ExtraDataSize || !LayoutEnumCallback){ SetLastError( ERROR_INVALID_PARAMETER ); return( FALSE ); } Buffer = pSetupMalloc( LayoutContext->ExtraDataSize ); if( !Buffer ){ SetLastError( ERROR_NOT_ENOUGH_MEMORY ); return(FALSE); } //We use Package to send across parameters to the Callback Package.Context = LayoutContext; Package.Callback = LayoutEnumCallback; Package.Param = Param; ret = pSetupStringTableEnum( LayoutContext->Context, Buffer, LayoutContext->ExtraDataSize, InternalEnumRoutine, (LPARAM) &Package); pSetupFree( Buffer ); return( ret ); } BOOL InternalEnumRoutine( IN PVOID StringTable, IN LONG StringId, IN PCTSTR String, IN PFILE_LAYOUTINFORMATION LayoutInfo, IN UINT LayoutInfoSize, IN LPARAM Param ) /* This is the enum callback routine that we provide to setupapi. We in turn have to call the callers callback routine each time we are called. The callback routine of the caller is in Package. For now, we don't care about the StringID and don't tell the caller about it. */ { PVOID ExtraData; UINT ExtraDataSize; PCALLBACK_PACKAGE Package = (PCALLBACK_PACKAGE)Param; BOOL ret; MYASSERT( Package->Callback ); ExtraData = LayoutInfo+sizeof(FILE_LAYOUTINFORMATION); ExtraDataSize = LayoutInfoSize-(sizeof(FILE_LAYOUTINFORMATION)); //BUGBUG : Should probably put this in a try/except block ret = Package->Callback( Package->Context, String, LayoutInfo, ExtraData, ExtraDataSize, Package->Param ); // // If the user's callback returns false we stop enumeration. However the // toplevel EnumerateLayoutInf function still returns TRUE as it was not an // error in itself. // if( !ret ){ SetLastError(ERROR_INVALID_PARAMETER); return( FALSE ); } return( TRUE ); } BOOL FindFileInLayoutInf( IN PLAYOUT_CONTEXT LayoutContext, IN PCTSTR Filename, OUT PFILE_LAYOUTINFORMATION LayoutInformation, OPTIONAL OUT PVOID ExtraData, OPTIONAL OUT PUINT ExtraDataSize, OPTIONAL OUT PMEDIA_INFO Media_Info OPTIONAL ) /* This function finds the file information for a given filename inside a built layout context. It returns the layout information as well as the extra data (if any) associated with the file. Arguments: Context - Pointer to open LAYOUT_CONTEXT Filename - Specifies the filename to search for LayoutInformation - Pointer to caller supplied buffer that gets Layout Information for this file. ExtraData - Pointer to the a caller supplied buffer that gets ExtraData that the caller may have stored. ExtraDataSize - Size in bytes of the ExtraData returned. Media_Info - Pointer to MEDIA_INFO structure that will get filled with the file's corresponding Media information. Return value; TRUE if the file is found - False otherwise. */ { PVOID Buffer; MEDIA_INFO TagInfo; PFILE_LAYOUTINFORMATION Temp; BOOL Err = TRUE; TCHAR filename[MAX_PATH]; if( !LayoutContext || !LayoutContext->Context || !LayoutContext->ExtraDataSize || !Filename){ SetLastError( ERROR_INVALID_PARAMETER ); return( FALSE ); } lstrcpy( filename, Filename ); //To get around constness problem Buffer = pSetupMalloc( LayoutContext->ExtraDataSize ); if( !Buffer ){ SetLastError( ERROR_NOT_ENOUGH_MEMORY ); return(FALSE); } if( pSetupStringTableLookUpStringEx( LayoutContext->Context, filename, STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE, Buffer, LayoutContext->ExtraDataSize) == -1 ){ Err = FALSE; goto cleanup; } if( LayoutInformation ) CopyMemory( LayoutInformation, Buffer, sizeof(FILE_LAYOUTINFORMATION)); if( ExtraData ){ CopyMemory( ExtraData, ((PFILE_LAYOUTINFORMATION)Buffer+sizeof(FILE_LAYOUTINFORMATION)), ((LayoutContext->ExtraDataSize)-(sizeof(FILE_LAYOUTINFORMATION))) ); } if( ExtraDataSize ) *ExtraDataSize = (LayoutContext->ExtraDataSize)-(sizeof(FILE_LAYOUTINFORMATION)); // // Now get the Media Information for the file if needed // if( Media_Info ){ Temp = (PFILE_LAYOUTINFORMATION)Buffer; if( pSetupStringTableLookUpStringEx( LayoutContext->MediaInfo[Temp->SectionIndex], Temp->Media_tagID, STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE, Media_Info, sizeof(MEDIA_INFO)) == -1 ){ _tprintf( TEXT("\nError - Could not get Media Info for tag %s\n"), Temp->Media_tagID); } } cleanup: if( Buffer ) pSetupFree( Buffer ); return Err; } BOOL CloseLayoutInfContext( IN PLAYOUT_CONTEXT LayoutContext) /* This function closes a Layout Inf Context and frees all memory associated with it. Arguments : LayoutContext - LayoutContext to close Return values : TRUE if it succeeds, else FALSE */ { int i; if( !LayoutContext ){ SetLastError( ERROR_INVALID_PARAMETER ); return( FALSE ); }else{ if( LayoutContext->Context ) pSetupStringTableDestroy( LayoutContext->Context ); for( i=0; iMediaInfo[i] ) pSetupStringTableDestroy( LayoutContext->MediaInfo[i] ); } pSetupFree( LayoutContext ); } return TRUE; } VOID MyConcatenatePaths( IN OUT PTSTR Path1, IN LPCTSTR Path2, IN DWORD BufferSizeChars ) /*++ Routine Description: Concatenate two path strings together, supplying a path separator character (\) if necessary between the 2 parts. Arguments: Path1 - supplies prefix part of path. Path2 is concatenated to Path1. Path2 - supplies the suffix part of path. If Path1 does not end with a path separator and Path2 does not start with one, then a path sep is appended to Path1 before appending Path2. BufferSizeChars - supplies the size in chars (Unicode version) or bytes (Ansi version) of the buffer pointed to by Path1. The string will be truncated as necessary to not overflow that size. Return Value: None. --*/ { BOOL NeedBackslash = TRUE; DWORD l; if(!Path1) return; l = lstrlen(Path1); if(BufferSizeChars >= sizeof(TCHAR)) { // // Leave room for terminating nul. // BufferSizeChars -= sizeof(TCHAR); } // // Determine whether we need to stick a backslash // between the components. // if(l && (Path1[l-1] == TEXT('\\'))) { NeedBackslash = FALSE; } if(Path2 && *Path2 == TEXT('\\')) { if(NeedBackslash) { NeedBackslash = FALSE; } else { // // Not only do we not need a backslash, but we // need to eliminate one before concatenating. // Path2++; } } // // Append backslash if necessary and if it fits. // if(NeedBackslash && (l < BufferSizeChars)) { lstrcat(Path1,TEXT("\\")); } // // Append second part of string to first part if it fits. // if(Path2 && ((l+lstrlen(Path2)) < BufferSizeChars)) { lstrcat(Path1,Path2); } return; }