Zdrojový kód prvního projektu do předmětu IZP. Jde o jednoduché šifrování textu podle zadaného klíče. Více v příslušném článku nebo přímo v komentářích v kódu.
/* * Soubor: proj1.c * Datum: 21.10.2008 * Autor: David Sabata (xsabat01) * Projekt: Sifrovani, projekt c. 1 pro predmet IZP * Popis: Program provadi de/sifrovani vstupniho textu podle zadaneho klice */ #include #include #include // "Cislice" nasi soustavy; dalo by se prepocitavat z ASCII, ale v ramci // rychlosti a rozsiritelnosti radeji pouzivam pole const char TRANS[] = {'0','1','2','3','4','5','6','7','8','9', 'A','B','C','D','E','F','G','H','I','J','K','L','M','N', 'O','P','Q','R','S','T','U','V','W','X','Y','Z'}; // Zaklad soustavy const int BASE = 36; // Ukonceni radku const int CR = 13; const int LF = 10; /** * Chybove hlasky */ const char *EMSG[] = { "Vse v poradku", "Nespravne parametry. Prosim, pouzijte napovedu.", "Neplatny znak klice", "Neplatny vstupni znak" }; /** * Vysledky rozboru argumentu */ enum actions { AHELP, // budeme tisknout napovedu AENCODE, // budeme sifrovat ADECODE // bdueme desifrovat }; /** Funkce **/ int loadParams(int argc, char *argv[]); int charOk(int ch); int encdec(int action, int ch1, int ch2); int getKeyChar(char *argv, int keyIterator); void ltr2num(int *ch); void num2ltr(int *ch); void printError(int error); void printHelp(); /******************************************************************************/ /** * Main */ int main(int argc, char *argv[]) { // Akce urcena na zaklade parametru int action = loadParams(argc, argv); // Znacitko aktualniho znaku ktery z klice bereme (pro posouvani) int keyIterator = 0; // Delka retezce klice int keyLength = 0; // Dva znaky se kteryma se bude pracovat int vstup = 0; int klic = 0; // Bude se pouzivat pro podrzeni zpracovaneho znaku predtim nez se vytiskne char out; switch (action) { // Vytisknuti napovedy case AHELP: printHelp(); break; // De/sifrovani case AENCODE: case ADECODE: // Spocitani delky klice, at se nepocita v cyklu keyLength = strlen(argv[2]); do { // nacist znak z klice klic = getKeyChar(argv[2], keyIterator); // posuneme ukazatel na nasledujici znak a pokud jsme na konci // retezce klice, skocime zase na zacatek keyIterator++; if (keyIterator==keyLength) keyIterator = 0; // nacist znak ze vstupu vstup = getchar(); // spravny znak vypsat, pokud neni spravny, nastavila se chyba if (charOk(vstup) && klic>0) { // Zpracovat znak prislusnou akci a vypsat out = encdec(action, vstup, klic); putchar(out); } // Nacitani dalsich klaves dokud nenarazime na konec vstupu } while (vstup>0 && vstup!=CR && vstup!=LF); } return EXIT_SUCCESS; } /** * Nacte parametry a vyhodnoti akci, pripadne chybu * @param argc int pocet parametru * @param argv char pole parametru * @return int akce ktera se ma provest */ int loadParams(int argc, char *argv[]) { // Napoveda if (argc == 2 && strcmp("-h", argv[1]) == 0) return AHELP; // Sifrovani if (argc == 3 && strcmp("-encode", argv[1]) == 0) return AENCODE; // Desifrovani if (argc == 3 && strcmp("-decode", argv[1]) == 0) return ADECODE; // Cokoliv jineho je chyba, vytiskneme hlasku o nespravnych parametrech, // coz zaroven ukonci program. Hodnota v returnu je pouze formalita. printError(1); return -1; } /** * Vytiskne chybove hlaseni na chybově věstup. Pote tvrde ukonci program, asi by * bylo praktictejsi nechat chybu vybublat az do fce main, ale jelikoz mame * zakazano pouziti globalnich promennych, bylo by slozite to realizovat, proto * se vola ukonceni hned pri vypsani chyby. * @param error int cislo chybove hlasky */ void printError(int error) { fprintf(stderr, "Chyba: %s\n", EMSG[error]); exit(EXIT_FAILURE); } /** * Vytiskne napovedu */ void printHelp() { printf( "Program Sifrovani\n" "Autor: David Sabata (c)2008\n" "Program de/sifruje text ze standardniho vstupu pomoci klice zadaneho \n" "v parametru. Pro klic i vstupni text jsou povolena " "pouze velka pismena anglicke abecedy a cisla.\n" "Parametry:\n" "\t-encode KLIC\tprogram bude sifrovat podle klice KLIC\n" "\t-decode KLIC\tprogram bude desifrovat podle klice KLIC\n" "\t-h\t\tzobrazeni teto napovedy\n\n" ); } /** * Kontrola znaku - bereme pouze velke pismena a cisla, porovnavame podle ascii * @param ch int znak ke kontrole * @return int [0|1] */ int charOk(int ch) { // Osetreni EOL a EOF - je to chybovy znak, ale nevypisujeme hlasku if ( ch==CR || ch==LF || ch<0 ) return 0; // Konrola podle cisla znaku v ASCII if ( (ch>='0' && ch< ='9') || (ch>='A' && ch< ='Z') ) return 1; else // nastavit "chyba na vstupu" printError(3); return 0; } /** * De/sifrovani znaku * @param action int akce (AENCODE|ADECODE) * @param ch1 int prvni znak k zasifrovani * @param ch2 int druhy znak k zasifrovani * @return int de/sifrovany znak */ int encdec(int action, int ch1, int ch2) { // Prevest na desitkove cislo ltr2num(&ch1); ltr2num(&ch2); // Vysledny znak int chr; if (action == AENCODE) { // Sifrovani je proste secteni chr = ch1 + ch2; } else { // Pricist zaklad, ktery vyvazi chybu zanedbavani // vyssich radu pri sifrovani; vysledek to nepokazi, protoze vystup // jde pres %BASE (%36); ch1 += BASE; // Desifrovani je odcitani klice chr = ch1 - ch2; // Osetrit zaporny rozdil - nahrada funkce fabs() if (chr < 0) chr *= -1; } // Prevest zpet na kod num2ltr(&chr); return chr; } /** * Vraci jeden znak z klice kterym (de)kodujeme * @param char key klic podle ktereho se sifruje * @param int keyIterator poradi znaku v retezci, se kterym se bude pracovat * @return int znak z klice */ int getKeyChar(char *key, int keyIterator) { // nacist znak char ch = key[keyIterator]; // zkontrolovat ho podle cisla v ASCII, popr. vypsat chybu a ukoncit if ( ch<'0' || (ch>'9' && ch< 'A') || ch>'Z' ) { printError(2); } return ch; } /** * Prevadi znak na desitkove cislo 0-35 * @param int ch znak k upraveni */ void ltr2num(int *ch) { // Cisla jsou cisla, namisto pouziti fce pro prevod, jednoduse odecteme // ASCII hodnotu znaku 0, cimz prevedeme cislo z jeho ASCII hodnoty na // hodnotu kterou potrebujeme if (*ch >= '0' && *ch < = '9') { *ch = *ch - '0'; } // Pismena se prepocitaji obdobne if (*ch >= 'A' && *ch < = 'Z') { // Odecteme ASCII hodnotu znaku A, cimz pro nas budou pismena A,B,C,... // predstavovat hodnoty 0,1,2,... *ch = *ch - 'A'; // Pricteme 10, coz znamena, ze A je na 10. pozici v tabulce, vyplyva to // z toho, ze je pred nim 10 cislic [0-9]; nepouzivam zde zadnou konstantu // protoze jde o jediny vyskyt v programu a tezko budeme nekdy pouzivat // vic cislic nez 10 *ch += 10; } } /** * Prevadi cislo 0-35 na odpovidajici znak * @param int ch cislo k upraveni */ void num2ltr(int *ch) { // Modulo zajisti, ze cislo nebude vetsi nez zaklad soustavy *ch = *ch % BASE; // a z tabulky jednoduse vybereme znak na odpovidajici pozici *ch = TRANS[*ch]; }