niedziela, 20 stycznia 2008

Cudowny zapach

Dusia weszła po cichu ukradkiem, żeby Michał jej nie zauważył. Michał siedział przy komputerze jak zwykle nocną porą. Dusia dotknęła jego ramienia. Michał wystraszył się. Dusia zaśmiała sie głośno.
--- Michale nad czym tak długo siedzisz?
--- Nad pisaniem bibliotek w języku programowania C dla innego języka programowania Pythona.
--- A co w tym jest takiego interesującego?
--- To, że można rozszerzać możliwości programowania w języku Python. Na przykład zechcesz prowadzić korespondencję za pomocą zaszyfrowanych SMS. Jedyną rzeczą jest to, że musisz znać hasło. Tym hasłem może być data.
--- No już wiem co chcesz napisać, ale dlaczego w języku programowania Python a nie C++?
--- Już Ci tłumaczę Dusia. Otóż programiści wolą mieć dużo małych programików, które robią jakaś funkcjonalność dobrze. Powiedzmy, że ktoś napisał bibliotekę czyli taki programik, który będzie można dołączać do innych programów. Mnie zainteresowała biblioteka do szyfrowania. Ale w Symbianie C++ nie ma takiej biblioteki publicznie dostępnej. Firma Nokia zaproponowała, żeby programiści napisali taką bibliotekę P.I.P.S. dla Symbiana. Jest ona dostępna w tym miejscu. Teraz gdy mam do napisania dzięki tej bibliotece szyfrowanie SMS to muszę wybrać w jakim języku programowania to napiszę. Obecnie na komórki można programować w takich językach programowania jak C++, Java, Python czy Open C, Postanowiłem napisać kod w Open C i w Pythonie.
Dusia zasłuchana patrzyła ze zdziwieniem
--- Ale z Ciebie Michale poliglota! Jak można się nauczyć tylu języków programowania?
--- Z pasja można sie nauczyć. Pokaże Ci kod do wysyłania SMS dobrze?
Dusia wyjęła z kieszeni szlafroka lakier i zaczęła lakierować paznokcie u stóp. Michał napisał kod w Pythonie:

messaging.sms_send(rcp, txt)

a potem w Symbian C++

RSendAs srv;
if ( srv.Connect() == KErrNone )
{
CleanupClosePushL(srv);
RSendAsMessage msg;
CleanupClosePushL(msg);
msg.CreateL(srv, KSenduiMtmSmsUid);
msg.AddRecipientL(recipient,RSendAsMessage::ESendAsRecipientTo);
msg.SetBodyTextL(message);
msg.SendMessageAndCloseL();
CleanupStack::Pop(&msg);
}
else
{
CleanupClosePushL(srv);
}


--- Ale kod w Pythonie to jedna linijka kodu!? Kod w C++ jest taki skomplikowany. Po co mnie uczysz C++?
--- Żebyś była wyjątkowa!!! Właśnie chciałem Ci pokazać dlaczego powstają nowe języki programowania. Programiści piszą je przede wszystkim, żeby ułatwić innym i sobie pisanie kodu aplikacji. Ale to niesie pewne niebezpieczeństwo. Ci, którzy zaczynają naukę od takich języków jak Java czy Python zapominają często o tym jak wygląda działanie programu w systemie operacyjnym Symbian, ponieważ te języki programowania upraszczają pewne działania. Na przykład w tych językach programowania programista nie musi zajmować się zarządzaniem danych w pamięci, natomiast programując w C++ musi o tym pamiętać.
--- Ale ja nadal nie wiem po co mam poznawać C++ skoro są łatwiejsze języki programowania niż C++ na Symbianie?
--- Dusiu, warto poświecić więcej czasu na zrozumienie takich rzeczy jak zarządzanie pamięcią czy obsługa sytuacji krytycznych w Symbianie, albo nauczyć się pisać kod według określonych konwencji nazewniczych. Dzięki temu masz większy dostęp do możliwości tego systemu operacyjnego. Aplikacje pisane w C++ powinny działać szybciej. Znajomość C++ pozwoli Tobie na rozszerzanie możliwości tych języków, które są napisane w C++.
--- Czy to oznacza, że inne języki programowania są zależne od C++?
--- W praktyce tak. Na przykład kod źródłowy języków takich jak Python jest napisany w C++. To pozwala innym programistom rozszerzać możliwości takiego języka. Ja właśnie zajmuję się dzisiaj takim przypadkiem. Chcę napisać rozszerzenie do języka programowania Python S60 do szyfrowania. Interfejs graficzny użytkownika aplikacji ma być napisany w języku programowania Python, bo zajmuje mniej kodu niż jego odpowiednik w C++. Dusiu, pokażę Ci kawałek kodu z pliku nagłówkowego s60_crypt.h
Dusia wróciła do lakierowania paznokci. Michał napisał kod:

#ifndef S60_CRYPT_H
#define S60_CRYPT_H

extern void
s60_encrypt(int len,
char* in,
char* out,
char* password,
int passlen);

extern void
s60_decrypt(int len,
char* in,
char* out,
char* password,
int passlen);

#endif

--- Michale przypomnij mi do czego są używane pliki nagłówkowe.
--- Informują kompilatora jakie funkcje mają zawierać. W tym przypadku mamy dwie funkcje. Jedna służy do szyfrowania a druga do odszyfrowania.
--- I to wszystko?
--- Nie Dusiu, trzeba jeszcze napisać jak ma działać takie szyfrowanie i odszyfrowywanie,
Dusia wyszła z pokoju. Michał napisał kod w Open C w pliku s60crypt.c

#include <stddef.h>
#include <openssl/rc4.h>
#include <openssl/md5.h>

