s8 PartitionHandle::CheckGPT(u8 PartNum)
{
	GPT_HEADER *gpt_header = (GPT_HEADER*)MEM2_alloc(MAX_BYTES_PER_SECTOR);
	if(gpt_header == NULL)
		return -1;

	// Read and validate the extended boot record
	if(!interface->readSectors(1, 1, gpt_header))
	{
		MEM2_free(gpt_header);
		return -1;
	}
	if(strncmp(gpt_header->magic, "EFI PART", 8) != 0)
	{
		MEM2_free(gpt_header);
		return -1;
	}

	gpt_header->part_table_lba = le64(gpt_header->part_table_lba);
	gpt_header->part_entries = le32(gpt_header->part_entries);
	gpt_header->part_entry_size = le32(gpt_header->part_entry_size);
	gpt_header->part_entry_checksum = le32(gpt_header->part_entry_checksum);

	u8 *sector_buf = (u8*)MEM2_alloc(MAX_BYTES_PER_SECTOR);
	if(sector_buf == NULL)
	{
		MEM2_free(gpt_header);
		return -1;
	}
	u64 next_lba = gpt_header->part_table_lba;
	for(u32 i = 0; i < gpt_header->part_entries; ++i)
	{
		if(!interface->readSectors(next_lba, 1, sector_buf))
			break;

		for(u32 n = 0; n < BYTES_PER_SECTOR/gpt_header->part_entry_size; ++n, ++i)
		{
			GUID_PART_ENTRY *part_entry = (GUID_PART_ENTRY*)(sector_buf+gpt_header->part_entry_size*n);

			if(memcmp(part_entry->part_type_guid, TYPE_UNUSED, 16) == 0)
				continue;

			if(IsExisting(le64(part_entry->part_first_lba)))
				continue;

			bool bootable = (memcmp(part_entry->part_type_guid, TYPE_BIOS, 16) == 0);

			AddPartition("GUID-Entry", le64(part_entry->part_first_lba), le64(part_entry->part_last_lba), bootable, PARTITION_TYPE_GPT, PartNum);
		}
		next_lba++;
	}
	MEM2_free(sector_buf);
	MEM2_free(gpt_header);
	return 0;
}
Exemple #2
0
	void *__wrap_malloc(size_t size)
	{
		void *p;
		if ((SYS_GetArena1Lo() >= MAX_MEM1_ARENA_LO) || size >= MEM2_PRIORITY_SIZE)
		{
			p = MEM2_alloc(size);
			return p != 0 ? p : __real_malloc(size);
		}
		p = __real_malloc(size);
		return p != 0 ? p : MEM2_alloc(size);
	}
Exemple #3
0
	void *__wrap_memalign(size_t a, size_t size)
	{
		void *p;
		if ((SYS_GetArena1Lo() >= MAX_MEM1_ARENA_LO) || size >= MEM2_PRIORITY_SIZE)
		{
			if (a <= 32 && 32 % a == 0)
			{
				p = MEM2_alloc(size);
				if (p != 0) return p;
			}
			return __real_memalign(a, size);
		}
		p = __real_memalign(a, size);
		return p != 0 ? p : MEM2_alloc(size);
	}
void BNSDecoder::OpenFile()
{
	u8 *tempbuff = (u8*)MEM2_alloc(file_fd->size());
	if(!tempbuff)
	{
		CloseFile();
		return;
	}

	int done = 0;

	while(done < file_fd->size())
	{
		int read = file_fd->read(tempbuff+done, file_fd->size()-done);
		if(read > 0)
			done += read;
		else
		{
			CloseFile();
			MEM2_free(tempbuff);
			return;
		}
	}

	SoundData = DecodefromBNS(tempbuff, done);
	MEM2_free(tempbuff);
	if(SoundData.buffer == NULL)
	{
		CloseFile();
		return;
	}
	Decode();
}
void PartitionHandle::CheckEBR(u8 PartNum, sec_t ebr_lba)
{
	EXTENDED_BOOT_RECORD *ebr = (EXTENDED_BOOT_RECORD*)MEM2_alloc(MAX_BYTES_PER_SECTOR);
	if(ebr == NULL)
		return;
	sec_t next_erb_lba = 0;

	do
	{
		// Read and validate the extended boot record
		if(!interface->readSectors(ebr_lba + next_erb_lba, 1, ebr))
		{
			MEM2_free(ebr);
			return;
		}
		if(ebr->signature != EBR_SIGNATURE && ebr->signature != EBR_SIGNATURE_MOD)
		{
			MEM2_free(ebr);
			return;
		}

		if(le32(ebr->partition.block_count) > 0 && !IsExisting(ebr_lba + next_erb_lba + le32(ebr->partition.lba_start)))
		{
			AddPartition(PartFromType(ebr->partition.type), ebr_lba + next_erb_lba + le32(ebr->partition.lba_start),
					le32(ebr->partition.block_count), (ebr->partition.status == PARTITION_BOOTABLE), ebr->partition.type, PartNum);
		}
		// Get the start sector of the current partition
		// and the next extended boot record in the chain
		next_erb_lba = le32(ebr->next_ebr.lba_start);
	}
	while(next_erb_lba > 0);

	MEM2_free(ebr);
}
Exemple #6
0
bool PoPPatch()
{
	if (memcmp("SPX", (char *) 0x80000000, 3) != 0 && memcmp("RPW", (char *) 0x80000000, 3) != 0)
		return false;

	WIP_Code * CodeList = MEM2_alloc(5 * sizeof(WIP_Code));
	CodeList[0].offset = 0x007AAC6A;
	CodeList[0].srcaddress = 0x7A6B6F6A;
	CodeList[0].dstaddress = 0x6F6A7A6B;
	CodeList[1].offset = 0x007AAC75;
	CodeList[1].srcaddress = 0x7C7A6939;
	CodeList[1].dstaddress = 0x69397C7A;
	CodeList[2].offset = 0x007AAC82;
	CodeList[2].srcaddress = 0x7376686B;
	CodeList[2].dstaddress = 0x686B7376;
	CodeList[3].offset = 0x007AAC92;
	CodeList[3].srcaddress = 0x80717570;
	CodeList[3].dstaddress = 0x75708071;
	CodeList[4].offset = 0x007AAC9D;
	CodeList[4].srcaddress = 0x82806F3F;
	CodeList[4].dstaddress = 0x6F3F8280;

	if (set_wip_list(CodeList, 5) == false)
	{
		MEM2_free(CodeList);
		CodeList = NULL;
		return false;
	}

	return true;
}
void GC_Disc::Read_FST(FILE *f, u32 FST_size)
{
	if(f == NULL)
		return;
	FSTable = (u8*)MEM2_alloc(FST_size);
	if(FSTable == NULL)
		return;
	fread(FSTable, 1, FST_size, f);

	FSTEnt = *(u32*)(FSTable + 0x08);
	FSTNameOff = (char*)(FSTable + FSTEnt * 0x0C);
}
Exemple #8
0
	void *__wrap_calloc(size_t n, size_t size)
	{
		void *p;
		if ((SYS_GetArena1Lo() >= MAX_MEM1_ARENA_LO) || (n * size) >= MEM2_PRIORITY_SIZE)
		{
			p = MEM2_alloc(n * size);
			if (p != 0)
			{
				memset(p, 0, n * size);
				return p;
			}
			return __real_calloc(n, size);
		}

		p = __real_calloc(n, size);
		if (p != 0) return p;

		p = MEM2_alloc(n * size);
		if (p != 0) memset(p, 0, n * size);
		return p;
	}
Exemple #9
0
signed_blob *GetTMD(u8 ios, u32 *TMD_Length)
{
	if(ES_GetStoredTMDSize(TITLE_ID(1, ios), TMD_Length) < 0)
		return NULL;

	signed_blob *TMD = (signed_blob*)MEM2_alloc(*TMD_Length);
	if(TMD == NULL)
		return NULL;
	if(ES_GetStoredTMD(TITLE_ID(1, ios), TMD, *TMD_Length) < 0)
	{
		MEM2_free(TMD);
		return NULL;
	}
	return TMD;
}
void PartitionHandle::AddPartition(const char *name, u64 lba_start, u64 sec_count, bool bootable, u8 part_type, u8 part_num)
{
	u8 *buffer = (u8*)MEM2_alloc(MAX_BYTES_PER_SECTOR);
	if(buffer == NULL)
		return;

	if(!interface->readSectors(lba_start, 1, buffer))
	{
		MEM2_free(buffer);
		return;
	}

	wbfs_head_t *head = (wbfs_head_t*)buffer;

	if(head->magic == wbfs_htonl(WBFS_MAGIC))
	{
		name = "WBFS";
		part_type = 0xBF;   //Override partition type on WBFS
		//! correct sector size in physical sectors (512 bytes per sector)
		sec_count = (u64) head->n_hd_sec * (u64) (1 << head->hd_sec_sz_s) / (u64) BYTES_PER_SECTOR;
	}
	else if(*((u16 *)(buffer + 0x1FE)) == 0x55AA)
	{
		//! Partition type can be missleading the correct partition format. Stupid lazy ass Partition Editors.
		if((memcmp(buffer + 0x36, "FAT", 3) == 0 || memcmp(buffer + 0x52, "FAT", 3) == 0) &&
			strncmp(PartFromType(part_type), "FAT", 3) != 0)
		{
			name = "FAT32";
			part_type = 0x0c;
		}
		if(memcmp(buffer + 0x03, "NTFS", 4) == 0)
		{
			name = "NTFS";
			part_type = 0x07;
		}
	}

	PartitionFS PartitionEntry;
	PartitionEntry.FSName = name;
	PartitionEntry.LBA_Start = lba_start;
	PartitionEntry.SecCount = sec_count;
	PartitionEntry.Bootable = bootable;
	PartitionEntry.PartitionType = part_type;
	PartitionEntry.PartitionNum = part_num;
	PartitionList.push_back(PartitionEntry);
	MEM2_free(buffer);
}
s32 USBStorage2_WriteSectors(u32 port, u32 sector, u32 numSectors, const void *buffer)
{
	u8 *buf = (u8 *) buffer;
	s32 ret = -1;

	/* Device not opened */
	if (fd < 0) return fd;

	/* Device not opened */
	if (!mem2_ptr)
		mem2_ptr = (u8 *) MEM2_alloc(MAX_SECTOR_SIZE * MAX_BUFFER_SECTORS);

	USBStorage2_SetPort(port);

	s32 write_size, write_secs;

	while(numSectors > 0)
	{
		write_secs = numSectors > MAX_BUFFER_SECTORS ? MAX_BUFFER_SECTORS : numSectors;
		write_size = write_secs*hdd_sector_size[port];

		/* MEM1 buffer */
		if (!isMEM2Buffer(buffer))
		{
			// Do not read more than MAX_BUFFER_SECTORS sectors at once and create a mem overflow!
			memcpy(mem2_ptr, buf, write_size);

			ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_UMS_WRITE_SECTORS, "ii:d", sector, write_secs, mem2_ptr, write_size);
			if(ret < 0)
				return ret;
		}
		else
		{
			/* Write data */
			ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_UMS_WRITE_SECTORS, "ii:d", sector, write_secs, buf, write_size);
			if(ret < 0)
				return ret;
		}

		sector += write_secs;
		numSectors -= write_secs;
		buf += write_size;
	}

	return ret;
}
Exemple #12
0
void RegisterDOL(u8 *dst, int len)
{
	if(!dolList)
		dolList = (appDOL *) MEM2_alloc(sizeof(appDOL));

	appDOL *tmp = (appDOL *) MEM2_realloc(dolList, (dolCount+1)*sizeof(appDOL));
	if(!tmp)
	{
		MEM2_free(dolList);
		dolCount = 0;
		return;
	}

	dolList = tmp;
	dolList[dolCount].dst = dst;
	dolList[dolCount].len = len;
	dolCount++;
}
void GC_Disc::init(const char *path)
{
	strncpy(GamePath, path, MAX_FAT_PATH);
	opening_bnr = NULL;
	FSTable = NULL;

	FILE *f = NULL;
	u32 FSTSize = 0;
	if(strstr(GamePath, "boot.bin") != NULL)
	{
		GameType = TYPE_FST;
		if(strchr(GamePath, '/') != NULL) //boot.bin
			*strrchr(GamePath, '/') = '\0';
		if(strchr(GamePath, '/') != NULL) //sys
			*strrchr(GamePath, '/') = '\0';
		char *FstPath = fmt_malloc("%s/sys/fst.bin", GamePath);
		if(FstPath != NULL)
		{
			fsop_GetFileSizeBytes(FstPath, &FSTSize);
			f = fopen(FstPath, "rb");
			MEM2_free(FstPath);
		}
	}
	else
	{
		GameType = TYPE_ISO;
		f = fopen(GamePath, "rb");
		if(f == NULL)
			return;
		u8 *ReadBuffer = (u8*)MEM2_alloc(0x440);
		if(ReadBuffer == NULL)
			return;
		fread(ReadBuffer, 1, 0x440, f);
		u32 FSTOffset = *(u32*)(ReadBuffer + 0x424);
		FSTSize = *(u32*)(ReadBuffer + 0x428);
		MEM2_free(ReadBuffer);
		fseek(f, FSTOffset, SEEK_SET);
	}
	if(f != NULL)
	{
		Read_FST(f, FSTSize);
		fclose(f);
	}
}
s32 USBStorage2_ReadSectors(u32 port, u32 sector, u32 numSectors, void *buffer)
{
	u8 *buf = (u8 *) buffer;
	s32 ret = -1;

	/* Device not opened */
	if (fd < 0) return fd;

	if (!mem2_ptr)
		mem2_ptr = (u8 *) MEM2_alloc(MAX_SECTOR_SIZE * MAX_BUFFER_SECTORS);

	USBStorage2_SetPort(port);

	s32 read_secs, read_size;

	while(numSectors > 0)
	{
		read_secs = numSectors > MAX_BUFFER_SECTORS ? MAX_BUFFER_SECTORS : numSectors;
		read_size = read_secs*hdd_sector_size[port];

		// Do not read more than MAX_BUFFER_SECTORS sectors at once and create a mem overflow!
		if (!isMEM2Buffer(buffer))
		{
			ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_UMS_READ_SECTORS, "ii:d", sector, read_secs, mem2_ptr, read_size);
			if(ret < 0)
				return ret;

			memcpy(buf, mem2_ptr, read_size);
		}
		else
		{
			/* Read data */
			ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_UMS_READ_SECTORS, "ii:d", sector, read_secs, buf, read_size);
			if(ret < 0)
				return ret;
		}

		sector += read_secs;
		numSectors -= read_secs;
		buf += read_size;
	}

	return ret;
}
s8 PartitionHandle::FindPartitions()
{
	MASTER_BOOT_RECORD *mbr = (MASTER_BOOT_RECORD*)MEM2_alloc(MAX_BYTES_PER_SECTOR);
	if(mbr == NULL)
		return -1;

	// Read the first sector on the device
	if(!interface->readSectors(0, 1, mbr))
	{
		MEM2_free(mbr);
		return -1;
	}

	// If this is the devices master boot record
	if(mbr->signature != MBR_SIGNATURE && mbr->signature != MBR_SIGNATURE_MOD)
	{
		MEM2_free(mbr);
		return -1;
	}

	for(u8 i = 0; i < 4; i++)
	{
		PARTITION_RECORD *partition = (PARTITION_RECORD *)&mbr->partitions[i];

		if(partition->type == PARTITION_TYPE_GPT)
		{
			s8 ret = CheckGPT(i);
			if(ret == 0) // if it's a GPT we don't need to go on looking through the mbr anymore
				return ret;
		}
		if(partition->type == PARTITION_TYPE_DOS33_EXTENDED || partition->type == PARTITION_TYPE_WIN95_EXTENDED)
		{
			CheckEBR(i, le32(partition->lba_start));
			continue;
		}
		if(le32(partition->block_count) > 0 && !IsExisting(le32(partition->lba_start)))
		{
			AddPartition(PartFromType(partition->type), le32(partition->lba_start),
					le32(partition->block_count), (partition->status == PARTITION_BOOTABLE), partition->type, i);
		}
	}
	MEM2_free(mbr);
	return 0;
}
void GX2InitShader(GX2Shader *shader)
{
   if (shader->fs.program)
      return;

   shader->fs.size = GX2CalcFetchShaderSizeEx(shader->vs.attribVarCount,
                     GX2_FETCH_SHADER_TESSELLATION_NONE, GX2_TESSELLATION_MODE_DISCRETE);
#ifdef GX2_CAN_ACCESS_DATA_SECTION
   shader->fs.program = MEM2_alloc(shader->fs.size, GX2_SHADER_ALIGNMENT);
#else
   shader->fs.program = MEM2_alloc(shader->fs.size + sizeof(org_programs_t), GX2_SHADER_ALIGNMENT);
#endif
   GX2InitFetchShaderEx(&shader->fs, (uint8_t *)shader->fs.program,
                        shader->vs.attribVarCount,
                        shader->attribute_stream,
                        GX2_FETCH_SHADER_TESSELLATION_NONE, GX2_TESSELLATION_MODE_DISCRETE);
   GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, shader->fs.program, shader->fs.size);

