Developers can add a new algorithm to KFileCoder, if it is free. To do it, this handbook explains how to do. After, you must send your work to the application author, if you want it to be in the official release. You can't distribute an unofficial version of KFileCoder.
Many numbers are written in 64 bits, for example file sizes, in order to avoid future limitations of the file formats. 64 bits variables must be declared as QWORD, this is defined as unsigned long long int. in resource.h
There is free space, reserved for future use, in the main header, and in each file header, in order to add other informations in the future, without making archives files uncompatibles.
Variables names are written in the following format: PositionTypeName:
Examples:
This has a lot of advantages: When you see a variable, you know the type (int, bool, FILE *), and you know if it's a global, local or member one.
Likewise, if two variables have the same name, if resolves the problem. For example, we have:
bool KClass::m_bState;
void KClass::setState(bool bState)
{
m_bState = bState;
}
instead of:
bool KClass::state;
void KClass::setState(bool state2)
{
state = state2;
}
All the general work is done in an only function of the code. Thus, opening files, checking data contents,... are made in KFileCoderDoc::addFile(KURL urlFile) and extractFiles(const char *, bool) and don't have to be implemented in each algorithm specialized functions.
The most important thing to do is to write two functions:
The first one is:
int addFileAlgoXXXXX(QWidget *wWin, const char *szFilename, const BYTE *cPassword, FILE *fFileToAdd, FILE *fArchive, BYTE *cHashControl, QWORD *qwCompressedFileSize, QWORD *qwEncodedFileSize)
XXXXX is the name of the algorithm used.
This functions takes 8 arguments:
The return value is -1 if there was an error, or 0 if success.
The best way to write this function is to copy existing versions of it, as addFileAlgoPc1, and to update the core encoding instructions.
All the code used by your algorithm, must be implemented in an only cpp file, which name is algo_XXXXX, with a header file too. This file contains the two main encoding and decoding functions, and external functions if need. You can look at algo_pc1.cpp and algo_pc1.h to have an example. Please, don't use global variables ! It can make many bugs, and it make multi-thread applications bug.
This function must encode data of the file. But there is another work to do. In deed, this function first write the size of compressed data, and of encoded data, in 64 bits numbers. qwCompressedFileSize must contain the number of read bytes. This is the compressed size, because if compression is used, the datas the encoding function receives are compressed. And the only way to know the size is to read all bytes. If data are not compressed, this is the same number as orignal size. of file. qwEncodedFileSize is the number of bytes written by the encoding function, to the archive. In many cases, if the algorithm used doesn't change the size of data, then this is equal to the compressed size. If the algorithm don't change the data size, this is very simple: you just have to copy the value from qwCompressedFileSize at the end of the encoding work. While encoding, this function must update the 128 bits hash table cHashControl used to check data contents. To do it, you just have to XOR the hash current byte, with the current encoded byte, with the following code:
// update the hash control table
cHashControl[dwHashPos] ^= cCurChar;
dwHashPos++;
if (dwHashPos >= ENCODING_LEN)
dwHashPos = 0;
Don't forget to initialize dwHashPos to 0 at the beginning of the function. And, you have to encode the hash, after file encoding, with the following code:
// encode the hash control table
end = (ENCODING_LEN+1)*ENCODING_LEN;
for (z=1; z <= end; z++)
{
cCurChar = cHashControl[dwHashPos];
pc1Assemble(pcX1a0, pcKey, &pcInter, &pcI, &pcX1a2, &pcSi);
pcCfc = pcInter >> 8;
pcCfd = pcInter & 255; // pcCfc ^ pcCfd = random byte
for (dwCount = 0; dwCount < ENCODING_LEN; dwCount++)
pcKey[dwCount] ^= cCurChar;
cCurChar ^= (pcCfc ^ pcCfd);
cHashControl[dwHashPos] ^= cCurChar;
dwHashPos++;
if (dwHashPos >= ENCODING_LEN)
dwHashPos = 0;
}
The filename and the filestream (szFilename and fFileToDecode) can be null. In this case, the function must not write any data. The only work of the function is to calculate the hash table, from decoded data. Then data must be decoded but not written. This is very easy to implement:
if (szFilename && fFileToDecode) // if these variables are NULL, it's only a test ==> do not write anything
{ nRes = putc(cCurChar, fFileToDecode);
if (nRes == EOF)
{ strMess.sprintf(i18n("Can't write file %s."), szFilename);
KMessageBox::error (wWin, strMess);
return -1;
}
}
The second one is:
int extractFilesAlgoXXXXX(QWidget *wWin, const char *szFilename, const BYTE *cPassword, FILE *fFileToDecode, FILE *fArchive, BYTE *cHashControl, QWORD qwCompressedFileSize, QWORD qwEncodedFileSize)
XXXXX is the name of the algorithm used.
This functions takes 8 arguments:
The return value is -1 if there was an error, or 0 if success.
The best way to write this function is to copy existing versions of it, as extractFilesAlgoPc1, and to update the core decoding instructions.
The extracting, and required external functions, must be implemented in the same file as the encoding function. This function must decode data. There only other work to do is to update the control hash table. To do it, XOR with the encoded byte, just after read, and encode the hash at the end of the operation, as in the encoding function.
The most important work is to decode data. You have to make the opposite work as the encoding function did.
Other changes have to be done, to add an algorithm to KFileCoder.
First, you must increase the ALGO_SUPPORTED_NB macro, defined in the resource.h file.
Then, update the algorithm information table, at the beginning of kfilecoderdoc.cpp:
KAlgoInfo g_algo[] =
{
{"PC1", "hard 128 bits encryption", addFileAlgoPc1, extractFilesAlgoPc1}
//{"XOR", "eXclusive OR, very low security", addFileAlgoXor, extractFilesAlgoXor},
//{0, 0, 0, 0}
};
The first string, is a short name for the algorithm. The second one is a short description. The third one is a pointer to the encoding function of the algorithm, and the last one a pointer to the decoding function. Don't forget to include the header file of your algorithm in the kfilecoderdoc.cpp file.
There are two main parts in an KFileCoder archive:
It's written at the beginning of the file. Main informations about the archive are written in this header:
The most important size of this header is free: it will allow to add other information in the future.
This header is managed with KFileCoderDoc::writeArchiveHeader() and KFileCoderDoc::readArchiveHeader() This header is written in all archives, even is they are empty. The main header is written at the archive creation, and is never updated. It is read each time the user open the archive.
Each file of the archive is written in the following format:
First, we have a file header. there is the encoded filename, and filepath, original size, compressed size, size of encoded data, permissions, owners (user, group), the file date, filename mixer, and the password mixer. This header contains free space (64 bytes) for future use. When encoding files, all members of the file header are written by KFileCoderDoc::writeFileHeader(). This header contains a 128 bits hash table, calculated with pschf. This allow the program to check the data validity after a file extraction is done. This test is implemented in the general code, and don't have to be made by each extract function. But to be possible, the cControlHash hash must have been updated by encoding and extracting functions, which are algorithm dependent.
The second part is the file encoded datas. The encoded data size can be different than the decoded data size, with some algorithms. These data are written by the addFileAlgoXXXXX() function.
The KFileCoder project is hosted by Sourceforge. This site provide us a CVS server for the project. Then, many developers can work together in the project. You can ask a login to the project maintainer if you want to submit your work.