Zamiana ciągów znaków (HEX) na inny o tej samej długości

0

Witam.

Próbuję napisać program zmieniający ciąg znaków (HEX) na inny o tej samej długości. Robię to w C++ i mam trochę problem (dopiero w sumie raczkuję w temacie). Znalazłem pewną funkcję która robi to dla jednego ciągu i to działa po modyfikacji, jednak zależy mi aby tych ciągów do zmiany było wiele (nieokreślona ilość z możliwością dopisywania). Kod działający z jednym ciągiem wygląda tak:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <iostream>
#include <fstream>

using namespace std;

size_t replace(FILE *fi, FILE *fo, uint8_t *what, uint8_t *repl, size_t size){
    size_t i, index = 0, count = 0;
    int ch;
    while(EOF!=(ch=fgetc(fi))){
        if(ch == what[index]){
            if(++index == size){
                for(i = 0; i < size ; ++i){
                    fputc(repl[i], fo);
                }
                index = 0;
                ++count;
            }
        } else {
            for(i = 0; i < index ; ++i){
                fputc(what[i], fo);
            }
            index =0;
            fputc(ch, fo);
        }
    }
    for(i = 0; i < index ; ++i){
        fputc(what[i], fo);
    }

    return count;
}

int main(void){
    
    FILE *file,*fileout;

    uint8_t what[] = {0xA8, 0x78, 0x0A, 0x21, 0x6A} ; uint8_t repl[] = {0xE8, 0x78, 0x0A, 0x21, 0x6A};
    size_t count;
    file=fopen("fw","rb");
    fileout=fopen("fw_changed","wb");
    count = replace(file, fileout, what, repl, sizeof(what));
//
//    delete what;
//    delete repl;
//
//    uint8_t what[] = {0xA8, 0x78, 0xB0, 0xFB, 0xF1};     uint8_t repl[] = {0xE8, 0x78, 0xB0, 0xFB, 0xF1};
//    file=fopen("fw","rb");
//    fileout=fopen("fw_changed","wb");
//    count = replace(file, fileout, what, repl, sizeof(what));

    fclose(fileout);
    fclose(file);
    return 0;
}

chciałbym to zrobić tego typu:

 uint8_t what[] = {0xA8, 0x78, 0x0A, 0x21, 0x6A} ; uint8_t repl[] = {0xE8, 0x78, 0x0A, 0x21, 0x6A};
 uint8_t what[] = {0xA8, 0x78, 0x0A, 0x21, 0x6A} ; uint8_t repl[] = {0xE8, 0x78, 0x0A, 0x21, 0x6A};
 uint8_t what[] = {0xA8, 0x78, 0x0A, 0x21, 0x6A} ; uint8_t repl[] = {0xE8, 0x78, 0x0A, 0x21, 0x6A};
 uint8_t what[] = {0xA8, 0x78, 0x0A, 0x21, 0x6A} ; uint8_t repl[] = {0xE8, 0x78, 0x0A, 0x21, 0x6A};
 uint8_t what[] = {0xA8, 0x78, 0x0A, 0x21, 0x6A} ; uint8_t repl[] = {0xE8, 0x78, 0x0A, 0x21, 0x6A};
 uint8_t what[] = {0xA8, 0x78, 0x0A, 0x21, 0x6A} ; uint8_t repl[] = {0xE8, 0x78, 0x0A, 0x21, 0x6A};
 uint8_t what[] = {0xA8, 0x78, 0x0A, 0x21, 0x6A} ; uint8_t repl[] = {0xE8, 0x78, 0x0A, 0x21, 0x6A};
 uint8_t what[] = {0xA8, 0x78, 0x0A, 0x21, 0x6A} ; uint8_t repl[] = {0xE8, 0x78, 0x0A, 0x21, 0x6A};
 uint8_t what[] = {0xA8, 0x78, 0x0A, 0x21, 0x6A} ; uint8_t repl[] = {0xE8, 0x78, 0x0A, 0x21, 0x6A};
 uint8_t what[] = {0xA8, 0x78, 0x0A, 0x21, 0x6A} ; uint8_t repl[] = {0xE8, 0x78, 0x0A, 0x21, 0x6A};
....

bo tych ciągów będzie do zmiany.

Próbowałem powtórzyć:

    uint8_t what[] = {0xA8, 0x78, 0x0A, 0x21, 0x6A} ; uint8_t repl[] = {0xE8, 0x78, 0x0A, 0x21, 0x6A};
    size_t count;
    file=fopen("fw","rb");
    fileout=fopen("fw_changed","wb");
    count = replace(file, fileout, what, repl, sizeof(what));

ale pojawia się problem (error) redeklaracji zmiennych i nie wygląda to na optymalnie. Możecie pomóc?

0

Z tego co widzę po prostu potrzebujesz dwuwymiarowej tablicy, po której w pętli wywołasz replace dla każdej pary co->na co

0

Myślałem o tym, ale nie udało mi się to zrobić. Próbowałem jeszcze znaleźć sposób, aby w pętli podmieniać to: {0xA8, 0x78, 0x0A, 0x21, 0x6A} przed "uint8_t what[] =" w jakiejś innej tablicy np. what2 ale też coś nie poszło.

size_t replace(FILE *fi, FILE *fo, uint8_t *what, uint8_t *repl, size_t size){
    size_t i, index = 0, count = 0;
    int ch;
    while(EOF!=(ch=fgetc(fi))){
        if(ch == what[index][1]){
            if(++index == size){
                for(i = 0; i < size ; ++i){
                    fputc(repl[i][1], fo);
                }
                index = 0;
                ++count;
            }
        } else {
            for(i = 0; i < index ; ++i){
                fputc(what[i][1], fo);
            }
            index =0;
            fputc(ch, fo);
        }
    }
    for(i = 0; i < index ; ++i){
        fputc(what[i][1], fo);
    }
 
    return count;
}

Gdy dokładam drugi wymiar do tablic ([]) i próbuję to testowo wywołać to mam błędy.


int main(void){
 
    FILE *file,*fileout;
 
    uint8_t what[][1] = {0xA8, 0x78, 0x0A, 0x21, 0x6A} ; uint8_t repl[][1] = {0xE8, 0x78, 0x0A, 0x21, 0x6A};
    size_t count;
    file=fopen("fw","rb");
    fileout=fopen("fw_changed","wb");
    count = replace(file, fileout, what, repl, sizeof(what));
 
    fclose(fileout);
    fclose(file);
    return 0;
}

G:\programowanie\c++\zamiana\main.cpp|13|error: invalid types 'uint8_t {aka unsigned char}[int]' for array subscript|

0

Źle przekazujesz tablicę do funkcji. Zobacz tutaj jak powinno się to robić.

1

No tak, tylko że jak próbuję zrobić powtórzenie, to mam komunikat o redeklaracji zmiennych i nie działa.

Możesz zrobić tak:

uint8_t tab[][2][5] = 
	{
		{ {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} },
		{ {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} },
		{ {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} },
		{ {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} },
		{ {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} },
		{ {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} },
		{ {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} },
		{ {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} },
		{ {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} },
		{ {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} }
	};


	for(auto &p : tab)
	{
		...
	
		replace(file, fileout, p[0], p[1], sizeof(p[0]));

		...
	}

Choć jak pisałem, lepiej wczytać plik do pamięci.

--- dodane ---

	std::vector<uint8_t> v;

	// tu do 'v' wczytujesz plik 

	for(auto &p : tab)
	{
		auto i = v.begin();

		while(i != v.end())
		{
			i = std::search(i, v.end(), std::begin(p[0]), std::end(p[0]));
			if(i != v.end())
			{
				i = std::copy(std::begin(p[1]), std::end(p[1]), i);
			}
		}
	}

	// tu zapisujesz zawartość 'v' do pliku
0
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <iostream>
#include <fstream>

using namespace std;

size_t replace(FILE *fi, FILE *fo, uint8_t *what, uint8_t *repl, size_t size){
    size_t i, index = 0, count = 0;
    int ch;
    while(EOF!=(ch=fgetc(fi))){
        if(ch == what[index]){
            if(++index == size){
                for(i = 0; i < size ; ++i){
                    fputc(repl[i], fo);
                }
                index = 0;
                ++count;
            }
        } else {
            for(i = 0; i < index ; ++i){
                fputc(what[i], fo);
            }
            index =0;
            fputc(ch, fo);
        }
    }
    for(i = 0; i < index ; ++i){
        fputc(what[i], fo);
    }

    return count;
}

int main(void){

    FILE *file,*fileout;

    uint8_t tab[][2][5] =
    {
        { {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} },
        { {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} },
        { {0x00, 0x98, 0x00, 0x20, 0xA5}, {0x00, 0x00, 0x00, 0x00, 0x00} },
        { {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} },
        { {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} },
        { {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} },
        { {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} },
        { {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} },
        { {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} },
        { {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} }
    };

    file=fopen("fw","rb");
    fileout=fopen("fw_changed","wb");

    for(auto &p : tab)
    {

        replace(file, fileout, p[0], p[1], sizeof(p[0]));

    }

    fclose(fileout);
    fclose(file);
    return 0;
}

Próbuję ogarnąć na razie wersję z operacją na pliku i coś nie działa to u mnie.
Działa tylko jakby pierwszy wiersz: { {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} },

1
for(auto &p : tab)
{
        // tu otwierasz pliki
        replace(file, fileout, p[0], p[1], sizeof(p[0]));
        // tu je zamykasz
}