#ifndef GX2_CAN_ACCESS_DATA_SECTION
   org_programs_t *org = (org_programs_t *)(shader->fs.program + shader->fs.size);
   org->vs_program = shader->vs.program;
   org->ps_program = shader->ps.program;
   org->gs_program = shader->gs.program;
   org->gs_copy_program = shader->gs.copyProgram;

   shader->vs.program = MEM2_alloc(shader->vs.size, GX2_SHADER_ALIGNMENT);
   memcpy(shader->vs.program, org->vs_program, shader->vs.size);
   GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, shader->vs.program, shader->vs.size);

   shader->ps.program = MEM2_alloc(shader->ps.size, GX2_SHADER_ALIGNMENT);
   memcpy(shader->ps.program, org->ps_program, shader->ps.size);
   GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, shader->ps.program, shader->ps.size);

   if (org->gs_program)
   {
      shader->gs.program = MEM2_alloc(shader->gs.size, GX2_SHADER_ALIGNMENT);
      memcpy(shader->gs.program, org->gs_program, shader->gs.size);
      GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, shader->gs.program, shader->gs.size);

      shader->gs.copyProgram = MEM2_alloc(shader->gs.copyProgramSize, GX2_SHADER_ALIGNMENT);
      memcpy(shader->gs.copyProgram, org->gs_copy_program, shader->gs.copyProgramSize);
      GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, shader->gs.copyProgram, shader->gs.copyProgramSize);
   }

