Commit bbf218e5 by Szeberényi Imre

Zolitól

parents
CCX = g++
CXXFLAGS = -Wall -Wdeprecated -pedantic -DMEMTRACE -g
HEADERS := $(wildcard *.h) $(wildcard *.hpp)
SOURCES := $(wildcard *.cpp)
OBJECTS := $(SOURCES:%.cpp=%.o)
.PHONY: main
all: main
main: $(OBJECTS)
$(CCX) $^ -g -o $@ -ldl
%.o: %.c $(HEADERS)
$(CCX) $(CXXFLAGS) -c $<
.PHONY: clean
clean:
rm -rf $(OBJECTS) main
\ No newline at end of file
# Titkosítás
Sorgalmi feladat __Karsa Zoltán__ tól.
A következő szorgalmifeladatban 2 nagyon egyszerű titkosítást kell megvalósítani. Az egyik a Caesar titkosítás, míg a másik egy saját ötlet. Ezen kívül egy CipherQueue osztályt is el kell készíteni, ami összetett, többszintű titkosítást tesz lehetővé. Meg kell jegyezni hogy ezek nagyon gyenge titkosítási eljárások, inkább csak iskolapéldája az öröklésnek és a heterogén kollekciónak.
## ABC
A feladatban az egyszerűség kedvéért csak az angol ábécé kisbetűit (a -tól z, 26 db) és szóközöket tartalmazó üzeneteket kell kódolni. A kódolás során a szóközök változatlanok maradnak, és az ábécé minden kisbetűjének képe az ábécé egy kisbetűje lesz.
## Osztálydiagram
![osztálydiagram](class.png)
A feladatban az osztálydiagramon szereplő osztályokat kell megvalósítani. Az osztályokhoz tartozó pontos specifikáció itt olvasható:
### Cipher
Absztrakt interfész-ősosztály tisztán virtuális függvényekkel.
* __encode(message)__ a paraméterül kapott `std::string` üzenetből létrehozza a neki megfelelő titkosított szöveget
* __decode(ciphertext)__ a paraméterül kapott `std::string` titkosított szövegből visszaadja az üzenetet.
* __clone()__ létrehoz a példányból egy dinamikus másolatot
_Az __encode/decode__ függvények minden leszármazottnál kivételt dobnak ha az átvett `string`-ben van az értelmezési tartományhoz (angol abc kis betűi + szóköz) NEM tartozó karakter, a kivétel a __Neptun__ kódod!_
Megadtuk a __Cipher__ interfész kódját is:
```c++
class Cipher {
public:
virtual std::string encode(const std::string& message) = 0;
virtual std::string decode(const std::string& chipertext) = 0;
virtual Cipher* clone() const = 0;
virtual ~Cipher() { };
};
```
### CaesarCipher
A CaesarCipher osztály a Caesar-titkosítást valósítja meg. Ez az eljárás a bejövő üzenet minden karakterét egy konstanssal (__shift__) tolja el, ez a konstans a titkosítás kulcsa.
Alább egy példát mutatunk shift=3 beállítással (figyeld a szóközök változatlanságát és az utolsó három karakter kódolását is)
```
Be: abcdefgh ijklmnop qrstuvwxyz
Ki: defghijk lmnopqrs tuvwxyzabc
```
Figyelem, a __shift__ lehet negatív is, vagy akár 26-nál nagyobb is!
A Caesar titkosítást megvalósító osztály természetesen implementálja a fenti interfészt, ezen kívül konstruktora képes a shift paraméter eltárolására:
* __CaesarCipher(shift)__ a konstruktorban az eltolás mértéke állítható be.
### MyCipher
Az osztály __encode/decode__ függvényei a Caesar-kódoláshoz hasonlóan eltoláson alapulnak, de az eltolás mértéke nem állandó, hanem karakterről karakterre változik az alábbi szabály szerint:
A kód kulcsa egyrészt egy sztring (__key__), másrészt egy egész eltolás (__offset__). A bejövő szöveg __i__-edik karakterének képét úgy kapjuk meg, hogy azt eltoljuk __offset + i__-vel, továbbá eltoljuk a __key__ string __i__-edik karakterének `a`-tól számított numerikus értékével is. Amennyiben a bejövő szöveg hosszabb, mint a __key__ sztring, akkor __key__ sztring karaktereit az elsőtől kezdve ismételjük. A __key__ sztring nem tartalmazhat szóközt.
Ennek értelmében, amennyiben a __key__ sztring értéke `abc`, valamint __offset__ értéke -2, akkor a `hello bello` üzenet kódolás utáni képe
|üzenet | `h`(7) | `e`(4) | `l`(11) | `l`(11) | `o`(14) | `' '` | `b` | `e` | `l` | `l` | `o` |
|---------------|-----|-----|------|------|------|---|---|---|---|---|---|
|__key__ | `a`(0) | `b`(1) | `c`(2) | `a`(0) | `b`(1) | `c` | `a` | `b` | `c` | `a` | `b` |
|__offset__ + __i__ | -2 | -1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|kódolt szöveg | `f`(5) | `e`(4) | `n`(13) | `m`(12) | `r`(17) | `' '` | `f` | `k` | `t` | `s` | `x` |
A dekódolásház a Caesar titkosításhoz hasonlóan, az ellenkező irányba történő eltolást kell alkalmazni.
Az osztály konstruktorai:
* __MyCipher(key)__ beállítja a kulcsot és az ofszetet 0-ra.
* __MyChipher(key, offset)__ beállítja a kulcsot és az ofszetet
Figyelem, a __offset__ lehet negatív is!
### CipherQueue
A harmadik kódoló osztály összetett kódolót valósít meg, mely tetszőleges kódolók egymás utáni alkalmazására képes. Megvalósítása __Cipher__-leszármazottakat tartalmazó heterogén kollekcióval történik: Azaz __Cipher__ pointereket kell tárolni, ezt sugallja is az osztály függvényei:
Függvények:
* __add(Cipher*)__ egy dinamikusan foglalt kódoló címét veszi át, és a pointert eltárolja a sor végén, később az osztály feladata ezt felszabadítani.
* __encode(message)__ végighalad a tárolt rejtljelezőkön a hozzáadás sorrendjében: először feldolgozza az üzenetet az első hozzáadott titkosító, majd annak eredményét a 2. rejtjelező továbbtitkosítja... végül visszaadja a többszinten titkosított szöveget.
* __decode(ciphertext)__ dekódolja a titkosított üzenetet, ehhez visszafele kell haladni a sorban.
* __CipherQueue(CipherQueue const &)__ másoló konstruktor. Célszerű elkészíteni a __clone__ függvény implementálásához
Figyelj a virtuális függvényekre és a destruktorra, figyeld meg az osztálydiagramon látható jelöléseket, azok alapján dolgozz, továbbá tegyél minden függvényt konstans tagfüggvénynek, amit csak lehet!
## Megoldás
A Git tárolóból letölthető [https://git.ik.bme.hu/Prog2/szorgalmi_feladatok/cipher](https://git.ik.bme.hu/Prog2/szorgalmi_feladatok/cipher)
fájlok felhasználásával hozz létre a lokális fejlesztőkörnyezetedben egy C++ projektet! Ehhez felhasználható a *Makefile*, amiben megtalálhatók a fordítási opciók. Tervezz, fejlessz, tesztelj, majd töltsd fel a megoldást a Jporta rendszerbe!
## Tiltott szavak
A megoldás során nem kell (nem lehet) semmilyen explicit cast operátor, ezért ezek használatát tiltjuk. A Jporta egyszerű szövegkereséssel ellenőrzi a feltöltött fájlokat, hogy szerepel-e bennük "_cast", de azt nem hogy milyen kontextusban találja meg azt. __Így az "_cast" minta nem szerepelhet változónévben, string-ben, kommentben ... sem!__
## Beadás
Feltöltendő a `ciphers.h` és `ciphers.cpp`, a teszteléshez definiáltuk az `ELKESZULT` makrót, amit a `test.cpp` fájlban kell beállítani, de ezt a fájlt nem kell feltölteni.
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_project_file>
<FileVersion major="1" minor="6" />
<Project>
<Option title="cipher" />
<Option pch_mode="2" />
<Option compiler="gcc" />
<Build>
<Target title="Debug">
<Option output="bin/Debug/cipher" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Debug/" />
<Option type="1" />
<Option compiler="gcc" />
<Compiler>
<Add option="-g" />
<Add option="-DMEMTRACE" />
</Compiler>
</Target>
<Target title="Release">
<Option output="bin/Release/cipher" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Release/" />
<Option type="1" />
<Option compiler="gcc" />
<Compiler>
<Add option="-O2" />
</Compiler>
<Linker>
<Add option="-s" />
</Linker>
</Target>
</Build>
<Compiler>
<Add option="-pedantic" />
<Add option="-Wall" />
<Add option="-std=c++11" />
</Compiler>
<Unit filename="ciphers.cpp" />
<Unit filename="ciphers.h" />
<Unit filename="test.cpp" />
<Unit filename="gtest_lite.h" />
<Unit filename="memtrace.cpp" />
<Unit filename="memtrace.h" />
<Extensions>
<code_completion />
<envvars />
<debugger />
</Extensions>
</Project>
</CodeBlocks_project_file>
/**
* \file ciphers.cpp
*
* Ebben a fájlban kell megvalósítania az CaesarCipher, MyCipher, CipherQueue osztályok metódusait.
*
* Ezt a fájlt be kell adni (fel kell tölteni) a megoldással.
*/
#include "memtrace.h"
#include "ciphers.h"
/**
* \file ciphers.h
*
* Ezt a fájlt be kell adni (fel kell tölteni) a megoldással.
*/
#ifndef CipherS_H
#define CipherS_H
#include <string>
#include <vector>
#include "memtrace.h"
/**
* Az ős osztály interfésze
*/
class Cipher {
public:
/**
* Titkosítja a kapott stringet
* @param message titkosítandó üzenet
* @return a message szöveg titkosított változata
*/
virtual std::string encode(const std::string& message) = 0;
/**
* Dekódolja a kapott stringet
* @param ciphertext titkosított üzenet
* @return a megfejtett nyílt szöveg
*/
virtual std::string decode(const std::string& ciphertext) = 0;
/**
* Létrehoz egy másolatot dinamikusan
* @return a létrehozott objektumra mutató pointer
*/
virtual Cipher* clone() const = 0;
/**
* Alap destruktor
*/
virtual ~Cipher() { };
};
//Osztályok, amiket meg kell csinálni a leírások és az osztálydiagram alapján
class CaesarCipher {
};
class MyCipher {
};
class CipherQueue {
};
#endif
\ No newline at end of file
class.png

32.3 KB

This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
/*********************************
Memoriaszivargas-detektor
Keszitette: Peregi Tamas, BME IIT, 2011
petamas@iit.bme.hu
Kanari: Szeberenyi Imre, 2013.,
VS 2012: Szeberényi Imre, 2015.,
mem_dump: 2016.
inclue-ok: 2017., 2018., 2019., 2021.
*********************************/
#ifndef MEMTRACE_H
#define MEMTRACE_H
#if defined(MEMTRACE)
/*ha definiálva van, akkor a hibakat ebbe a fajlba írja, egyébkent stderr-re*/
/*#define MEMTRACE_ERRFILE MEMTRACE.ERR*/
/*ha definialva van, akkor futas kozben lancolt listat epit. Javasolt a hasznalata*/
#define MEMTRACE_TO_MEMORY
/*ha definialva van, akkor futas kozben fajlba irja a foglalasokat*/
/*ekkor nincs ellenorzes, csak naplozas*/
/*#define MEMTRACE_TO_FILE*/
/*ha definialva van, akkor a megallaskor automatikus riport keszul */
#define MEMTRACE_AUTO
/*ha definialva van, akkor malloc()/calloc()/realloc()/free() kovetve lesz*/
#define MEMTRACE_C
#ifdef MEMTRACE_C
/*ha definialva van, akkor free(NULL) nem okoz hibat*/
#define ALLOW_FREE_NULL
#endif
#ifdef __cplusplus
/*ha definialva van, akkor new/delete/new[]/delete[] kovetve lesz*/
#define MEMTRACE_CPP
#endif
#if defined(__cplusplus) && defined(MEMTRACE_TO_MEMORY)
/*ha definialva van, akkor atexit helyett objektumot hasznal*/
/*ajanlott bekapcsolni*/
#define USE_ATEXIT_OBJECT
#endif
/******************************************/
/* INNEN NE MODOSITSD */
/******************************************/
#ifdef NO_MEMTRACE_TO_FILE
#undef MEMTRACE_TO_FILE
#endif
#ifdef NO_MEMTRACE_TO_MEMORY
#undef MEMTRACE_TO_MEMORY
#endif
#ifndef MEMTRACE_AUTO
#undef USE_ATEXIT_OBJECT
#endif
#ifdef __cplusplus
#define START_NAMESPACE namespace memtrace {
#define END_NAMESPACE } /*namespace*/
#define TRACEC(func) memtrace::func
#include <new>
#else
#define START_NAMESPACE
#define END_NAMESPACE
#define TRACEC(func) func
#endif
// THROW deklaráció változatai
#if defined(_MSC_VER)
// VS rosszul kezeli az __cplusplus makrot
#if _MSC_VER < 1900
// * nem biztos, hogy jó így *
#define THROW_BADALLOC
#define THROW_NOTHING
#else
// C++11 vagy újabb
#define THROW_BADALLOC noexcept(false)
#define THROW_NOTHING noexcept
#endif
#else
#if __cplusplus < 201103L
// C++2003 vagy régebbi
#define THROW_BADALLOC throw (std::bad_alloc)
#define THROW_NOTHING throw ()
#else
// C++11 vagy újabb
#define THROW_BADALLOC noexcept(false)
#define THROW_NOTHING noexcept
#endif
#endif
START_NAMESPACE
int allocated_blocks();
END_NAMESPACE
#if defined(MEMTRACE_TO_MEMORY)
START_NAMESPACE
int mem_check(void);
END_NAMESPACE
#endif
#if defined(MEMTRACE_TO_MEMORY) && defined(USE_ATEXIT_OBJECT)
#include <cstdio>
START_NAMESPACE
class atexit_class {
private:
static int counter;
static int err;
public:
atexit_class() {
#if defined(CPORTA) && !defined(CPORTA_NOSETBUF)
if (counter == 0) {
setbuf(stdout, 0);
setbuf(stderr, 0);
}
#endif
counter++;
}
int check() {
if(--counter == 0)
err = mem_check();
return err;
}
~atexit_class() {
check();
}
};
static atexit_class atexit_obj;
END_NAMESPACE
#endif/*MEMTRACE_TO_MEMORY && USE_ATEXIT_OBJECT*/
/*Innentol csak a "normal" include eseten kell, kulonben osszezavarja a mukodest*/
#ifndef FROM_MEMTRACE_CPP
#include <stdlib.h>
#ifdef __cplusplus
#include <iostream>
/* ide gyűjtjük a nemtrace-vel összeakadó headereket, hogy előbb legyenek */
#include <fstream> // VS 2013 headerjében van deleted definició
#include <sstream>
#include <vector>
#include <list>
#include <map>
#include <algorithm>
#include <functional>
#include <memory>
#include <iomanip>
#include <locale>
#include <typeinfo>
#include <ostream>
#include <stdexcept>
#include <ctime>
#if __cplusplus >= 201103L
#include <iterator>
#include <regex>
#endif
#endif
#ifdef MEMTRACE_CPP
namespace std {
typedef void (*new_handler)();
}
#endif
#ifdef MEMTRACE_C
START_NAMESPACE
#undef malloc
#define malloc(size) TRACEC(traced_malloc)(size,#size,__LINE__,__FILE__)
void * traced_malloc(size_t size, const char *size_txt, int line, const char * file);
#undef calloc
#define calloc(count,size) TRACEC(traced_calloc)(count, size, #count","#size,__LINE__,__FILE__)
void * traced_calloc(size_t count, size_t size, const char *size_txt, int line, const char * file);
#undef free
#define free(p) TRACEC(traced_free)(p, #p,__LINE__,__FILE__)
void traced_free(void * p, const char *size_txt, int line, const char * file);
#undef realloc
#define realloc(old,size) TRACEC(traced_realloc)(old,size,#size,__LINE__,__FILE__)
void * traced_realloc(void * old, size_t size, const char *size_txt, int line, const char * file);
void mem_dump(void const *mem, size_t size, FILE* fp = stdout);
END_NAMESPACE
#endif/*MEMTRACE_C*/
#ifdef MEMTRACE_CPP
START_NAMESPACE
#undef set_new_handler
#define set_new_handler(f) TRACEC(_set_new_handler)(f)
void _set_new_handler(std::new_handler h);
void set_delete_call(int line, const char * file);
END_NAMESPACE
void * operator new(size_t size, int line, const char * file) THROW_BADALLOC;
void * operator new[](size_t size, int line, const char * file) THROW_BADALLOC;
void * operator new(size_t size) THROW_BADALLOC;
void * operator new[](size_t size) THROW_BADALLOC;
void operator delete(void * p) THROW_NOTHING;
void operator delete[](void * p) THROW_NOTHING;
#if __cplusplus >= 201402L
// sized delete miatt: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3536.html
void operator delete(void * p, size_t) THROW_NOTHING;
void operator delete[](void * p, size_t) THROW_NOTHING;
#endif
/* Visual C++ 2012 miatt kell, mert háklis, hogy nincs megfelelő delete, bár senki sem használja */
void operator delete(void *p, int, const char *) THROW_NOTHING;
void operator delete[](void *p, int, const char *) THROW_NOTHING;
#define new new(__LINE__, __FILE__)
#define delete memtrace::set_delete_call(__LINE__, __FILE__),delete
#ifdef CPORTA
#define system(...) // system(__VA_ARGS__)
#endif
#endif /*MEMTRACE_CPP*/
#endif /*FROM_MEMTRACE_CPP*/
#else
#pragma message ( "MEMTRACE NOT DEFINED" )
#endif /*MEMTRACE*/
#endif /*MEMTRACE_H*/
/**
* \file test.cpp
*
* Cipher nevű szorgalmi feladat tesztjei gtest_lite eszközeivel megvalósítva
* A szorgalmi feladat megoldásához ezt az állományt nem kell beadni (feltölteni).
*
* A ELKESZULT makró vezérli az egyes tesztesetek fordítását, ezzel lehetővé válik
* hogy kisebb lépésekben teszteljünk.
*
*/
#include <iostream>
#include <ctime>
#include "gtest_lite.h"
#include "ciphers.h"
#include "memtrace.h"
#define ELKESZULT 0
/* ELKESZULT makró:
= 5: Caesar titkosítás tesztjei
= 8: Caesar és MyCipher titkosítás tesztjei
= 10: Caesar, MyCipher és a CipherQueue tesztjei - az összes teszt
*/
int main() {
GTINIT(std::cin);
#if ELKESZULT > 0
//Caesar titkosítás ellenőrzése
TEST(Caesar shift=4, _alma) {
CaesarCipher cc(4);
std::string alma = cc.encode("alma");
EXPECT_STREQ("epqe", alma.c_str());
std::string almacr = cc.decode(alma);
EXPECT_STREQ("alma", almacr.c_str());
} END
#endif
#if ELKESZULT > 1
TEST(Caesar shift=3, _uvwxyz) {
CaesarCipher cc(3);
std::string a = cc.encode("uvwxyz");
EXPECT_STREQ("xyzabc", a.c_str());
std::string b = cc.decode(a);
EXPECT_STREQ("uvwxyz", b.c_str());
} END
#endif
#if ELKESZULT > 2
TEST(Caesar shift=-10, _caesar) {
CaesarCipher cc(-10);
std::string a = cc.encode("caesar");
EXPECT_STREQ("squiqh", a.c_str());
std::string b = cc.decode(a);
EXPECT_STREQ("caesar", b.c_str());
} END
#endif
#if ELKESZULT > 3
TEST(Caesar shift=1000, _caesar) {
CaesarCipher cc(1000);
std::string a = cc.encode("caesar");
EXPECT_STREQ("omqemd", a.c_str());
std::string b = cc.decode(a);
EXPECT_STREQ("caesar", b.c_str());
} END
#endif
#if ELKESZULT > 4
TEST(Caesar shift=10, _ez egy uzenet) {
CaesarCipher cc(10);
const std::string str = "ez egy uzenet";
std::string a = cc.encode(str);
EXPECT_STREQ("oj oqi ejoxod", a.c_str());
std::string b = cc.decode(a);
EXPECT_STREQ("ez egy uzenet", b.c_str());
} END
#endif
#if ELKESZULT > 5
TEST(My_Cipher key=abc counter=0, _titkositas) {
MyCipher mc("abc");
std::string a = mc.encode("titkositas");
EXPECT_STREQ("tkxntzobkb", a.c_str());
std::string b = mc.decode(a);
EXPECT_STREQ("titkositas", b.c_str());
} END
#endif
//My cipher tesztek
#if ELKESZULT > 6
TEST(const My_Cipher key=cipher counter=10, _titkositas) {
const MyCipher mc("cipher", 10);
Cipher * const clone = mc.clone();
std::string a = clone->encode("titkositas");
EXPECT_STREQ("fbuegyashs", a.c_str());
std::string b = clone->decode(a);
EXPECT_STREQ("titkositas", b.c_str());
delete clone;
} END
#endif
#if ELKESZULT > 7
TEST(My_Cipher key=xyz counter=-3, _virtualis destruktor) {
MyCipher mc("xyz", -3);
std::string a = mc.encode("virtualis destruktor");
EXPECT_STREQ("pepqtblkw ilybbdvgaf", a.c_str());
std::string b = mc.decode(a);
EXPECT_STREQ("virtualis destruktor", b.c_str());
} END
#endif
//CipherQueue tesztek
CipherQueue queue; //kell majd a következőhöz is
#if ELKESZULT > 8
TEST(Cipher_Queue: caesar + mycipher, _meg tobb szorgalmit prog2bol) {
const CaesarCipher caesar(6);
const MyCipher myCipher("abc", -2);
queue.add(caesar.clone());
queue.add(myCipher.clone());
std::string str1 = queue.encode("meg tobb szorgalmit progkettobol");
EXPECT_STREQ("qko czln fofhyuehfp pqpjmizyvkwv", str1.c_str());
std::string str2 = queue.decode(str1);
EXPECT_STREQ("meg tobb szorgalmit progkettobol", str2.c_str());
} END
#endif
#if ELKESZULT > 9
TEST(Cipher_Queue: inner queue, _pointert mindenhova) {
std::srand(std::time(nullptr));
CipherQueue inner;
inner.add(new MyCipher("queue"));
inner.add(new CaesarCipher(std::rand() % 26));
queue.add(inner.clone());
queue.add(queue.clone()); //ennek sem kellene gondot okoznia
std::string str = queue.decode(queue.encode("pointert mindenhova"));
EXPECT_STREQ("pointert mindenhova", str.c_str());
} END
#endif
if (ELKESZULT < 10)
ADD_FAILURE() << "\nNem futott minden teszteset!" << std::endl;
#if ELKESZULT > 7
//Neptun ellenőrzése
TEST(Kivetelek, Caesar/MyCipher) {
CaesarCipher cc(2);
MyCipher mc("a");
try {
EXPECT_THROW_THROW(cc.decode("A"), const char* p);
} catch (const char *p) {
#ifdef CPORTA
EXPECT_ENVCASEEQ("ORG_ID", p);
#endif
}
try {
EXPECT_THROW_THROW(mc.encode("_"), const char* p);
} catch (const char *p) {
#ifdef CPORTA
EXPECT_ENVCASEEQ("ORG_ID", p);
#endif
}
} END
#endif
GTEND(std::cerr);
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment