Добро пожаловать на Pro Pawn - Портал о PAWN-скриптинге.
Показано с 1 по 5 из 5
  1. #1
    Аватар для kenjutsu
    Пользователь

    Статус
    Оффлайн
    Регистрация
    21.11.2022
    Сообщений
    4
    Репутация:
    0 ±

    sampgdk неверная кодировка

    1. char name[MAX_PLAYER_NAME + 1];
    2. sampgdk::GetPlayerName(id, name, MAX_PLAYER_NAME + 1);


    Если зайти под ником "Привет", то в name будет "яяяПяяяряяяияяявяяяеяяят"
    Но если поставить английскую букву в начале, например "zПривет", то все нормально

    YSF 2.2 (последняя на данный момент) - для поддержки кириллицы в нике
    sampgdk 4.6.2 (последняя на данный момент)

    Читал здесь. Попробовал фикс с помощью побитового &=, не помогло
    Капнул чуть глубже и выяснил, что sampgdk вызывает amx_GetString после вызова стандартной нативы GetPlayerName.
    Не знаю как это может помочь в "исследовании", но думаю это важно.
    В amx не особо разбираюсь, да и в кодировках тоже. Прошу помощи)

    UPD: для интереса попробовал вызвать GetPlayerName через InvokeNative:
    1. char name[MAX_PLAYER_NAME + 1];
    2.  
    3. AMX_NATIVE native = sampgdk::FindNative("GetPlayerName");
    4. sampgdk::InvokeNative(native, "iS[25]i", id, name, 25);


    Результат тот же
    Последний раз редактировалось kenjutsu; 22.11.2022 в 12:42.

  2. #2
    Аватар для kenjutsu
    Пользователь

    Статус
    Оффлайн
    Регистрация
    21.11.2022
    Сообщений
    4
    Репутация:
    0 ±
    100+ просмотров и ни одного ответа? :(

  3. #3
    Аватар для Daniel_Cortez
    "Это не хак, это фича"

    Статус
    Оффлайн
    Регистрация
    06.04.2013
    Адрес
    Novokuznetsk, Russia
    Сообщений
    2,192
    Репутация:
    2590 ±
    Проблема не в sampgdk, а именно в GetPlayerName() (а заодно и в куче других функций SA-MP, которые используют одну общую функцию для конверсии из cell в char и делают это неправильно, расширяя знаковый бит - отсюда и берутся лишние символы "я").
    Как вариант, можно попробовать вызвать функцию через InvokeNative(), но только интерпретировать результат не как строку, а как массив ячеек (сам ни разу не пользовался sampgdk, но думаю, наверняка же можно указать в спецификаторах "A[25]" вместо "S[25]"), и уже из этого массива конвертировать в массив char.
    При этом преобразование должно проводиться без переноса знакового бита, т.е. вместо, скажем, вот такой наивной конверсии:
    1. name[i] = (char)name_cells[i];

    должно быть:
    1. name[i] = (char)(unsigned char)name_cells[i];
    Индивидуально в ЛС по скриптингу не помогаю. Задавайте все свои вопросы здесь (click).

  4. Пользователь сказал cпасибо:
    kenjutsu (29.11.2022)
  5. #4
    Аватар для kenjutsu
    Пользователь

    Статус
    Оффлайн
    Регистрация
    21.11.2022
    Сообщений
    4
    Репутация:
    0 ±
    Цитата Сообщение от Daniel_Cortez Посмотреть сообщение
    Проблема не в sampgdk, а именно в GetPlayerName() (а заодно и в куче других функций SA-MP, которые используют одну общую функцию для конверсии из cell в char и делают это неправильно, расширяя знаковый бит - отсюда и берутся лишние символы "я").
    Как вариант, можно попробовать вызвать функцию через InvokeNative(), но только интерпретировать результат не как строку, а как массив ячеек (сам ни разу не пользовался sampgdk, но думаю, наверняка же можно указать в спецификаторах "A[25]" вместо "S[25]"), и уже из этого массива конвертировать в массив char.
    При этом преобразование должно проводиться без переноса знакового бита, т.е. вместо, скажем, вот такой наивной конверсии:
    1. name[i] = (char)name_cells[i];

    должно быть:
    1. name[i] = (char)(unsigned char)name_cells[i];
    1. // TODO: reverse samp server and implement a normal fix
    2. AMX_NATIVE amx_native = sampgdk::FindNative("GetPlayerName");
    3. if(amx_native != NULL)
    4. {
    5. // Kalcor moment -->
    6. cell name_cells[MAX_PLAYER_NAME + 1];
    7.  
    8. char amx_format[8];
    9. sprintf(amx_format, "iA[%i]i", sizeof(name_cells) / sizeof(cell));
    10.  
    11. sampgdk::InvokeNative(amx_native, amx_format, id, name_cells, MAX_PLAYER_NAME + 1);
    12.  
    13. char name[MAX_PLAYER_NAME + 1];
    14. for (int i = 0; i <= MAX_PLAYER_NAME; i++)
    15. {
    16. name[i] = (char)(unsigned char)name_cells[i];
    17. }
    18. // <-- Kalcor moment
    19. }


    Работает, спасибо :)
    По поводу S и A. Между ними нет разницы, посмотрел в исходниках sampgdk

  6. #5
    Аватар для kenjutsu
    Пользователь

    Статус
    Оффлайн
    Регистрация
    21.11.2022
    Сообщений
    4
    Репутация:
    0 ±
    Все же решил одним глазком заглянуть в идашку :)

    Цель была найти самопальную функцию set_amxstring о которой писал Daniel_Cortez здесь.
    Сначала нашел AMXPrintError по статическим данным, а там рядом оказалась та самая set_amxstring

    Код:
    .text:0046FCB0 ; int __cdecl sub_46FCB0(int, int, _BYTE *, int)
    .text:0046FCB0 sub_46FCB0      proc near 
    .text:0046FCB0                                        
    .text:0046FCB0
    .text:0046FCB0 arg_0           = dword ptr  4
    .text:0046FCB0 arg_4           = dword ptr  8
    .text:0046FCB0 arg_8           = dword ptr  0Ch
    .text:0046FCB0 arg_C           = dword ptr  10h
    .text:0046FCB0
    .text:0046FCB0                 mov     eax, [esp+arg_0]
    .text:0046FCB4                 mov     ecx, [eax]
    .text:0046FCB6                 mov     eax, [ecx+10h]
    .text:0046FCB9                 mov     edx, [esp+arg_4]
    .text:0046FCBD                 add     eax, ecx
    .text:0046FCBF                 add     eax, edx
    .text:0046FCC1                 mov     edx, [esp+arg_C]
    .text:0046FCC5                 test    edx, edx
    .text:0046FCC7                 push    edi
    .text:0046FCC8                 mov     edi, eax
    .text:0046FCCA                 jz      short loc_46FCE6
    .text:0046FCCC                 push    esi
    .text:0046FCCD                 mov     esi, [esp+8+arg_8]
    .text:0046FCD1
    .text:0046FCD1 loc_46FCD1:                            
    .text:0046FCD1                 mov     cl, [esi]
    .text:0046FCD3                 dec     edx
    .text:0046FCD4                 test    cl, cl
    .text:0046FCD6                 jz      short loc_46FCE5
    .text:0046FCD8                 movsx   ecx, cl
    .text:0046FCDB                 mov     [eax], ecx
    .text:0046FCDD                 add     eax, 4
    .text:0046FCE0                 inc     esi
    .text:0046FCE1                 test    edx, edx
    .text:0046FCE3                 jnz     short loc_46FCD1
    .text:0046FCE5
    .text:0046FCE5 loc_46FCE5:                             
    .text:0046FCE5                 pop     esi
    .text:0046FCE6
    .text:0046FCE6 loc_46FCE6:                             
    .text:0046FCE6                 mov     dword ptr [eax], 0
    .text:0046FCEC                 sub     eax, edi
    .text:0046FCEE                 sar     eax, 2
    .text:0046FCF1                 pop     edi
    .text:0046FCF2                 retn
    .text:0046FCF2 sub_46FCB0      endp
    .text:0046FCF2
    .text:0046FCF2 ; ---------------------------------------------------------------------------
    .text:0046FCF3                 align 10h

    Дизассемблер помог понять, что это та самая функция:
    1. int __cdecl sub_46FCB0(int a1, int a2, _BYTE *a3, int a4)
    2. {
    3. _DWORD *v4; // eax
    4. int v5; // edx
    5. _DWORD *i; // edi
    6.  
    7. v4 = (_DWORD *)(a2 + *(_DWORD *)a1 + *(_DWORD *)(*(_DWORD *)a1 + 16));
    8. v5 = a4;
    9. for ( i = v4; v5; ++a3 )
    10. {
    11. --v5;
    12. if ( !*a3 )
    13. break;
    14. *v4++ = (char)*a3; // та самая строка, о которой писал Daniel_Cortez
    15. }
    16. *v4 = 0;
    17. return v4 - i;
    18. }


    Оставалось только заменить movsx(signed extension) на movzx(zero extend).
    Для этого достаточно было просто записать по адресу где находится movsx значение 0xB60F

    Адреса для 03DL:
    Windows: 0x46FCD8
    Linux: 0x80E1AC7
    Последний раз редактировалось kenjutsu; 29.11.2022 в 16:24.

 

 

Информация о теме

Пользователи, просматривающие эту тему

Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •