RGSSAD: Add RGSS3 archive reader
Everything except the entry table parsing is the same as RGSS1.
This commit is contained in:
		
							parent
							
								
									6726493ee7
								
							
						
					
					
						commit
						2f831aea60
					
				
					 3 changed files with 168 additions and 42 deletions
				
			
		| 
						 | 
					@ -340,6 +340,7 @@ FileSystem::FileSystem(const char *argv0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	PHYSFS_registerArchiver(&RGSS1_Archiver);
 | 
						PHYSFS_registerArchiver(&RGSS1_Archiver);
 | 
				
			||||||
	PHYSFS_registerArchiver(&RGSS2_Archiver);
 | 
						PHYSFS_registerArchiver(&RGSS2_Archiver);
 | 
				
			||||||
 | 
						PHYSFS_registerArchiver(&RGSS3_Archiver);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (allowSymlinks)
 | 
						if (allowSymlinks)
 | 
				
			||||||
		PHYSFS_permitSymbolicLinks(1);
 | 
							PHYSFS_permitSymbolicLinks(1);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										208
									
								
								src/rgssad.cpp
									
										
									
									
									
								
							
							
						
						
									
										208
									
								
								src/rgssad.cpp
									
										
									
									
									
								
							| 
						 | 
					@ -79,14 +79,14 @@ readUint32(PHYSFS_Io *io, uint32_t &result)
 | 
				
			||||||
	return (count == 4);
 | 
						return (count == 4);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define RGSS_HEADER_1 0x53534752
 | 
					#define RGSS_HEADER "RGSSAD"
 | 
				
			||||||
#define RGSS_HEADER_2 0x01004441
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define RGSS_MAGIC 0xDEADCAFE
 | 
					#define RGSS_MAGIC 0xDEADCAFE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define PHYSFS_ALLOC(type) \
 | 
					#define PHYSFS_ALLOC(type) \
 | 
				
			||||||
	static_cast<type*>(PHYSFS_getAllocator()->Malloc(sizeof(type)))
 | 
						static_cast<type*>(PHYSFS_getAllocator()->Malloc(sizeof(type)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define IO_READ(io, dest, size) (io->read(io, dest, size) == size)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline uint32_t
 | 
					static inline uint32_t
 | 
				
			||||||
advanceMagic(uint32_t &magic)
 | 
					advanceMagic(uint32_t &magic)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -278,22 +278,65 @@ static const PHYSFS_Io RGSS_IoTemplate =
 | 
				
			||||||
    RGSS_ioDestroy
 | 
					    RGSS_ioDestroy
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					processDirectories(RGSS_archiveData *data, BoostSet<std::string> &topLevel,
 | 
				
			||||||
 | 
					                   char *nameBuf, uint32_t nameLen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* Check for top level entries */
 | 
				
			||||||
 | 
						for (uint32_t i = 0; i < nameLen; ++i)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							bool slash = nameBuf[i] == '/';
 | 
				
			||||||
 | 
							if (!slash && i+1 < nameLen)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (slash)
 | 
				
			||||||
 | 
								nameBuf[i] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							topLevel.insert(nameBuf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (slash)
 | 
				
			||||||
 | 
								nameBuf[i] = '/';
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Check for more entries */
 | 
				
			||||||
 | 
						for (uint32_t i = nameLen; i > 0; i--)
 | 
				
			||||||
 | 
							if (nameBuf[i] == '/')
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								nameBuf[i] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								const char *dir = nameBuf;
 | 
				
			||||||
 | 
								const char *entry = &nameBuf[i+1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								BoostSet<std::string> &entryList = data->dirHash[dir];
 | 
				
			||||||
 | 
								entryList.insert(entry);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool
 | 
				
			||||||
 | 
					verifyHeader(PHYSFS_Io *io, char version)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char header[8];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!IO_READ(io, header, sizeof(header)))
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (strcmp(header, RGSS_HEADER))
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (header[7] != version)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void*
 | 
					static void*
 | 
				
			||||||
RGSS_openArchive(PHYSFS_Io *io, const char *, int forWrite)
 | 
					RGSS_openArchive(PHYSFS_Io *io, const char *, int forWrite)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (forWrite)
 | 
						if (forWrite)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Check header */
 | 
						/* Version 1 */
 | 
				
			||||||
	uint32_t header1, header2;
 | 
						if (!verifyHeader(io, 1))
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!readUint32(io, header1))
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!readUint32(io, header2))
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (header1 != RGSS_HEADER_1 || header2 != RGSS_HEADER_2)
 | 
					 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	RGSS_archiveData *data = new RGSS_archiveData;
 | 
						RGSS_archiveData *data = new RGSS_archiveData;
 | 
				
			||||||
| 
						 | 
					@ -337,35 +380,7 @@ RGSS_openArchive(PHYSFS_Io *io, const char *, int forWrite)
 | 
				
			||||||
		entry.startMagic = magic;
 | 
							entry.startMagic = magic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		data->entryHash.insert(nameBuf, entry);
 | 
							data->entryHash.insert(nameBuf, entry);
 | 
				
			||||||
 | 
							processDirectories(data, topLevel, nameBuf, nameLen);
 | 
				
			||||||
		/* Check for top level entries */
 | 
					 | 
				
			||||||
		for (i = 0; i < nameLen; ++i)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			bool slash = nameBuf[i] == '/';
 | 
					 | 
				
			||||||
			if (!slash && i+1 < nameLen)
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (slash)
 | 
					 | 
				
			||||||
				nameBuf[i] = '\0';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			topLevel.insert(nameBuf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (slash)
 | 
					 | 
				
			||||||
				nameBuf[i] = '/';
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Check for more entries */
 | 
					 | 
				
			||||||
		for (i = nameLen; i > 0; i--)
 | 
					 | 
				
			||||||
			if (nameBuf[i] == '/')
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				nameBuf[i] = '\0';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				const char *dir = nameBuf;
 | 
					 | 
				
			||||||
				const char *entry = &nameBuf[i+1];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				BoostSet<std::string> &entryList = data->dirHash[dir];
 | 
					 | 
				
			||||||
				entryList.insert(entry);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		io->seek(io, entry.offset + entry.size);
 | 
							io->seek(io, entry.offset + entry.size);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -507,3 +522,112 @@ const PHYSFS_Archiver RGSS2_Archiver =
 | 
				
			||||||
	RGSS_stat,
 | 
						RGSS_stat,
 | 
				
			||||||
	RGSS_closeArchive
 | 
						RGSS_closeArchive
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool
 | 
				
			||||||
 | 
					readUint32AndXor(PHYSFS_Io *io, uint32_t &result, uint32_t key)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!readUint32(io, result))
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						result ^= key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void*
 | 
				
			||||||
 | 
					RGSS3_openArchive(PHYSFS_Io *io, const char *, int forWrite)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (forWrite)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Version 3 */
 | 
				
			||||||
 | 
						if (!verifyHeader(io, 3))
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint32_t baseMagic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!readUint32(io, baseMagic))
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						baseMagic = (baseMagic * 9) + 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						RGSS_archiveData *data = new RGSS_archiveData;
 | 
				
			||||||
 | 
						data->archiveIo = io;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Top level entry list */
 | 
				
			||||||
 | 
						BoostSet<std::string> &topLevel = data->dirHash[""];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (true)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							uint32_t offset, size, magic, nameLen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!readUint32AndXor(io, offset, baseMagic))
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Zero offset means entry list has ended */
 | 
				
			||||||
 | 
							if (offset == 0)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!readUint32AndXor(io, size, baseMagic))
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!readUint32AndXor(io, magic, baseMagic))
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!readUint32AndXor(io, nameLen, baseMagic))
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							char nameBuf[512];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!IO_READ(io, nameBuf, nameLen))
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							uint32_t i;
 | 
				
			||||||
 | 
							for (i = 0; i < nameLen; ++i)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								nameBuf[i] ^= ((baseMagic >> 8*(i%4)) & 0xFF);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (nameBuf[i] == '\\')
 | 
				
			||||||
 | 
									nameBuf[i] = '/';
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							nameBuf[i] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							RGSS_entryData entry;
 | 
				
			||||||
 | 
							entry.offset = offset;
 | 
				
			||||||
 | 
							entry.size = size;
 | 
				
			||||||
 | 
							entry.startMagic = magic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							data->entryHash.insert(nameBuf, entry);
 | 
				
			||||||
 | 
							processDirectories(data, topLevel, nameBuf, nameLen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						error:
 | 
				
			||||||
 | 
							delete data;
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return data;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const PHYSFS_Archiver RGSS3_Archiver =
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						0,
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							"RGSS3A",
 | 
				
			||||||
 | 
							"RGSS3 encrypted archive format",
 | 
				
			||||||
 | 
							"", /* Author */
 | 
				
			||||||
 | 
							"", /* Website */
 | 
				
			||||||
 | 
							0 /* symlinks not supported */
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						RGSS3_openArchive,
 | 
				
			||||||
 | 
						RGSS_enumerateFiles,
 | 
				
			||||||
 | 
						RGSS_openRead,
 | 
				
			||||||
 | 
						RGSS_noop1, /* openWrite */
 | 
				
			||||||
 | 
						RGSS_noop1, /* openAppend */
 | 
				
			||||||
 | 
						RGSS_noop2, /* remove */
 | 
				
			||||||
 | 
						RGSS_noop2, /* mkdir */
 | 
				
			||||||
 | 
						RGSS_stat,
 | 
				
			||||||
 | 
						RGSS_closeArchive
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,5 +26,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern const PHYSFS_Archiver RGSS1_Archiver;
 | 
					extern const PHYSFS_Archiver RGSS1_Archiver;
 | 
				
			||||||
extern const PHYSFS_Archiver RGSS2_Archiver;
 | 
					extern const PHYSFS_Archiver RGSS2_Archiver;
 | 
				
			||||||
 | 
					extern const PHYSFS_Archiver RGSS3_Archiver;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif // RGSSAD_H
 | 
					#endif // RGSSAD_H
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue