Author: tkreuzer
Date: Sat Oct 13 13:32:49 2012
New Revision: 57552
URL:
http://svn.reactos.org/svn/reactos?rev=57552&view=rev
Log:
[RTL]
Implement LdrEnumResources
Modified:
trunk/reactos/lib/rtl/res.c
Modified: trunk/reactos/lib/rtl/res.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/rtl/res.c?rev=57552&am…
==============================================================================
--- trunk/reactos/lib/rtl/res.c [iso-8859-1] (original)
+++ trunk/reactos/lib/rtl/res.c [iso-8859-1] Sat Oct 13 13:32:49 2012
@@ -283,18 +283,220 @@
}
-/*
- * @unimplemented
- */
+#define NAME_FROM_RESOURCE_ENTRY(RootDirectory, Entry) \
+ ((Entry)->NameIsString ? (ULONG_PTR)(RootDirectory) + (Entry)->NameOffset :
(Entry)->Id)
+
+static
+LONG
+LdrpCompareResourceNames_U(
+ _In_ PUCHAR ResourceData,
+ _In_ PIMAGE_RESOURCE_DIRECTORY_ENTRY Entry,
+ _In_ ULONG_PTR CompareName)
+{
+ PIMAGE_RESOURCE_DIR_STRING_U ResourceString;
+ PWSTR String1, String2;
+ USHORT ResourceStringLength;
+ WCHAR Char1, Char2;
+
+ /* Check if the resource name is an ID */
+ if (CompareName <= USHRT_MAX)
+ {
+ /* Just compare the 2 IDs */
+ return (CompareName - Entry->Id);
+ }
+ else
+ {
+ /* Fail if ResourceName2 is an ID */
+ if (Entry->Id <= USHRT_MAX) return -1;
+
+ /* Get the resource string */
+ ResourceString = (PIMAGE_RESOURCE_DIR_STRING_U)(ResourceData +
+ Entry->NameOffset);
+
+ /* Get the string length */
+ ResourceStringLength = ResourceString->Length;
+
+ String1 = ResourceString->NameString;
+ String2 = (PWSTR)CompareName;
+
+ /* Loop all characters of the resource string */
+ while (ResourceStringLength--)
+ {
+ /* Get the next characters */
+ Char1 = *String1++;
+ Char2 = *String2++;
+
+ /* Check if they don't match, or if the compare string ends */
+ if ((Char1 != Char2) || (Char2 == 0))
+ {
+ /* They don't match, fail */
+ return Char2 - Char1;
+ }
+ }
+
+ /* All characters match, check if the compare string ends here */
+ return (*String2 == 0) ? 0 : 1;
+ }
+}
+
NTSTATUS
NTAPI
LdrEnumResources(
- IN PVOID BaseAddress,
- IN PLDR_RESOURCE_INFO ResourceInfo,
- IN ULONG Level,
- IN OUT PULONG ResourceCount,
- OUT PLDR_ENUM_RESOURCE_INFO Resources OPTIONAL)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
+ _In_ PVOID ImageBase,
+ _In_ PLDR_RESOURCE_INFO ResourceInfo,
+ _In_ ULONG Level,
+ _Inout_ ULONG *ResourceCount,
+ _Out_opt_ LDR_ENUM_RESOURCE_INFO *Resources)
+{
+ PUCHAR ResourceData;
+ NTSTATUS Status;
+ ULONG i, j, k;
+ ULONG NumberOfTypeEntries, NumberOfNameEntries, NumberOfLangEntries;
+ ULONG Count, MaxResourceCount;
+ PIMAGE_RESOURCE_DIRECTORY TypeDirectory, NameDirectory, LangDirectory;
+ PIMAGE_RESOURCE_DIRECTORY_ENTRY TypeEntry, NameEntry, LangEntry;
+ PIMAGE_RESOURCE_DATA_ENTRY DataEntry;
+ ULONG Size;
+ LONG Result;
+
+ /* If the caller wants data, get the maximum count of entries */
+ MaxResourceCount = (Resources != NULL) ? *ResourceCount : 0;
+
+ /* Default to 0 */
+ *ResourceCount = 0;
+
+ /* Locate the resource directory */
+ ResourceData = RtlImageDirectoryEntryToData(ImageBase,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_RESOURCE,
+ &Size);
+ if (ResourceData == NULL)
+ return STATUS_RESOURCE_DATA_NOT_FOUND;
+
+ /* The type directory is at the root, followed by the entries */
+ TypeDirectory = (PIMAGE_RESOURCE_DIRECTORY)ResourceData;
+ TypeEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(TypeDirectory + 1);
+
+ /* Get the number of entries in the type directory */
+ NumberOfTypeEntries = TypeDirectory->NumberOfNamedEntries +
+ TypeDirectory->NumberOfIdEntries;
+
+ /* Start with 0 resources and status success */
+ Status = STATUS_SUCCESS;
+ Count = 0;
+
+ /* Loop all entries in the type directory */
+ for (i = 0; i < NumberOfTypeEntries; ++i, ++TypeEntry)
+ {
+ /* Check if comparison of types is requested */
+ if (Level > RESOURCE_TYPE_LEVEL)
+ {
+ /* Compare the type with the requested Type */
+ Result = LdrpCompareResourceNames_U(ResourceData,
+ TypeEntry,
+ ResourceInfo->Type);
+
+ /* Not equal, continue with next entry */
+ if (Result != 0) continue;
+ }
+
+ /* The entry must point to the name directory */
+ if (!TypeEntry->DataIsDirectory)
+ {
+ return STATUS_INVALID_IMAGE_FORMAT;
+ }
+
+ /* Get a pointer to the name subdirectory and it's first entry */
+ NameDirectory = (PIMAGE_RESOURCE_DIRECTORY)(ResourceData +
+ TypeEntry->OffsetToDirectory);
+ NameEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(NameDirectory + 1);
+
+ /* Get the number of entries in the name directory */
+ NumberOfNameEntries = NameDirectory->NumberOfNamedEntries +
+ NameDirectory->NumberOfIdEntries;
+
+ /* Loop all entries in the name directory */
+ for (j = 0; j < NumberOfNameEntries; ++j, ++NameEntry)
+ {
+ /* Check if comparison of names is requested */
+ if (Level > RESOURCE_NAME_LEVEL)
+ {
+ /* Compare the name with the requested name */
+ Result = LdrpCompareResourceNames_U(ResourceData,
+ NameEntry,
+ ResourceInfo->Name);
+
+ /* Not equal, continue with next entry */
+ if (Result != 0) continue;
+ }
+
+ /* The entry must point to the language directory */
+ if (!NameEntry->DataIsDirectory)
+ {
+ return STATUS_INVALID_IMAGE_FORMAT;
+ }
+
+ /* Get a pointer to the language subdirectory and it's first entry */
+ LangDirectory = (PIMAGE_RESOURCE_DIRECTORY)(ResourceData +
+
NameEntry->OffsetToDirectory);
+ LangEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(LangDirectory + 1);
+
+ /* Get the number of entries in the language directory */
+ NumberOfLangEntries = LangDirectory->NumberOfNamedEntries +
+ LangDirectory->NumberOfIdEntries;
+
+ /* Loop all entries in the language directory */
+ for (k = 0; k < NumberOfLangEntries; ++k, ++LangEntry)
+ {
+ /* Check if comparison of languages is requested */
+ if (Level > RESOURCE_LANGUAGE_LEVEL)
+ {
+ /* Compare the language with the requested language */
+ Result = LdrpCompareResourceNames_U(ResourceData,
+ LangEntry,
+ ResourceInfo->Language);
+
+ /* Not equal, continue with next entry */
+ if (Result != 0) continue;
+ }
+
+ /* This entry must point to data */
+ if (LangEntry->DataIsDirectory)
+ {
+ return STATUS_INVALID_IMAGE_FORMAT;
+ }
+
+ /* Get a pointer to the data entry */
+ DataEntry = (PIMAGE_RESOURCE_DATA_ENTRY)(ResourceData +
+ LangEntry->OffsetToData);
+
+ /* Check if there is still space to store the data */
+ if (Count < MaxResourceCount)
+ {
+ /* There is, fill the entry */
+ Resources[Count].Type =
+ NAME_FROM_RESOURCE_ENTRY(ResourceData, TypeEntry);
+ Resources[Count].Name =
+ NAME_FROM_RESOURCE_ENTRY(ResourceData, NameEntry);
+ Resources[Count].Language =
+ NAME_FROM_RESOURCE_ENTRY(ResourceData, LangEntry);
+ Resources[Count].Data = (PUCHAR)ImageBase +
DataEntry->OffsetToData;
+ Resources[Count].Reserved = 0;
+ Resources[Count].Size = DataEntry->Size;
+ }
+ else
+ {
+ /* There is not enough space, save error status */
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ /* Count this resource */
+ ++Count;
+ }
+ }
+ }
+
+ /* Return the number of matching resources */
+ *ResourceCount = Count;
+ return Status;
+}