Jak łatwo się domyślić w pierwszej iteracji otwierasz pliki fw i fw_changed, przy następnych na zmianę fw_changed i fw_changed2. Średnio to wygląda, i dlatego uważam, że to kiepski pomysł.

0
    file=fopen("fw","rb");
    fileout=fopen("fw_changed","wb");

    for(auto &p : tab)
    {
        fseek  (file, 0 , SEEK_SET);
        fseek  (fileout, 0 , SEEK_SET);

        replace(file, fileout, p[0], p[1], sizeof(p[0]));

   }
    cout << "bele " << tab[0][2][5];



    fclose(fileout);
    fclose(file);

coś w tym stylu?

0

Raczej tak:

file1 = fopen("fw","rwb");
file2 = fopen("fw_changed","rwb");

for(auto &p : tab)
{
	replace(file1, file2, p[0], p[1], sizeof(p[0]));

	fseek  (file1, 0 , SEEK_SET);
	fseek  (file2, 0 , SEEK_SET);

	std::swap(file1, file2);
}

...

Policz, w którym pliku będziesz miał wynik ;) Oba pliki są modyfikowane...

PS. zamiast fseek() możesz użyć rewid().

0

OK, to teraz mnie czeka nauka wczytywania pliku do buforu i zapisu z buforu. Z tego co wstępnie zauważyłem, operacja na plikach stricte tekstowych jest dużo prostsza :)

0

OK, testowo napisałem kod do wczytywania pliku do wektora:

char znak;
 vector<uint8_t> v;
 ifstream fw;
 fw.open("fw", ios::in|ios::binary);

 while(fw.get(znak))
 v.push_back(znak);
 fw.close();

 for (int a=0;a<=50;a++){
 cout << hex << setfill('0') << setw(2) <<(int)v[a] <<  " ";
 }

I teraz co zauważyłem, że do wektora nie wczytuje się wersja HEX tylko jakieś dziwne znaki:

0  0ś 0  0  0ą 0 0  0  0ş 0 0  0  0┼ 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0Ţ 0 0  0  0  0  0

to wypluwa cout << v[a];

przy (int)v[a]; jest OK:

00 98 00 20 a5 04 00 20 ad 04 00 20 c5 04 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 dd 04 00 20 00 00 00

I jak dalej sobie z tym poradzić?

0

Mam już tak:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <iterator>
#include  <iomanip>

using namespace std;


int main () {
    char znak;
    vector<uint8_t> v;
    ifstream fw;
    fw.open("fw.bin", ios::in|ios::binary);

    while(fw.get(znak))
    v.push_back(znak);


    uint8_t tab[][2][5] =
    {
        { {0x00, 0x98, 0x00, 0x20, 0xA5}, {0x00, 0x00, 0x00, 0x00, 0x00} },
        { {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} },
        { {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x00, 0x00, 0x00, 0x00, 0x00} },
        { {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} },
        { {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} },
        { {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} },
        { {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} },
        { {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} },
        { {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} },
        { {0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A} }
    };


    for(auto &p : tab)
    {
        auto i = v.begin();

        while(i != v.end())
        {
            i = search(i, v.end(), begin(p[0]), end(p[0]));
            if(i != v.end())
            {
                i = copy(begin(p[1]), end(p[1]), i);
            }
        }
    }

    ofstream fw2;
    fw2.open("fw2.bin", std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
    fw2.write(reinterpret_cast<char*>(&v[0]), v.size());


    fw.close();
    fw2.close();

    return 0;
}

Ale coś źle działa - na początku podmienia OK, potem jest kaszanka.

W pliku fw.bin mam np.:

FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF

a po operacji w fw2.bin tak:

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF

Generalnie wszędzie tam gdzie napotyka FF FF FF ... to jest zeruje.

1

Tak czytaj:

	vector<uint8_t> v( fw.seekg(0, ios_base::end).tellg() );

	fw.seekg(0).read(static_cast<char*>(&v.front()), v.size());
0

A jakbym chciał użyć różnej długości ciągów do zmiany, np: część 5 znakowych, część 6. to musiałbym utworzyć drugą tablicę tab2 i powtórzyć te operacje? Bo jak próbowałem dodać 3 znakową "podmianę" do tej tablicy 5 znakowej, to program nie wypluł błędem, ale zmiana nie dokonała się.

0

Jeśli wzorzec i nowy ciąg są takiej samej długości (tak jak teraz), to wtedy najprościej zrobić drugą tablicę i powtórzyć operację, oczywiście pomijając ponowne wczytywanie pliku.

0

Bardzo dziękuję za wszelką pomoc - działa jak trzeba teraz :) Jeszcze pozostaje mi trochę go rozbudować o możliwość wczytywania pliku z linii komend np. program.exe -i plik.fw. Mógłbyś podpowiedzieć?