void s60_encrypt(int len, unsigned char* in, unsigned char* out, unsigned char* password, int passlen)
{
unsigned char digest[MD5_DIGEST_LENGTH];
RC4_KEY key;

MD5(password, passlen, digest);

RC4_set_key(&key, MD5_DIGEST_LENGTH, digest);
RC4(&key, len, in, out);
}

void s60_decrypt(int len, unsigned char* in, unsigned char* out, unsigned char* password, int passlen)
{
unsigned char digest[MD5_DIGEST_LENGTH];
RC4_KEY key;

MD5(password, passlen, digest);

RC4_set_key(&key, MD5_DIGEST_LENGTH, digest);
RC4(&key, len, in, out);
}

Dusia wróciła z flakonikiem. Popatrzyła na Michała zalotnie.
-- No widzę kod, ale nic nie rozumiem z tego. Chyba pożegnam się z marzeniami o programowaniu. Przerażasz mnie.
-- Już po kilku dniach panikujesz - uśmiechnął się - najpierw trzeba sie oswoić z tym okropnym wyglądem potwora. Obserwuj potwora pomimo, że nic nie rozumiesz. Potraktuj lekcje programowania jak naukę czytania chińskich znaków (ideogramów).
--- Nie dam sie nabrać Michale! - odpowiedziała wkurzona
--- Dusiu został nam jeszcze jeden plik źródłowy dla tego rozszerzenia. To jest plik wraper.c
Dusia patrzyła bezradna na Michała. Chciała żeby ją sie zajął. Postawiła swoje stopy na jego kolanach. Rozluźniła szlafrok i odsłoniła swoje wdzięki. Michał pisał kod i od czasu do czasu uśmiechał się zalotnie. Dusia zaczęła rozpinać jego koszulę. Z kobiecej przekory przeszkadzała mu. Michał napisał taki kod w języku Open C

#include <Python.h>
#include "s60crypt.h"

static PyObject* pycrypt_encrypt(PyObject* self, PyObject* args)
{
char* data;
int datalen;
char* pw;
int pwlen;
char* out;
PyObject* result;

if (!PyArg_ParseTuple(args, "s#s#", &data, &datalen, &pw, &pwlen))
return NULL;

out = (char*)malloc(datalen);
if (!out)
return PyErr_NoMemory();

s60_encrypt(datalen, data, out, pw, pwlen);

result = Py_BuildValue("s#", out, datalen);
free(out);
if (!result)
return PyErr_NoMemory();

return result;
}

static PyObject* pycrypt_decrypt(PyObject* self, PyObject* args)
{
char* data;
int datalen;
char* pw;
int pwlen;
char* out;
PyObject* result;

if (!PyArg_ParseTuple(args, "s#s#", &data, &datalen, &pw, &pwlen))
return NULL;

out = (char*)malloc(datalen);
if (!out)
return PyErr_NoMemory();

s60_decrypt(datalen, data, out, pw, pwlen);

result = Py_BuildValue("s#", out, datalen);
free(out);
if (!result)
return PyErr_NoMemory();

return result;
}


static const PyMethodDef PyCryptMethods[] =
{
{"encrypt", pycrypt_encrypt, METH_VARARGS},
{"decrypt", pycrypt_decrypt, METH_VARARGS},
{NULL, NULL}
};

DL_EXPORT(void) initpycrypt(void)
{
(void)Py_InitModule("pycrypt", PyCryptMethods);
}

--- Dusiu nie łaskocz mnie.
Dusia zrzuciła szlafrok i otworzyła flakonik. Cudowny zapach fiołków uniósł sie w pokoju.
-- Michale namaść mnie olejkiem. Chcę być królową programistów.
Postawiła flakonik i zaczęła namaszczać Michała po jego plecach. Michał zaśmiał się głośno.
--- A ja mam być królem programistów? Nie wiem, czy do tego się nadaję. Teraz pozostaje mi plik napisać plik dla kompilatora, żeby wiedział co ma skompilować. Taki plik to pycrypt.mmp i wygląda tak:

TARGET pycrypt.dll
TARGETTYPE dll
UID 0x00000000 0x0CBDC9B9
EXPORTUNFROZEN

CAPABILITY NetworkServices LocalServices ReadUserData WriteUserData UserEnvironment

NOSTRICTDEF

USERINCLUDE ..\include
SYSTEMINCLUDE \epoc32\include
SYSTEMINCLUDE \epoc32\include\stdapis
SYSTEMINCLUDE \epoc32\include\python

SOURCEPATH ..\src

SOURCE s60crypt.c
SOURCE wrapper.c

LIBRARY libc.lib
LIBRARY euser.lib
LIBRARY libcrypt.lib
LIBRARY libcrypto.lib
LIBRARY python222.lib

I jeszcze trzeba dodać plik tworzący bibliotekę bld.inf Kompilator musi wiedzieć na jaką architekturę procesorów ma skompilować ten kod

PRJ_PLATFORMS
ARMV5 ARMV5_ABIV2 GCCE WINSCW

PRJ_MMPFILES
pycrypt.mmp

--- Dusiu zostało mi skompilować
--- Michale nie teraz. Teraz jesteś mój i ja chcę, żebyś mnie popieścił.
Michał zapisał pracę i klęknął przy niej. Michał nalał na dłoń olejku i namaścił jej stopy. Jej ciało przenikał cudowny zapach.

2 komentarze:

Lax pisze...

Doskonałe, może jakiś wieczorek autorski na następnym żąmidja tour? :)

K pisze...

szkoda, ze nie ma zrodel ;)
ja np. szukam programu do szyfrowania sms-ow i taki pythonowy program bylby fajny. Wazne by dalo sie to latwo odczytac np.
openssl enc ...