Ejemplo n.º 1
0
void test_version(const resource_version_info_reader& ver_reader, file_version_info& file_info, lang_string_values_map& strings, translation_values_map& translations)
{
    strings.clear();
    translations.clear();

    PE_TEST_EXCEPTION(file_info = ver_reader.get_version_info(strings, translations), "Version Info Parser test 1", test_level_critical);
    PE_TEST(strings.size() == 2 && translations.size() == 2, "Version Info Parser test 2", test_level_critical);
    PE_TEST(strings.find(L"040004b0") != strings.end() && strings.find(L"041904b0") != strings.end(), "Version Info Parser test 3", test_level_critical);
    PE_TEST(translations.find(0x0400) != translations.end() && translations.find(0x0419) != translations.end(), "Version Info Parser test 4", test_level_critical);
    PE_TEST(strings[L"040004b0"][L"FileDescription"] == L"PE Bliss Test PE File", "Version Info Parser test 5", test_level_normal);
    PE_TEST(strings[L"041904b0"][L"FileDescription"] == L"PE Bliss - Тестовый PE-файл", "Version Info Parser test 6", test_level_normal);
    PE_TEST((*translations.find(0x0400)).second == 0x4b0 && (*translations.find(0x0419)).second == 0x4b0, "Version Info Parser test 7", test_level_normal);
    PE_TEST(file_info.get_file_date_ls() == 0 && file_info.get_file_date_ms() == 0
            && file_info.get_file_flags() == 0 && file_info.get_file_os() == file_version_info::file_os_nt_win32
            && file_info.get_file_subtype() == 0 && file_info.get_file_type() == file_version_info::file_type_application
            && file_info.get_file_version_ls() == 0x00020001 && file_info.get_file_version_ms() == 0x00040003
            && file_info.get_product_version_ls() == 0x00070008 && file_info.get_product_version_ms() == 0x00050006
            && file_info.get_file_version_string<char>() == "4.3.2.1"
            && file_info.get_product_version_string<wchar_t>() == L"5.6.7.8", "File Version Info Parser test", test_level_normal);

    version_info_viewer ver_view(strings, translations);
    version_info_editor ver_edit(strings, translations);

    PE_TEST(version_info_viewer::translation_from_string(L"041904b0").first == 0x0419
            && version_info_viewer::translation_from_string(L"041904b0").second == 0x04b0, "translation_from_string test", test_level_normal);

    PE_TEST(ver_view.get_company_name() == L"PE Bliss", "Version Info Viewer test 1", test_level_normal);
    PE_TEST(ver_view.get_company_name(L"040004b0") == L"PE Bliss", "Version Info Viewer test 2", test_level_normal);
    PE_TEST(ver_view.get_file_description() == L"PE Bliss - Тестовый PE-файл", "Version Info Viewer test 3", test_level_normal);
    PE_TEST(ver_view.get_file_description(L"040004b0") == L"PE Bliss Test PE File", "Version Info Viewer test 4", test_level_normal);
    PE_TEST(ver_view.get_file_version() == L"4.3.2.1", "Version Info Viewer test 5", test_level_normal);
    PE_TEST(ver_view.get_file_version(L"040004b0") == L"4.3.2.1", "Version Info Viewer test 6", test_level_normal);
    PE_TEST(ver_view.get_internal_name() == L"test.exe", "Version Info Viewer test 7", test_level_normal);
    PE_TEST(ver_view.get_internal_name(L"040004b0") == L"test.exe", "Version Info Viewer test 8", test_level_normal);
    PE_TEST(ver_view.get_legal_copyright() == L"(C) dx", "Version Info Viewer test 9", test_level_normal);
    PE_TEST(ver_view.get_legal_copyright(L"040004b0") == L"(C) dx", "Version Info Viewer test 10", test_level_normal);
    PE_TEST(ver_view.get_original_filename() == L"original.exe", "Version Info Viewer test 11", test_level_normal);
    PE_TEST(ver_view.get_original_filename(L"040004b0") == L"original.exe", "Version Info Viewer test 12", test_level_normal);
    PE_TEST(ver_view.get_product_name() == L"PE Bliss - Тесты", "Version Info Viewer test 13", test_level_normal);
    PE_TEST(ver_view.get_product_name(L"040004b0") == L"PE Bliss Test", "Version Info Viewer test 14", test_level_normal);
    PE_TEST(ver_view.get_product_version() == L"5.6.7.8", "Version Info Viewer test 15", test_level_normal);
    PE_TEST(ver_view.get_product_version(L"040004b0") == L"5.6.7.8", "Version Info Viewer test 16", test_level_normal);
    PE_TEST(ver_view.get_property(L"CompanyName", L"", false) == L"PE Bliss", "Version Info Viewer test 17", test_level_normal);
    PE_TEST(ver_view.get_property(L"CompanyName", L"040004b0", false) == L"PE Bliss", "Version Info Viewer test 18", test_level_normal);
    PE_TEST(ver_view.get_property(L"TestProperty", L"", false) == L"", "Version Info Viewer test 19", test_level_normal);
    PE_TEST(ver_view.get_property(L"TestProperty", L"040004b0", false) == L"", "Version Info Viewer test 20", test_level_normal);
    PE_TEST_EXPECT_EXCEPTION(ver_view.get_property(L"TestProperty", L"", true) == L"", pe_exception::version_info_string_does_not_exist, "Version Info Viewer test 21", test_level_normal);
    PE_TEST_EXPECT_EXCEPTION(ver_view.get_property(L"TestProperty", L"040004b0", true) == L"", pe_exception::version_info_string_does_not_exist, "Version Info Viewer test 22", test_level_normal);
    PE_TEST(ver_view.get_translation_list().size() == 2, "Version Info Viewer test 23", test_level_critical);
    PE_TEST(ver_view.get_translation_list().at(1) == L"041904b0", "Version Info Viewer test 24", test_level_critical);
}
//Sets/replaces full version information:
//file_version_info: versions and file info
//lang_string_values_map: map of version info strings with encodings
//translation_values_map: map of translations
void resource_version_info_writer::set_version_info(const file_version_info& file_info,
	const lang_string_values_map& string_values,
	const translation_values_map& translations,
	uint32_t language,
	uint32_t codepage,
	uint32_t timestamp)
{
	std::string version_data;

	//Calculate total size of version resource data
	uint32_t total_version_info_length =
		static_cast<uint32_t>(sizeof(version_info_block) - sizeof(uint16_t) + sizeof(uint16_t) /* pading */
		+ (resource_version_info_reader::version_info_key.length() + 1) * 2
		+ sizeof(vs_fixedfileinfo));

	//If we have any strings values
	if(!string_values.empty())
	{
		total_version_info_length += sizeof(version_info_block) - sizeof(uint16_t); //StringFileInfo block
		total_version_info_length += SizeofStringFileInfo; //Name of block (key)

		//Add required size for version strings
		for(lang_string_values_map::const_iterator table_it = string_values.begin(); table_it != string_values.end(); ++table_it)
		{
			total_version_info_length += pe_utils::align_up(static_cast<uint32_t>(sizeof(uint16_t) * 3 + ((*table_it).first.length() + 1) * 2), sizeof(uint32_t)); //Name of child block and block size (key of string table block)

			const string_values_map& values = (*table_it).second;
			for(string_values_map::const_iterator it = values.begin(); it != values.end(); ++it)
			{
				total_version_info_length += pe_utils::align_up(static_cast<uint32_t>(sizeof(uint16_t) * 3 + ((*it).first.length() + 1) * 2), sizeof(uint32_t));
				total_version_info_length += pe_utils::align_up(static_cast<uint32_t>(((*it).second.length() + 1) * 2), sizeof(uint32_t));
			}
		}
	}

	//If we have translations
	if(!translations.empty())
	{
		total_version_info_length += (sizeof(version_info_block) - sizeof(uint16_t)) * 2; //VarFileInfo and Translation blocks
		total_version_info_length += SizeofVarFileInfoAligned; //DWORD-aligned VarFileInfo block name
		total_version_info_length += SizeofTranslationAligned; //DWORD-aligned Translation block name
		total_version_info_length += static_cast<uint32_t>(translations.size() * sizeof(uint16_t) * 2);
	}

	//Resize version data buffer
	version_data.resize(total_version_info_length);

	//Create root version block
	version_info_block root_block = {0};
	root_block.ValueLength = sizeof(vs_fixedfileinfo);
	root_block.Length = static_cast<uint16_t>(total_version_info_length);

	//Fill fixed file info
	vs_fixedfileinfo fixed_info = {0};
	fixed_info.dwFileDateLS = file_info.get_file_date_ls();
	fixed_info.dwFileDateMS = file_info.get_file_date_ms();
	fixed_info.dwFileFlags = file_info.get_file_flags();
	fixed_info.dwFileFlagsMask = vs_ffi_fileflagsmask;
	fixed_info.dwFileOS = file_info.get_file_os_raw();
	fixed_info.dwFileSubtype = file_info.get_file_subtype();
	fixed_info.dwFileType = file_info.get_file_type_raw();
	fixed_info.dwFileVersionLS = file_info.get_file_version_ls();
	fixed_info.dwFileVersionMS = file_info.get_file_version_ms();
	fixed_info.dwSignature = vs_ffi_signature;
	fixed_info.dwStrucVersion = vs_ffi_strucversion;
	fixed_info.dwProductVersionLS = file_info.get_product_version_ls();
	fixed_info.dwProductVersionMS = file_info.get_product_version_ms();

	//Write root block and fixed file info to buffer
	uint32_t data_ptr = 0;
	memcpy(&version_data[data_ptr], &root_block, sizeof(version_info_block) - sizeof(uint16_t));
	data_ptr += sizeof(version_info_block) - sizeof(uint16_t);
	memcpy(&version_data[data_ptr], resource_version_info_reader::version_info_key.c_str(), (resource_version_info_reader::version_info_key.length() + 1) * sizeof(uint16_t));
	data_ptr += static_cast<uint32_t>((resource_version_info_reader::version_info_key.length() + 1) * sizeof(uint16_t));
	memset(&version_data[data_ptr], 0, sizeof(uint16_t));
	data_ptr += sizeof(uint16_t);
	memcpy(&version_data[data_ptr], &fixed_info, sizeof(fixed_info));
	data_ptr += sizeof(fixed_info);

	//Write string values, if any
	if(!string_values.empty())
	{
		//Create string file info root block
		version_info_block string_file_info_block = {0};
		string_file_info_block.Type = 1; //Block type is string
		memcpy(&version_data[data_ptr], &string_file_info_block, sizeof(version_info_block) - sizeof(uint16_t));
		//We will calculate its length later
		version_info_block* string_file_info_block_ptr = reinterpret_cast<version_info_block*>(&version_data[data_ptr]);
		data_ptr += sizeof(version_info_block) - sizeof(uint16_t);

		uint32_t old_ptr1 = data_ptr; //Used to calculate string file info block length later
		memcpy(&version_data[data_ptr], StringFileInfo, SizeofStringFileInfo); //Write block name
		data_ptr += SizeofStringFileInfo;

		//Create string table root block (child of string file info)
		version_info_block string_table_block = {0};
		string_table_block.Type = 1; //Block type is string

		for(lang_string_values_map::const_iterator table_it = string_values.begin(); table_it != string_values.end(); ++table_it)
		{
			const string_values_map& values = (*table_it).second;

			memcpy(&version_data[data_ptr], &string_table_block, sizeof(version_info_block) - sizeof(uint16_t));
			//We will calculate its length later
			version_info_block* string_table_block_ptr = reinterpret_cast<version_info_block*>(&version_data[data_ptr]);
			data_ptr += sizeof(version_info_block) - sizeof(uint16_t);

			uint32_t old_ptr2 = data_ptr; //Used to calculate string table block length later
			uint32_t lang_key_length = static_cast<uint32_t>(((*table_it).first.length() + 1) * sizeof(uint16_t));

#ifdef PE_BLISS_WINDOWS
			memcpy(&version_data[data_ptr], (*table_it).first.c_str(), lang_key_length); //Write block key
#else
			{
				u16string str(pe_utils::to_ucs2((*table_it).first));
				memcpy(&version_data[data_ptr], str.c_str(), lang_key_length); //Write block key
			}
#endif

			data_ptr += lang_key_length;
			//Align key if necessary
			if((sizeof(uint16_t) * 3 + lang_key_length) % sizeof(uint32_t))
			{
				memset(&version_data[data_ptr], 0, sizeof(uint16_t));
				data_ptr += sizeof(uint16_t);
			}

			//Create string block (child of string table block)
			version_info_block string_block = {0};
			string_block.Type = 1; //Block type is string
			for(string_values_map::const_iterator it = values.begin(); it != values.end(); ++it)
			{
				//Calculate value length and key length of string block
				string_block.ValueLength = static_cast<uint16_t>((*it).second.length() + 1);
				uint32_t key_length = static_cast<uint32_t>(((*it).first.length() + 1) * sizeof(uint16_t));
				//Calculate length of block
				string_block.Length = static_cast<uint16_t>(pe_utils::align_up(sizeof(uint16_t) * 3 + key_length, sizeof(uint32_t)) + string_block.ValueLength * sizeof(uint16_t));

				//Write string block
				memcpy(&version_data[data_ptr], &string_block, sizeof(version_info_block) - sizeof(uint16_t));
				data_ptr += sizeof(version_info_block) - sizeof(uint16_t);

#ifdef PE_BLISS_WINDOWS
				memcpy(&version_data[data_ptr], (*it).first.c_str(), key_length); //Write block key
#else
				{
					u16string str(pe_utils::to_ucs2((*it).first));
					memcpy(&version_data[data_ptr], str.c_str(), key_length); //Write block key
				}
#endif

				data_ptr += key_length;
				//Align key if necessary
				if((sizeof(uint16_t) * 3 + key_length) % sizeof(uint32_t))
				{
					memset(&version_data[data_ptr], 0, sizeof(uint16_t));
					data_ptr += sizeof(uint16_t);
				}

				//Write block data (value)
#ifdef PE_BLISS_WINDOWS
				memcpy(&version_data[data_ptr], (*it).second.c_str(), string_block.ValueLength * sizeof(uint16_t));
#else
				{
					u16string str(pe_utils::to_ucs2((*it).second));
					memcpy(&version_data[data_ptr], str.c_str(), string_block.ValueLength * sizeof(uint16_t));
				}
#endif

				data_ptr += string_block.ValueLength * 2;
				//Align data if necessary
				if((string_block.ValueLength * 2) % sizeof(uint32_t))
				{
					memset(&version_data[data_ptr], 0, sizeof(uint16_t));
					data_ptr += sizeof(uint16_t);
				}
			}

			//Calculate string table and string file info blocks lengths
			string_table_block_ptr->Length = static_cast<uint16_t>(data_ptr - old_ptr2 + sizeof(uint16_t) * 3);
		}

		string_file_info_block_ptr->Length = static_cast<uint16_t>(data_ptr - old_ptr1 + sizeof(uint16_t) * 3);
	}

	//If we have transactions
	if(!translations.empty())
	{
		//Create root var file info block
		version_info_block var_file_info_block = {0};
		var_file_info_block.Type = 1; //Type of block is string
		//Write block header
		memcpy(&version_data[data_ptr], &var_file_info_block, sizeof(version_info_block) - sizeof(uint16_t));
		//We will calculate its length later
		version_info_block* var_file_info_block_ptr = reinterpret_cast<version_info_block*>(&version_data[data_ptr]);
		data_ptr += sizeof(version_info_block) - sizeof(uint16_t);

		uint32_t old_ptr1 = data_ptr; //Used to calculate var file info block length later
		memcpy(&version_data[data_ptr], VarFileInfoAligned, SizeofVarFileInfoAligned); //Write block key (aligned)
		data_ptr += SizeofVarFileInfoAligned;

		//Create root translation block (child of var file info block)
		version_info_block translation_block = {0};
		//Write block header
		memcpy(&version_data[data_ptr], &translation_block, sizeof(version_info_block) - sizeof(uint16_t));
		//We will calculate its length later
		version_info_block* translation_block_ptr = reinterpret_cast<version_info_block*>(&version_data[data_ptr]);
		data_ptr += sizeof(version_info_block) - sizeof(uint16_t);

		uint32_t old_ptr2 = data_ptr; //Used to calculate var file info block length later
		memcpy(&version_data[data_ptr], TranslationAligned, SizeofTranslationAligned); //Write block key (aligned)
		data_ptr += SizeofTranslationAligned;

		//Calculate translation block value length
		translation_block_ptr->ValueLength = static_cast<uint16_t>(sizeof(uint16_t) * 2 * translations.size());

		//Write translation values to block
		for(translation_values_map::const_iterator it = translations.begin(); it != translations.end(); ++it)
		{
			uint16_t lang_id = (*it).first; //Language ID
			uint16_t codepage_id = (*it).second; //Codepage ID
			memcpy(&version_data[data_ptr], &lang_id, sizeof(lang_id));
			data_ptr += sizeof(lang_id);
			memcpy(&version_data[data_ptr], &codepage_id, sizeof(codepage_id));
			data_ptr += sizeof(codepage_id);
		}

		//Calculate Translation and VarFileInfo blocks lengths
		translation_block_ptr->Length = static_cast<uint16_t>(data_ptr - old_ptr2 + sizeof(uint16_t) * 3);
		var_file_info_block_ptr->Length = static_cast<uint16_t>(data_ptr - old_ptr1 + sizeof(uint16_t) * 3);
	}

	//Add/replace version info resource
	res_.add_resource(version_data, pe_resource_viewer::resource_version, 1, language, codepage, timestamp);
}