#endif

}
Exemple #17
0
bool SFont::fromBuffer(const u8 *buffer, const u32 bufferSize, u32 size, u32 lspacing, u32 w, u32 idx, const char *fontname)
{
	if(buffer == NULL)
		return false;
	fSize = min(max(6u, size), 1000u);
	lineSpacing = min(max(6u, lspacing), 1000u);
	weight = min(w, 32u);
	index = idx;

	if(data != NULL)
		free(data);
	data = (u8*)MEM2_alloc(bufferSize);
	if(data == NULL) return false;
	dataSize = bufferSize;

	memcpy(data, buffer, bufferSize);
	DCFlushRange(data, dataSize);

	memcpy(name, fontname, 127);
	font = new FreeTypeGX();
	font->loadFont(data, dataSize, fSize, weight, index, false);
	return true;
}
u8 *GC_Disc::GetGameCubeBanner()
{
	if(FSTable == NULL || GamePath == NULL)
		return NULL;

	FILE *bnr_fp = NULL;
	u32 BnrSize = 0;

	FST *fst = (FST*)FSTable;
	for(u32 i = 1; i < FSTEnt; ++i)
	{
		if(fst[i].Type) //Folder
			continue;
		else if(strcmp(FSTNameOff + fst[i].NameOffset, "opening.bnr") == 0)
		{
			if(GameType == TYPE_FST)
				bnr_fp = fopen(fmt("%s/root/opening.bnr", GamePath), "rb");
			else
			{
				bnr_fp = fopen(GamePath, "rb");
				if(bnr_fp != NULL)
					fseek(bnr_fp, fst[i].FileOffset, SEEK_SET);
			}
			BnrSize = fst[i].FileLength;
			break;
		}
	}

	if(bnr_fp != NULL)
	{
		opening_bnr = (u8*)MEM2_alloc(BnrSize);
		if(opening_bnr != NULL && fread(opening_bnr, 1, BnrSize, bnr_fp) != BnrSize)
			MEM2_free(opening_bnr);
		fclose(bnr_fp);
	}
	return opening_bnr;
}
Exemple #19
0
u8 *ISFS_GetFile(u8 *path, u32 *size, s32 length)
{
	*size = 0;
	
	s32 fd = ISFS_Open((const char *) path, ISFS_OPEN_READ);
	u8 *buf = NULL;
	static fstats stats ATTRIBUTE_ALIGN(32);
	
	if (fd >= 0)
	{
		if (ISFS_GetFileStats(fd, &stats) >= 0)
		{
			if (length <= 0) length = stats.file_length;
			if (length > 0)
				buf = (u8 *) MEM2_alloc(ALIGN32(length));

			if (buf)
			{
				*size = stats.file_length;
				if (ISFS_Read(fd, (char*)buf, length) != length)
				{
					*size = 0;
					SAFE_FREE(buf);
				}
			}
		}
		ISFS_Close(fd);
	}

	if (*size > 0)
	{
		DCFlushRange(buf, *size);
		ICInvalidateRange(buf, *size);
	}
	
	return buf;
}
Exemple #20
0
	void *__wrap_realloc(void *p, size_t size)
	{
		void *n;
		// ptr from mem2
		if (((u32)p & 0x10000000) != 0 || (p == 0 && size > MEM2_PRIORITY_SIZE))
		{
			n = MEM2_realloc(p, size);
			if (n != 0) {
				return n;
			}
			n = __real_malloc(size);
			if (n == 0) {
				return 0;
			}
			if (p != 0)
			{
				memcpy(n, p, MEM2_usableSize(p) < size ? MEM2_usableSize(p) : size);
				MEM2_free(p);
			}
			return n;
		}
		// ptr from malloc
		n = __real_realloc(p, size);
		if (n != 0) {
			return n;
		}
		n = MEM2_alloc(size);
		if (n == 0) {
			return 0;
		}
		if (p != 0)
		{
			memcpy(n, p, __real_malloc_usable_size(p) < size ? __real_malloc_usable_size(p) : size);
			__real_free(p);
		}
		return n;
	}
GFDFile *gfd_open(const char *filename)
{
   GFDFile* gfd = calloc(1, sizeof(*gfd));
   FILE *fp = fopen(filename, "rb");

   if (!fp)
      goto error;

   fseek(fp, 0, SEEK_END);
   int size = ftell(fp);
   fseek(fp, 0, SEEK_SET);
   gfd->data = MEM2_alloc(size, GX2_SHADER_ALIGNMENT);
   fread(gfd->data, 1, size, fp);
   fclose(fp);

   GFDFileHeader *header = (GFDFileHeader *)gfd->data;

   if (header->magic != GFD_FILE_MAGIC)
   {
      printf("wrong file magic number.\n");
      goto error;
   }

   if (header->headerSize != sizeof(GFDFileHeader))
   {
      printf("wrong file header size.\n");
      goto error;
   }

   if (header->majorVersion != GFD_FILE_MAJOR_VERSION)
   {
      printf("file version not supported.\n");
      goto error;
   }

   if (header->gpuVersion != GFD_FILE_GPU_VERSION)
   {
      printf("gpu version not supported.\n");
      goto error;
   }

   if (!header->align)
   {
      printf("data is not aligned.\n");
      goto error;
   }

   GFDBlock *block = (GFDBlock *)(gfd->data + header->headerSize);

   while (block->header.type != GFD_BLOCK_TYPE_END_OF_FILE)
   {
      if (block->header.magic != GFD_BLOCK_MAGIC)
      {
         printf("wrong block magic number.\n");
         goto error;
      }

      if (block->header.headerSize != sizeof(GFDBlockHeader))
      {
         printf("wrong block header size.\n");
         goto error;
      }

      if (block->header.majorVersion != GFD_BLOCK_MAJOR_VERSION)
      {
         printf("block version not supported.\n");
         goto error;
      }

      switch (block->header.type)
      {
      case GFD_BLOCK_TYPE_VERTEX_SHADER_HEADER:
         if (gfd->vs)
            continue;

         gfd->vs = (GX2VertexShader*)block->data;
         if(!gfd_relocate_block(block))
            goto error;

         break;

      case GFD_BLOCK_TYPE_VERTEX_SHADER_PROGRAM:
         if(gfd->vs->program)
            continue;

         GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, block->data, block->header.dataSize);
         gfd->vs->program = block->data;
         break;

      case GFD_BLOCK_TYPE_PIXEL_SHADER_HEADER:
         if (gfd->ps)
            continue;

         gfd->ps = (GX2PixelShader*)block->data;
         if(!gfd_relocate_block(block))
            goto error;

         break;

      case GFD_BLOCK_TYPE_PIXEL_SHADER_PROGRAM:
         if(gfd->ps->program)
            continue;

         GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, block->data, block->header.dataSize);
         gfd->ps->program = block->data;
         break;

      default:
         break;
      }

      block = (GFDBlock *)((u8 *)block + block->header.headerSize + block->header.dataSize);
   }

   if(!gfd->vs)
   {
      printf("vertex shader is missing.\n");
      goto error;
   }

   if(!gfd->vs->program)
   {
      printf("vertex shader program is missing.\n");
      goto error;
   }

   if(!gfd->ps)
   {
      printf("pixel shader is missing.\n");
      goto error;
   }

   if(!gfd->ps->program)
   {
      printf("pixel shader program is missing.\n");
      goto error;
   }

   return gfd;