0

Jak chcesz pobrać argumenty wywołania programu, wtedy funkcja main() powinna wyglądać tak: int main ( int argc, char **argv ) { ... }. argc to liczba elementów w tablicy argv. Podejrzyj sobie co tam jest ;)

0

Zrobione :)

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <iterator>
#include  <iomanip>

using namespace std;


int main ( int argc, char *argv[] )
{
   string ble;
   ofstream fw2;

    ifstream fw (argv[1], ios::in|ios::binary );
 

 ble=argv[1];
 ble="data_"+ble;

    uint8_t tab[][2][5] =
    {
        {{0xA8, 0x78, 0x0A, 0x21, 0x6A}, {0xE8, 0x78, 0x0A, 0x21, 0x6A}},
        {{0xA8, 0x78, 0xB0, 0xFB, 0xF1}, {0xE8, 0x78, 0xB0, 0xFB, 0xF1}},
        {{0xEB, 0x78, 0x40, 0x1C, 0x0A}, {0xAB, 0x78, 0x40, 0x1C, 0x0A}},
        {{0xEB, 0x78, 0x40, 0x1C, 0xB3}, {0xAB, 0x78, 0x40, 0x1C, 0xB3}},
        {{0xA8, 0x7D, 0x0A, 0x21, 0xB0}, {0xE8, 0x7D, 0x0A, 0x21, 0xB0}},
        {{0xEB, 0x7D, 0x40, 0x1C, 0x0A}, {0xAB, 0x7D, 0x40, 0x1C, 0x0A}},
        {{0xEB, 0x7D, 0x40, 0x1C, 0xB3}, {0xAB, 0x7D, 0x40, 0x1C, 0xB3}},
        {{0xE3, 0x78, 0xA2, 0x78, 0x19}, {0xE2, 0x78, 0xA2, 0x78, 0x19}},
        {{0xA2, 0x78, 0x19, 0xA1, 0x68}, {0xA3, 0x78, 0x19, 0xA1, 0x68}},
        {{0xE3, 0x7D, 0xA2, 0x7D, 0x2F}, {0xE2, 0x7D, 0xA2, 0x7D, 0x2F}},
        {{0xA2, 0x7D, 0x2F, 0xA1, 0x05}, {0xA3, 0x7D, 0x2F, 0xA1, 0x05}},
        {{0xE3, 0x78, 0xA2, 0x78, 0x44}, {0xA3, 0x78, 0xA2, 0x78, 0x44}},
        {{0xA2, 0x78, 0x44, 0xA1, 0x03}, {0xE2, 0x78, 0x44, 0xA1, 0x03}},
        {{0xE3, 0x78, 0xA2, 0x78, 0x33}, {0xA3, 0x78, 0xA2, 0x78, 0x33}},
        {{0xA2, 0x78, 0x33, 0xA1, 0x03}, {0xE2, 0x78, 0x33, 0xA1, 0x03}},

        {{0x78, 0x21, 0xF2, 0xE7, 0x7A}, {0x72, 0x21, 0xF2, 0xE7, 0x7A}}
    };


    vector<uint8_t> v(fw.seekg(0, ios_base::end).tellg());
    fw.seekg(0).read(reinterpret_cast<char*>(&v.front()), v.size());

    c=0;


    for(auto &p : tab)
    {
        auto i = v.begin();
        while(i != v.end())
        {
            i = search(i, v.end(), begin(p[0]), end(p[0]));

            if(i != v.end())
            {
                i = copy(begin(p[1]), end(p[1]), i);
                c++;
            }
        }
    }

    cout << "Ilosc zmian: "<< c << " " ;
    fw2.open(ble, std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
    fw2.write(reinterpret_cast<char*>(&v[0]), v.size());


    fw.close();
    fw2.close();

    return 0;
}

Tylko trochę mało eleganckie, bo zmianę do nazwy pliku dodaję na początek, bo nie wiem jak to zrobić po nazwie pliku, ale przed rozszerzeniem.
I nie wiem jeszcze gdzie wstawić zmienną, która wyliczy ilość "wierszy" z tablicy oraz tego, że jak nie znajdzie w ogóle danych stringów to żeby wypisał których.

1
    std::string fn = "filename.ext";
    
    auto pos = fn.find_last_of('.');
    fn.insert(pos != std::string::npos ? pos : fn.size(), "-changed");
0

Zrobiłem proste zabezpieczenie:

if ((int)argv[1]<1) {
    cout << "A gdzie firmware? (przyklad: zmiana fw.fw)" ; return 0;
}
else
1

Ech...

if (argc < 2) { ... }

1 użytkowników online, w tym zalogowanych: 0, gości: 1