[Scummvm-cvs-logs] SF.net SVN: scummvm:[41671] tools/trunk/compress_gob.cpp

strangerke at users.sourceforge.net strangerke at users.sourceforge.net
Fri Jun 19 13:16:58 CEST 2009


Revision: 41671
          http://scummvm.svn.sourceforge.net/scummvm/?rev=41671&view=rev
Author:   strangerke
Date:     2009-06-19 11:16:57 +0000 (Fri, 19 Jun 2009)

Log Message:
-----------
- Add archive filename to the 'gob' config file
- some cleanup
- Doxygen comments

Modified Paths:
--------------
    tools/trunk/compress_gob.cpp

Modified: tools/trunk/compress_gob.cpp
===================================================================
--- tools/trunk/compress_gob.cpp	2009-06-19 11:12:57 UTC (rev 41670)
+++ tools/trunk/compress_gob.cpp	2009-06-19 11:16:57 UTC (rev 41671)
@@ -35,10 +35,10 @@
 	~Chunk() { delete next; }
 };
 
-Chunk *readChunkConf(FILE *gobconf, uint16 &chunkCount);
+Chunk *readChunkConf(FILE *gobconf, char *stkName, uint16 &chunkCount);
 void writeEmptyHeader(FILE *stk, uint16 chunkCount);
-void writeBody(FILE *stk, uint16 chunkcount, Chunk *chunks);
-uint32 writeBodyFile(FILE *stk, FILE *src);
+void writeBody(FILE *stk, Chunk *chunks);
+uint32 writeBodyStoreFile(FILE *stk, FILE *src);
 uint32 writeBodyPackFile(FILE *stk, FILE *src);
 void rewriteHeader(FILE *stk, uint16 chunkCount, Chunk *chunks);
 bool filcmp(FILE *src1, Chunk *compChunk);
@@ -47,12 +47,11 @@
 byte *packData(byte *src, uint32 &size);
 
 int main(int argc, char **argv) {
-	char *outFilename;
-	char *tmpStr;
 	Chunk *chunks;
 	FILE *stk;
 	FILE *gobConf;
 	uint16 chunkCount;
+	char stkName[256];
 
 	if ((argc < 2) || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
 		printf("Usage: %s <Conf file>\n\n", argv[0]);
@@ -63,25 +62,13 @@
 	if (!(gobConf = fopen(argv[1], "r")))
 		error("Couldn't open conf file \"%s\"", argv[1]);
 
-	outFilename = new char[strlen(argv[1]) + 5];
-	getFilename(argv[1], outFilename);
-
-	tmpStr = strstr(outFilename, ".");
-
-// TODO : other extensions ? (ITK, LTK)
-	if (tmpStr != 0)
-		strcpy(tmpStr, ".stk");
-	else
-		strcat(outFilename, ".stk");
-
-	if (!(stk = fopen(outFilename, "wb")))
-		error("Couldn't create file \"%s\"", outFilename);
-
-	chunks = readChunkConf(gobConf, chunkCount);
+	chunks = readChunkConf(gobConf, stkName, chunkCount);
 	fclose(gobConf);
+	if (!(stk = fopen(stkName, "wb")))
+		error("Couldn't create file \"%s\"", stkName);
 
 	writeEmptyHeader (stk, chunkCount);
-	writeBody(stk, chunkCount, chunks);
+	writeBody(stk, chunks);
 	rewriteHeader(stk, chunkCount, chunks);
 
 	fflush(stk);
@@ -100,7 +87,19 @@
 	error(msg);
 }
 
-Chunk *readChunkConf(FILE *gobConf, uint16 &chunkCount) {
+/*! \brief Config file parser
+ * \param gobConf Config file to parse
+ * \param stk STK/ITK archive file to be created
+ * \param chunkCount Number of chunks to be written in the archive file
+ * \return A list of chunks
+ *
+ * This function reads the '.gob' config file (generated by extract_gob_stk).
+ * It creates the output archive file and a list of chunks containing the file
+ * and compression information.
+ * In order to have a slightly better compression ration in some cases (Playtoons), it
+ * also detects duplicate files.
+ */
+Chunk *readChunkConf(FILE *gobConf, char *stkName, uint16 &chunkCount) {
 	Chunk *chunks = new Chunk;
 	Chunk *curChunk = chunks;
 	Chunk *parseChunk;
@@ -109,7 +108,10 @@
 
 	chunkCount = 1;
 
-// first read: signature
+// First read: Output filename
+	fscanf(gobConf, "%s", stkName);
+
+// Second read: signature
 	fscanf(gobConf, "%s", buffer);
 	if (!strcmp(buffer, confSTK21))
 		error("STK21 not yet handled");
@@ -161,23 +163,36 @@
 	return chunks;
 }
 
+/*! \brief Write an empty header to the STK archive
+ * \param stk STK/ITK archive file
+ * \param chunkCount Number of chunks to be written in the archive file
+ *
+ * This function writes an empty header in the STK archive. This is required as
+ * the header length is variable and depends on the number of chunks to be written
+ * in the archive file. 
+ *
+ * This header will be overwritten just before the end of the program execution
+ */
 void writeEmptyHeader(FILE *stk, uint16 chunkCount) {
-	int count;
-
-// Write empty header dummy header, which will be overwritten
-// at the end of the program execution.
-	for (count = 0; count < 2 + (chunkCount * 22); count++)
+	for (uint32 count = 0; count < 2 + (uint32) (chunkCount * 22); count++)
 		fputc(0, stk);
 
 	return;
 }
 
-void writeBody(FILE *stk, uint16 chunkCount, Chunk *chunks) {
+/*! \brief Write the body of the STK archive
+ * \param stk STK/ITK archive file
+ * \param chunks Chunk list
+ *
+ * This function writes the body of the STK archive by storing or compressing
+ * (or skipping duplicate files) the files. It also updates the chunk information
+ * with the size of the chunk in the archive, the compression method (if modified),
+ * ...
+ */
+void writeBody(FILE *stk, Chunk *chunks) {
 	Chunk *curChunk = chunks;
 	FILE *src;
 	uint32 tmpSize;
-	int count;
-	char buffer[4096];
 
 	while(curChunk) {
 		if (!(src = fopen(curChunk->name, "rb")))
@@ -205,13 +220,8 @@
 		if (curChunk->packed == 0) {
 			tmpSize = 0;
 			printf("Storing %12s\t", curChunk->name);
-			do {
-				count = fread(buffer, 1, 4096, src);
-				fwrite(buffer, 1, count, stk);
-				tmpSize += count;
-			} while (count == 4096);
-			curChunk->size = tmpSize;
-			printf("%d bytes\n", tmpSize);
+			curChunk->size = writeBodyStoreFile(stk, src);
+			printf("%d bytes\n", curChunk->size);
 		}
 
 		fclose(src);
@@ -220,21 +230,25 @@
 	return;
 }
 
-uint32 writeBodyFile(FILE *stk, FILE *src) {
-	int count;
-	char buffer[4096];
-	uint32 tmpSize;
-
-	tmpSize = 0;
-	do {
-		count = fread(buffer, 1, 4096, src);
-		fwrite(buffer, 1, count, stk);
-		tmpSize += count;
-	} while (count == 4096);
-	return tmpSize;
-}
-
-
+/*! \brief Rewrites the header of the archive file
+ * \param stk STK/ITK archive file
+ * \param chunkCount Number of chunks
+ * \param chunks List of chunks
+ *
+ * This function rewrites the header of the archive, replacing dummy values 
+ * by the one computed during execution.
+ * The structure of the header is the following :
+ * + 2 bytes : numbers of files archived in the .stk/.itk
+ * Then, for each files :
+ * + 13 bytes : the filename, terminated by '\0'. In original, there's
+ *   garbage after if the filename has not the maximum length
+ * + 4  bytes : size of the chunk
+ * + 4  bytes : start position of the chunk in the file
+ * + 1  byte  : If 0 : not compressed, if 1 : compressed
+ * 
+ * The duplicate files are defined using the same information
+ * as the one of the replacement file.
+*/
 void rewriteHeader(FILE *stk, uint16 chunkCount, Chunk *chunks) {
 	uint16 i;
 	char buffer[1024];
@@ -242,14 +256,6 @@
 
 	rewind(stk);
 
-//	The structure of the header is the following :
-//+ 2 bytes : numbers of files archived in the .stk/.itk
-//	Then, for each files :
-//+ 13 bytes : the filename, terminated by '\0'. In original, there's
-//  garbage after if the filename has not the maximum length
-//+ 4  bytes : size of the chunk
-//+ 4  bytes : start position of the chunk in the file
-//+ 1  byte  : If 0 : not compressed, if 1 : compressed
 	buffer[0] = chunkCount & 0xFF;
 	buffer[1] = chunkCount >> 8;
 	fwrite(buffer, 1, 2, stk);
@@ -290,6 +296,33 @@
 	return;
 }
 
+/*! \brief Stores a file in the archive file
+ * \param stk STK/ITK archive file
+ * \param src File to be stored
+ * \return Size of the file stored
+ *
+ * This function stores a file in the STK archive
+ */
+uint32 writeBodyStoreFile(FILE *stk, FILE *src) {
+	int count;
+	char buffer[4096];
+	uint32 tmpSize = 0;
+
+	do {
+		count = fread(buffer, 1, 4096, src);
+		fwrite(buffer, 1, count, stk);
+		tmpSize += count;
+	} while (count == 4096);
+	return tmpSize;
+}
+
+/*! \brief Compress a file in the archive file
+ * \param stk STK/ITK archive file
+ * \param src File to be stored
+ * \return Size of the resulting compressed chunk
+ *
+ * This function compress a file in the STK archive
+ */
 uint32 writeBodyPackFile(FILE *stk, FILE *src) {
 	byte dico[4114];
 	byte writeBuffer[17];
@@ -315,24 +348,25 @@
 	writeBuffer[3] = size >> 24;
 	fwrite(writeBuffer, 1, 4, stk);
 
-// TODO : check size, if too small, handle correctly
-
+// Size is already checked : small files (less than 8 characters) 
+// are not compressed, so copying the first three bytes is safe.
 	dicoIndex = 4078;
 	dico[dicoIndex] = unpacked[0];
 	dico[dicoIndex+1] = unpacked[1];
 	dico[dicoIndex+2] = unpacked[2];
 	dicoIndex += 3;
 
-//writeBuffer[0] is reserved for the command byte
+// writeBuffer[0] is reserved for the command byte
 	writeBuffer[1] = unpacked[0];
 	writeBuffer[2] = unpacked[1];
 	writeBuffer[3] = unpacked[2];
+// Force the 3 first operation bits to 'copy character'
+	cmd = (1 << 3) - 1;
 
 	counter = size - 3;
 	unpackedIndex = 3;
 	cpt = 3;
 	buffIndex = 4;
-	cmd = (1 << 3) - 1;
 
 	size=4;
 	resultcheckpos = 0;
@@ -342,6 +376,7 @@
 		if (!checkDico(unpacked, unpackedIndex, counter, dico, dicoIndex, resultcheckpos, resultchecklength)) {
 			dico[dicoIndex] = unpacked[unpackedIndex];
 			writeBuffer[buffIndex] = unpacked[unpackedIndex];
+// set the operation bit : copy character
 			cmd |= (1 << cpt);
 			unpackedIndex++;
 			dicoIndex = (dicoIndex + 1) % 4096;
@@ -356,6 +391,9 @@
 			writeBuffer[buffIndex] = resultcheckpos & 0xFF;
 			writeBuffer[buffIndex + 1] = ((resultcheckpos & 0x0F00) >> 4) + (resultchecklength - 3);
 
+// Do not set the operation bit : copy string from dictionary
+//			cmd |= (0 << cpt);
+
 			unpackedIndex += resultchecklength;
 			dicoIndex = (dicoIndex + resultchecklength) % 4096;
 			resultcheckpos = (resultcheckpos + resultchecklength) % 4096;
@@ -364,6 +402,8 @@
 			counter -= resultchecklength;
 		}
 
+// The command byte is complete when the file is entirely compressed, or 
+// when the 8 operation bits are set.
 		if ((cpt == 7) | (counter == 0)) {
 			writeBuffer[0] = cmd;
 			fwrite(writeBuffer, 1, buffIndex, stk);
@@ -379,6 +419,14 @@
 	return size;
 }
 
+/*! \brief Compare a file to a file defined in a chunk
+ * \param src1 File to be compared
+ * \param compChunk Chunk containing information on second file to be compared
+ * \return whether they are identical or not.
+ *
+ * This function compares a file to another defined in a chunk. The file sizes 
+ * are already tested outside the function.
+ */
 bool filcmp(FILE *src1, Chunk *compChunk) {
 	uint16 readCount;
 	bool checkFl = true;
@@ -402,6 +450,21 @@
 	return checkFl;
 }
 
+/*! \brief Compare a file to a file defined in a chunk
+ * \param unpacked Buffer being compressed
+ * \param unpackedIndex Current 'read' position in this buffer
+ * \param counter Number of bytes still to be compressed in the file
+ * \param dico Dictionary
+ * \param currIndex Current 'write' position in the dictionary (used to avoid dictionary collision)
+ * \param pos Position of the better match found, if any
+ * \param length Length of the better match found, if any
+ * \return whether a match has been found or not or not.
+ *
+ * This function search in the dictionary for matches with the characters still to be compressed. 
+ * 'A match' is when at least three characters of the buffer (comparing from the current 'read' position)
+ * are found in the dictionary. The match lengths are limited to 18 characters, as the 
+ * length (minus 3) is stored on 4 bits.
+ */
 bool checkDico(byte *unpacked, uint32 unpackedIndex, int32 counter, byte *dico, uint16 currIndex, uint16 &pos, uint8 &length) {
 	uint16 tmpPos, bestPos;
 	uint8 tmpLength, bestLength, i;


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list