error:
   printf("failed to open file : %s\n", filename);
   gfd_free(gfd);

   return NULL;
}
Exemple #22
0
/* Placeholder, will be needed with new memory manager */
void *MEM2_memalign(unsigned int /* alignment */, unsigned int s)
{
	return MEM2_alloc(s);
}
Exemple #23
0
static void* wiiu_gfx_init(const video_info_t* video,
                           const input_driver_t** input, void** input_data)
{
   int i;
   *input = NULL;
   *input_data = NULL;

   wiiu_video_t* wiiu = calloc(1, sizeof(*wiiu));

   if (!wiiu)
      return NULL;

   void* wiiuinput   = NULL;
   if (input && input_data)
   {
      wiiuinput = input_wiiu.init();
      *input = wiiuinput ? &input_wiiu : NULL;
      *input_data = wiiuinput;
   }

   /* video init */
   wiiu->cmd_buffer = MEM2_alloc(0x400000, 0x40);
   u32 init_attributes[] =
   {
      GX2_INIT_CMD_BUF_BASE, (u32)wiiu->cmd_buffer,
      GX2_INIT_CMD_BUF_POOL_SIZE, 0x400000,
      GX2_INIT_ARGC, 0,
      GX2_INIT_ARGV, 0,
      GX2_INIT_END
   };
   GX2Init(init_attributes);

   /* setup scanbuffers */
   u32 size = 0;
   u32 tmp = 0;
   wiiu->render_mode = wiiu_render_mode_map[GX2GetSystemTVScanMode()];
   GX2CalcTVSize(wiiu->render_mode.mode, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8, GX2_BUFFERING_MODE_DOUBLE, &size, &tmp);
   wiiu->tv_scan_buffer = MEMBucket_alloc(size, GX2_SCAN_BUFFER_ALIGNMENT);
   GX2Invalidate(GX2_INVALIDATE_MODE_CPU, wiiu->tv_scan_buffer, size);
   GX2SetTVBuffer(wiiu->tv_scan_buffer, size, wiiu->render_mode.mode, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8,
                  GX2_BUFFERING_MODE_DOUBLE);

   GX2CalcDRCSize(GX2_DRC_RENDER_MODE_SINGLE, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8, GX2_BUFFERING_MODE_DOUBLE, &size,
                  &tmp);
   wiiu->drc_scan_buffer = MEMBucket_alloc(size, GX2_SCAN_BUFFER_ALIGNMENT);
   GX2Invalidate(GX2_INVALIDATE_MODE_CPU, wiiu->drc_scan_buffer, size);
   GX2SetDRCBuffer(wiiu->drc_scan_buffer, size, GX2_DRC_RENDER_MODE_SINGLE, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8,
                   GX2_BUFFERING_MODE_DOUBLE);

   memset(&wiiu->color_buffer, 0, sizeof(GX2ColorBuffer));
   wiiu->color_buffer.surface.dim = GX2_SURFACE_DIM_TEXTURE_2D;
   wiiu->color_buffer.surface.width = wiiu->render_mode.width;
   wiiu->color_buffer.surface.height = wiiu->render_mode.height;
   wiiu->color_buffer.surface.depth = 1;
   wiiu->color_buffer.surface.mipLevels = 1;
   wiiu->color_buffer.surface.format = GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8;
   wiiu->color_buffer.surface.use = GX2_SURFACE_USE_TEXTURE_COLOR_BUFFER_TV;
   wiiu->color_buffer.viewNumSlices = 1;
   GX2CalcSurfaceSizeAndAlignment(&wiiu->color_buffer.surface);
   GX2InitColorBufferRegs(&wiiu->color_buffer);

   wiiu->color_buffer.surface.image = MEM1_alloc(wiiu->color_buffer.surface.imageSize,
                                      wiiu->color_buffer.surface.alignment);
   GX2Invalidate(GX2_INVALIDATE_MODE_CPU, wiiu->color_buffer.surface.image, wiiu->color_buffer.surface.imageSize);

   wiiu->ctx_state = (GX2ContextState*)MEM2_alloc(sizeof(GX2ContextState), GX2_CONTEXT_STATE_ALIGNMENT);
   GX2SetupContextStateEx(wiiu->ctx_state, GX2_TRUE);

   GX2SetContextState(wiiu->ctx_state);
   GX2SetColorBuffer(&wiiu->color_buffer, GX2_RENDER_TARGET_0);
   GX2SetViewport(0.0f, 0.0f, wiiu->color_buffer.surface.width, wiiu->color_buffer.surface.height, 0.0f, 1.0f);
   GX2SetScissor(0, 0, wiiu->color_buffer.surface.width, wiiu->color_buffer.surface.height);
   GX2SetDepthOnlyControl(GX2_DISABLE, GX2_DISABLE, GX2_COMPARE_FUNC_ALWAYS);
   GX2SetColorControl(GX2_LOGIC_OP_COPY, 1, GX2_DISABLE, GX2_ENABLE);
#if 1
   GX2SetBlendControl(GX2_RENDER_TARGET_0, GX2_BLEND_MODE_SRC_ALPHA, GX2_BLEND_MODE_INV_SRC_ALPHA, GX2_BLEND_COMBINE_MODE_ADD,
                      GX2_ENABLE,          GX2_BLEND_MODE_SRC_ALPHA, GX2_BLEND_MODE_INV_SRC_ALPHA, GX2_BLEND_COMBINE_MODE_ADD);
#else
   GX2SetBlendControl(GX2_RENDER_TARGET_0, GX2_BLEND_MODE_ONE, GX2_BLEND_MODE_ZERO, GX2_BLEND_COMBINE_MODE_ADD,
                      GX2_DISABLE,         GX2_BLEND_MODE_ONE, GX2_BLEND_MODE_ZERO, GX2_BLEND_COMBINE_MODE_ADD);
#endif
   GX2SetCullOnlyControl(GX2_FRONT_FACE_CCW, GX2_DISABLE, GX2_DISABLE);
#ifdef GX2_CAN_ACCESS_DATA_SECTION
   wiiu->shader = &tex_shader;
#else
   /* init shader */
   //   wiiu->shader = MEM2_alloc(sizeof(*wiiu->shader), GX2_VERTEX_BUFFER_ALIGNMENT);
   wiiu->shader = MEM2_alloc(sizeof(tex_shader), 0x1000);
   memcpy(wiiu->shader, &tex_shader, sizeof(tex_shader));
   GX2Invalidate(GX2_INVALIDATE_MODE_CPU, wiiu->shader, sizeof(tex_shader));

   wiiu->shader->vs.program = MEM2_alloc(wiiu->shader->vs.size, GX2_SHADER_ALIGNMENT);
   memcpy(wiiu->shader->vs.program, tex_shader.vs.program, wiiu->shader->vs.size);
   GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, wiiu->shader->vs.program, wiiu->shader->vs.size);
   wiiu->shader->vs.attribVars = MEM2_alloc(wiiu->shader->vs.attribVarCount * sizeof(GX2AttribVar),
         GX2_SHADER_ALIGNMENT);
   memcpy(wiiu->shader->vs.attribVars, tex_shader.vs.attribVars ,
          wiiu->shader->vs.attribVarCount * sizeof(GX2AttribVar));

   wiiu->shader->ps.program = MEM2_alloc(wiiu->shader->ps.size, GX2_SHADER_ALIGNMENT);
   memcpy(wiiu->shader->ps.program, tex_shader.ps.program, wiiu->shader->ps.size);
   GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, wiiu->shader->ps.program, wiiu->shader->ps.size);
   wiiu->shader->ps.samplerVars = MEM2_alloc(wiiu->shader->ps.samplerVarCount * sizeof(GX2SamplerVar),
         GX2_SHADER_ALIGNMENT);
   memcpy(wiiu->shader->ps.samplerVars, tex_shader.ps.samplerVars,
          wiiu->shader->ps.samplerVarCount * sizeof(GX2SamplerVar));

#endif
   wiiu->shader->fs.size = GX2CalcFetchShaderSizeEx(2, GX2_FETCH_SHADER_TESSELLATION_NONE, GX2_TESSELLATION_MODE_DISCRETE);
   wiiu->shader->fs.program = MEM2_alloc(wiiu->shader->fs.size, GX2_SHADER_ALIGNMENT);
   GX2InitFetchShaderEx(&wiiu->shader->fs, (uint8_t*)wiiu->shader->fs.program,
                        sizeof(wiiu->shader->attribute_stream) /  sizeof(GX2AttribStream),
                        (GX2AttribStream*)&wiiu->shader->attribute_stream,
                        GX2_FETCH_SHADER_TESSELLATION_NONE, GX2_TESSELLATION_MODE_DISCRETE);
   GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, wiiu->shader->fs.program, wiiu->shader->fs.size);
   GX2SetVertexShader(&wiiu->shader->vs);
   GX2SetPixelShader(&wiiu->shader->ps);
   GX2SetFetchShader(&wiiu->shader->fs);

   wiiu->position = MEM2_alloc(4 * sizeof(*wiiu->position), GX2_VERTEX_BUFFER_ALIGNMENT);
   wiiu_set_position(wiiu->position, &wiiu->color_buffer, 0, 0, wiiu->color_buffer.surface.width, wiiu->color_buffer.surface.height);

   wiiu->tex_coord = MEM2_alloc(4 * sizeof(*wiiu->tex_coord), GX2_VERTEX_BUFFER_ALIGNMENT);
   wiiu_set_tex_coords(wiiu->tex_coord, &wiiu->texture, 0, 0, wiiu->texture.surface.width, wiiu->texture.surface.height);

   GX2SetAttribBuffer(0, 4 * sizeof(*wiiu->position), sizeof(*wiiu->position), wiiu->position);
   GX2SetAttribBuffer(1, 4 * sizeof(*wiiu->tex_coord), sizeof(*wiiu->tex_coord), wiiu->tex_coord);

   wiiu->menu.position = MEM2_alloc(4 * sizeof(*wiiu->menu.position), GX2_VERTEX_BUFFER_ALIGNMENT);
   wiiu_set_position(wiiu->menu.position, &wiiu->color_buffer, 0, 0, wiiu->color_buffer.surface.width, wiiu->color_buffer.surface.height);

   wiiu->menu.tex_coord = MEM2_alloc(4 * sizeof(*wiiu->menu.tex_coord), GX2_VERTEX_BUFFER_ALIGNMENT);
   wiiu_set_tex_coords(wiiu->menu.tex_coord, &wiiu->menu.texture, 0, 0, wiiu->menu.texture.surface.width, wiiu->menu.texture.surface.height);

   /* init frame texture */
   memset(&wiiu->texture, 0, sizeof(GX2Texture));
   wiiu->texture.surface.width    = video->input_scale * RARCH_SCALE_BASE;
   wiiu->texture.surface.height   = video->input_scale * RARCH_SCALE_BASE;
   wiiu->texture.surface.depth    = 1;
   wiiu->texture.surface.dim      = GX2_SURFACE_DIM_TEXTURE_2D;
   wiiu->texture.surface.tileMode = GX2_TILE_MODE_LINEAR_ALIGNED;
   wiiu->texture.viewNumSlices    = 1;
   wiiu->rgb32 = video->rgb32;
   if(wiiu->rgb32)
   {
      wiiu->texture.surface.format   = GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8;
      wiiu->texture.compMap          = GX2_COMP_SEL(_G, _B, _A, _1);
   }
   else
   {
      wiiu->texture.surface.format   = GX2_SURFACE_FORMAT_UNORM_R5_G6_B5;
      wiiu->texture.compMap          = GX2_COMP_SEL(_B, _G, _R, _1);
   }
   GX2CalcSurfaceSizeAndAlignment(&wiiu->texture.surface);
   GX2InitTextureRegs(&wiiu->texture);

   wiiu->texture.surface.image = MEM2_alloc(wiiu->texture.surface.imageSize,
                                 wiiu->texture.surface.alignment);
   memset(wiiu->texture.surface.image, 0x0, wiiu->texture.surface.imageSize);
   GX2Invalidate(GX2_INVALIDATE_MODE_CPU_TEXTURE, wiiu->texture.surface.image,
                 wiiu->texture.surface.imageSize);

   /* init menu texture */
   memset(&wiiu->menu.texture, 0, sizeof(GX2Texture));
   wiiu->menu.texture.surface.width    = 512;
   wiiu->menu.texture.surface.height   = 512;
   wiiu->menu.texture.surface.depth    = 1;
   wiiu->menu.texture.surface.dim      = GX2_SURFACE_DIM_TEXTURE_2D;
   wiiu->menu.texture.surface.format   = GX2_SURFACE_FORMAT_UNORM_R4_G4_B4_A4;
   wiiu->menu.texture.surface.tileMode = GX2_TILE_MODE_LINEAR_ALIGNED;
   wiiu->menu.texture.viewNumSlices    = 1;
   wiiu->menu.texture.compMap          = GX2_COMP_SEL(_A, _R, _G, _B);
   GX2CalcSurfaceSizeAndAlignment(&wiiu->menu.texture.surface);
   GX2InitTextureRegs(&wiiu->menu.texture);

   wiiu->menu.texture.surface.image = MEM2_alloc(wiiu->menu.texture.surface.imageSize,
                                      wiiu->menu.texture.surface.alignment);

   memset(wiiu->menu.texture.surface.image, 0x0, wiiu->menu.texture.surface.imageSize);
   GX2Invalidate(GX2_INVALIDATE_MODE_CPU_TEXTURE, wiiu->menu.texture.surface.image,
                 wiiu->menu.texture.surface.imageSize);

   /* init samplers */
   GX2InitSampler(&wiiu->sampler_nearest, GX2_TEX_CLAMP_MODE_CLAMP, GX2_TEX_XY_FILTER_MODE_POINT);
   GX2InitSampler(&wiiu->sampler_linear, GX2_TEX_CLAMP_MODE_CLAMP, GX2_TEX_XY_FILTER_MODE_LINEAR);

   /* set Texture and Sampler */
   GX2SetPixelTexture(&wiiu->texture, wiiu->shader->sampler.location);
   GX2SetPixelSampler(&wiiu->sampler_linear, wiiu->shader->sampler.location);

   /* clear leftover image */
   GX2ClearColor(&wiiu->color_buffer, 0.0f, 0.0f, 0.0f, 1.0f);
   GX2CopyColorBufferToScanBuffer(&wiiu->color_buffer, GX2_SCAN_TARGET_DRC);
   GX2CopyColorBufferToScanBuffer(&wiiu->color_buffer, GX2_SCAN_TARGET_TV);

   GX2SwapScanBuffers();
   GX2Flush();
   GX2WaitForVsync();

   GX2SetTVEnable(GX2_ENABLE);
   GX2SetDRCEnable(GX2_ENABLE);

   wiiu->keep_aspect   = true;
   wiiu->should_resize = true;
   wiiu->smooth        = video->smooth;
   wiiu->vsync         = video->vsync;
   GX2SetSwapInterval(!!video->vsync);

   wiiu->vp.x           = 0;
   wiiu->vp.y           = 0;
   wiiu->vp.width       = 854;
   wiiu->vp.height      = 480;
   wiiu->vp.full_width  = 854;
   wiiu->vp.full_height = 480;
   video_driver_set_size(&wiiu->vp.width, &wiiu->vp.height);

   float refresh_rate = 60.0f / 1.001f;
   driver_ctl(RARCH_DRIVER_CTL_SET_REFRESH_RATE, &refresh_rate);

   return wiiu;
}
Exemple #24
0
bool NSMBPatch()
{
	WIP_Code * CodeList = NULL;

	if (memcmp("SMNE01", (char *) 0x80000000, 6) == 0)
	{
		CodeList = MEM2_alloc(3 * sizeof(WIP_Code));
		if(!CodeList)
			return false;

		CodeList[0].offset = 0x001AB610;
		CodeList[0].srcaddress = 0x9421FFD0;
		CodeList[0].dstaddress = 0x4E800020;
		CodeList[1].offset = 0x001CED53;
		CodeList[1].srcaddress = 0xDA000000;
		CodeList[1].dstaddress = 0x71000000;
		CodeList[2].offset = 0x001CED6B;
		CodeList[2].srcaddress = 0xDA000000;
		CodeList[2].dstaddress = 0x71000000;

	}
	else if (memcmp("SMNP01", (char *) 0x80000000, 6) == 0)
	{
		CodeList = MEM2_alloc(3 * sizeof(WIP_Code));
		if(!CodeList)
			return false;

		CodeList[0].offset = 0x001AB750;
		CodeList[0].srcaddress = 0x9421FFD0;
		CodeList[0].dstaddress = 0x4E800020;
		CodeList[1].offset = 0x001CEE90;
		CodeList[1].srcaddress = 0x38A000DA;
		CodeList[1].dstaddress = 0x38A00071;
		CodeList[2].offset = 0x001CEEA8;
		CodeList[2].srcaddress = 0x388000DA;
		CodeList[2].dstaddress = 0x38800071;
	}
	else if (memcmp("SMNJ01", (char *) 0x80000000, 6) == 0)
	{
		CodeList = MEM2_alloc(3 * sizeof(WIP_Code));
		if(!CodeList)
			return false;

		CodeList[0].offset = 0x001AB420;
		CodeList[0].srcaddress = 0x9421FFD0;
		CodeList[0].dstaddress = 0x4E800020;
		CodeList[1].offset = 0x001CEB63;
		CodeList[1].srcaddress = 0xDA000000;
		CodeList[1].dstaddress = 0x71000000;
		CodeList[2].offset = 0x001CEB7B;
		CodeList[2].srcaddress = 0xDA000000;
		CodeList[2].dstaddress = 0x71000000;
	}

	if (CodeList && set_wip_list(CodeList, 3) == false)
	{
		MEM2_free(CodeList);
		CodeList = NULL;
		return false;
	}


	return CodeList != NULL;
}
bool CMenu::_LangSettings(void)
{
	_refreshLangSettings();
	bool lang_changed = false;

	while(!m_exit)
	{
		_mainLoopCommon();
		if(BTN_HOME_PRESSED || BTN_B_PRESSED)
			break;
		else if(BTN_A_PRESSED)
		{
			if(m_btnMgr.selected(m_LangSettingsBtnBack))
				break;
			else if(m_btnMgr.selected(m_LangSettingsBtnCurLanguageP) || m_btnMgr.selected(m_LangSettingsBtnCurLanguageM))
			{
				s8 direction = m_btnMgr.selected(m_LangSettingsBtnCurLanguageP) ? 1 : -1;
				available_pos = loopNum(available_pos + direction, languages_available.size());
				m_curLanguage = languages_available[available_pos];
				if(!m_loc.load(fmt("%s/%s.ini", m_languagesDir.c_str(), m_curLanguage.c_str())))
				{
					m_curLanguage = "Default";
					m_cfg.setString("GENERAL", "language", m_curLanguage.c_str());
					m_loc.unload();
				}
				else
					m_cfg.setString("GENERAL", "language", m_curLanguage.c_str());
				lang_changed = true;
				_updateText();
				_showLangSettings();
			}
			else if(m_btnMgr.selected(m_LangSettingsBtnGetLanguages))
			{
				/* reset our variables doh */
				_hideLangSettings();
				language_cnt = 0;
				mem_pos = 0;
				u8 *file = NULL;
				u32 filesize = 0;
				_downloadUrl(fmt("%s/Languages/", SVN_URL), &file, &filesize);
				if(m_buffer != NULL)
				{
					const char *search_char = "<li><a";
					/* getting count */
					char *start = (strstr((char*)file, search_char)); /* skipping the .. */
					start = strstr(start, "\n") + 1; /* skipping the line */
					char *tmp = start;

					while((tmp = strstr(tmp, search_char)) != NULL)
					{
						language_cnt++;
						tmp = strstr(tmp, "\n") + 1; /* next line */
					}
					gprintf("Found %u languages\n", language_cnt);
					/* creating list */
					tmp = start;
					lang_list_mem = (language_list*)MEM2_alloc(language_cnt*sizeof(language_list));
					memset(lang_list_mem, 0, language_cnt*sizeof(language_list));
					for(u32 i = 0; i < language_cnt; ++i)
					{
						tmp = strstr(tmp, search_char);
						char *lang_chr = strchr(tmp, 0x22) + 1; /* the " is the beginning for the name */
						memcpy(lang_list_mem[i].lang, lang_chr, std::min(31u, (u32)(strchr(lang_chr, '.') - lang_chr)));
						//gprintf("%s added\n", lang_list_mem[i].lang);
						tmp = strstr(tmp, "\n") + 1; /* next line */
					}
					//gprintf("Finished creating the list\n");
					free(m_buffer);
					m_buffer = NULL;
				}
				_showLangSettings();
			}
			else if(m_btnMgr.selected(m_LangSettingsBtnCurDlLangP) || m_btnMgr.selected(m_LangSettingsBtnCurDlLangM))
			{
				s8 direction = m_btnMgr.selected(m_LangSettingsBtnCurDlLangP) ? 1 : -1;
				mem_pos = loopNum(mem_pos + direction, language_cnt);
				_showLangSettings();
			}
			else if(m_btnMgr.selected(m_LangSettingsBtnDownload))
			{
				_hideLangSettings();
				m_loc.unload();
				/* Get main ini */
				u8 *file = NULL;
				u32 filesize = 0;
				_downloadUrl(fmt("%s/Languages/%s.ini", SVN_URL, lang_list_mem[mem_pos].lang), &file, &filesize);
				if(m_buffer != NULL)
				{
					if(filesize > 0)
					{
						const char *language_ini = fmt("%s/%s.ini", m_languagesDir.c_str(), lang_list_mem[mem_pos].lang);
						fsop_deleteFile(language_ini);
						fsop_WriteFile(language_ini, file, filesize);
						gprintf("Wrote %s with the size %u\n", language_ini, filesize);
					}
					free(m_buffer);
					m_buffer = NULL;
				}
				/* Get help file */
				file = NULL;
				filesize = 0;
				_downloadUrl(fmt("%s/help/%s.txt", SVN_URL, lang_list_mem[mem_pos].lang), &file, &filesize);
				if(m_buffer != NULL)
				{
					if(filesize > 0)
					{
						const char *language_help = fmt("%s/%s.txt", m_helpDir.c_str(), lang_list_mem[mem_pos].lang);
						fsop_deleteFile(language_help);
						fsop_WriteFile(language_help, file, filesize);
						gprintf("Wrote %s with the size %u\n", language_help, filesize);
					}
					free(m_buffer);
					m_buffer = NULL;
				}
				/* reload */
				m_loc.load(fmt("%s/%s.ini", m_languagesDir.c_str(), m_curLanguage.c_str()));
				_updateText();
				_refreshLangSettings();
			}
		}
	}
	_hideLangSettings();
	if(lang_changed)
		_cfNeedsUpdate();

	if(lang_list_mem != NULL)
		free(lang_list_mem);
	lang_list_mem = NULL;
	return lang_changed;
}