1 (изменено: MandarinKa02, 2018-07-22 03:14:26)

Тема: AHK: Конвертация endians

Доброго времени суток. Прошу помочь написать функцию для конвертации байтов Big-endian(uint64) в Little-endian(uint64) и обратно.
Перепробовал множество способов.
Одна из попыток сделать так, как здесь: http://qaru.site/questions/2025004/c-htonll-and-back - завершилась также провалом.

Вот, базовые функции для конвертации:


ntohl(int) { ;net>x86
	return DllCall("Ws2_32\ntohl", UInt, int, UInt)
}
htonl(int) { ;x86>net
	return DllCall("Ws2_32\htonl", UInt, int, UInt)
}

ntohs(int) { ;net>x86
	return DllCall("Ws2_32\ntohs", UShort, int, UShort)
}
htons(int) { ;x86>net
	return DllCall("Ws2_32\htons", UShort, int, UShort)
}

Еще одна неудача: https://github.com/benesch/os161/blob/m … t/ntohll.c.


ntohll(int) {
	if (ntohl(1)=1)
		return int

	x0:= int & 0xffffffff
	y0:= ntohl(x0)
	x1:= int >> 32
	y1:= ntohl(x1)
	return (y0 << 32) | y1
}

2

Re: AHK: Конвертация endians

RtlUlonglongByteSwap.

3

Re: AHK: Конвертация endians

Скорее всего, не существует для 64 бит.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

4 (изменено: teadrinker, 2018-07-22 15:46:07)

Re: AHK: Конвертация endians

num := 0xFFEEDDCCBBAA9988
MsgBox, % swap(num, 8)

num := 0x12345678
MsgBox, % swap(num, 4)

num := 0xFEDC
MsgBox, % swap(num, 2)

swap(num, size)  {  ; size — количество байт в числе, поддерживается 2, 4, 8
   if !type := {2: "UShort", 4: "UInt", 8: "UInt64"}[size]
      Return
   VarSetCapacity(buff, size*2, 0)
   NumPut(num, buff, type)
   Loop % size
      DllCall("msvcrt\memmove", Ptr, &buff + size*2 - A_Index, Ptr, &buff + A_Index - 1, Ptr, 1)
   Return Format( "0x{:X}", NumGet(&buff + size, type) )
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

5

Re: AHK: Конвертация endians

MandarinKa02
Не знаю, зачем вам нужны эти uint64, но на всякий случай — AutoHotkey с этим типом нормально не работает, т.к. знает только int64. Поэтому может при вычислениях число испортить.


SetFormat, Integer, Hex
num = 0x8070605040302010
MsgBox, % num + 0

Но если нужен чисто обратный порядок байтов, то проблем быть не должно, наверно.

6

Re: AHK: Конвертация endians

YMP пишет:

т.к. знает только int64

Судя по всему, NumPut/NumGet знает UInt64, попробуй заменить в моём примере на Int64.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

7

Re: AHK: Конвертация endians

Да, NumPut, похоже, знает. Но этот разнобой и путает. Тут играем, тут не играем, тут рыбу заворачивали. В чём, интересно, проблема с общей поддержкой uint64.

8

Re: AHK: Конвертация endians

teadrinker пишет:

Скорее всего, не существует для 64 бит.

Вот из-за подобных случаев я и пользуюсь AHK 32 bit.

9

Re: AHK: Конвертация endians

Сколько много ответов наплыло..
Протестировал еще вчера функцию со второго поста. (спасибо, что напомнили о ней)
Работает как надо.

+ открыть спойлер
ntohl(int) { ;net>x86
	return DllCall("Ws2_32\ntohl", UInt, int, UInt)
}
htonl(int) { ;x86>net
	return DllCall("Ws2_32\htonl", UInt, int, UInt)
}



ntohs(int) { ;net>x86
	return DllCall("Ws2_32\ntohs", UShort, int, UShort)
}
htons(int) { ;x86>net
	return DllCall("Ws2_32\htons", UShort, int, UShort)
}



ntohl_64(int) { ;net>x86
	return htonl_64(int)
}
htonl_64(int) { ;x86>net
	return DllCall("ntdll\RtlUlonglongByteSwap","UInt64",int,"UInt64")
	;return DllCall("Ws2_32\htonll", UInt64, int, UInt64) :NOT_WORK
}
teadrinker пишет:

Скорее всего, не существует для 64 бит.

Существует - https://docs.microsoft.com/en-us/window … ck2-htonll.
Только, начиная с Windows 8.

YMP пишет:

Не знаю, зачем вам нужны эти uint64, но на всякий случай — AutoHotkey с этим типом нормально не работает, т.к. знает только int64. Поэтому может при вычислениях число испортить.

Сам AHK - да, переменной такое большое значение не присвоишь, а вот NumPut'ы работают без проблем.
Зачем нужны? Для программы сделал Web-интерфейс и была поставлена задача - связать основной скрипт с браузером. Использовал WebSocket, здесь у каждого фрейма есть структура, и если длина фрейма больше 16-битного числа(UShort), то необходимо длину фрейма поместить в int64. И здесь предстал вопрос: почему число задом наперед?

10 (изменено: teadrinker, 2018-07-22 21:42:02)

Re: AHK: Конвертация endians

MandarinKa02, ну вы просто монстр программирования, я смотрю.

MandarinKa02 пишет:

Существует - https://docs.microsoft.com/en-us/window … ck2-htonll.

А пример использования можете показать?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

11

Re: AHK: Конвертация endians

Хах, "монстр" - громко сказано. Есть монстры побольше.

teadrinker пишет:

А пример использования можете показать?

Т.к. меня данная функция не работает:

htonl_64(int) {
	return DllCall("Ws2_32\htonll", UInt64, int, UInt64) ;NOT_WORK
}

.. возьму предложенную Malcev'ым.

htonl_64(int) { ;x86>net
	return DllCall("ntdll\RtlUlonglongByteSwap","UInt64",int,"UInt64")
	;return DllCall("Ws2_32\htonll", UInt64, int, UInt64) :NOT_WORK
}

След. пример разбирает фрейм WebSocket'а.

	FIN:=(NumGet(&in_data,0,"UChar"))>>7,offset:=1
	len:=NumGet(&in_data,offset,"UChar")-128,offset+=1 ;exclude the first bit
	OPCODE:=NumGet(&in_data,0,"UChar")-(FIN?128:0)

	if (len>=0) {
		if(len<=125)
			do_nothing()
		else if(len=126)
			len:=htons(NumGet(&in_data,offset,"UShort")),offset+=2 ;16bits
		else if(len=127)
			len:=htonl_64(NumGet(&in_data,offset,"UInt64")),offset+=8 ;64bits
	} VarSetCapacity(mask,4)
	CopyBinData(&in_data+offset,&mask,4),offset+=4
	XOR_crypt(&in_data+offset,data,size:=len,mask)
	StrGet(&data+offset,size,"CP0")
+ XOR_crypt

XOR_crypt(data,ByRef out,size,ByRef key) {
    VarSetCapacity(out,size,0)
    loop % size {
        i:=A_Index-1
        num:=Abs(NumGet(data+0, i,"UChar")-1+1)^NumGet(&key+0, (i & 0x3), "UChar")
        NumPut(num, &out,i,"UChar")
    } return size
}

p.s. недостающие функции можно найти на форумах AHK, если загуглить.

12

Re: AHK: Конвертация endians

MandarinKa02 пишет:

.. возьму предложенную Malcev'ым.

Она у вас не совсем доделанная:

msgbox % htonl_64(0x0123456789abcdef) 
htonl_64(int) { ;x86>net
	return DllCall("ntdll\RtlUlonglongByteSwap","UInt64",int,"UInt64")
	;return DllCall("Ws2_32\htonll", UInt64, int, UInt64) :NOT_WORK
}

13

Re: AHK: Конвертация endians

Это не то?

data := (data << 8) | (data >> 8) ;меняем старший и младший байт местами

14

Re: AHK: Конвертация endians

teadrinker пишет:

А пример использования можете показать?

Судя по её определению,


unsigned __int64 __inline htonll(
   unsigned __int64 value
);

это инлайн-функция, т.е., по сути, макрос. Когда компилятор видит в исходнике её вызов, он туда просто вставляет её код. Поэтому в ws2_32.dll её нет, там только htonl.

15

Re: AHK: Конвертация endians

Ну да, я и смотрю, что в описании dll не указана, то-есть для нас её всё равно, что нет.
Raven, в принципе то, только надо то же самое для такого числа: 0xFFEEDDCCBBAA9988

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

16

Re: AHK: Конвертация endians

teadrinker Ну тогда может так?

data := (data << 32) | (data >> 32) ;меняем старший и младший байт местами

17

Re: AHK: Конвертация endians

Там, во-первых, не 32 байта, а все 64, а во-вторых, нужно не только старший и младший местами поменять, а чтобы все байты были в обратном порядке, чтобы понять, запустите этот код.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

18

Re: AHK: Конвертация endians

Нашёл в winsock2.h код, который выполняет htonll.


#define _WS2_32_WINSOCK_SWAP_LONGLONG(l)            \
            ( ( ((l) >> 56) & 0x00000000000000FFLL ) |       \
              ( ((l) >> 40) & 0x000000000000FF00LL ) |       \
              ( ((l) >> 24) & 0x0000000000FF0000LL ) |       \
              ( ((l) >>  8) & 0x00000000FF000000LL ) |       \
              ( ((l) <<  8) & 0x000000FF00000000LL ) |       \
              ( ((l) << 24) & 0x0000FF0000000000LL ) |       \
              ( ((l) << 40) & 0x00FF000000000000LL ) |       \
              ( ((l) << 56) & 0xFF00000000000000LL ) )


#ifndef htonll
__inline unsigned __int64 htonll ( unsigned __int64 Value ) 
{ 
    const unsigned __int64 Retval = _WS2_32_WINSOCK_SWAP_LONGLONG (Value);
    return Retval;
}
#endif /* htonll */

Выглядит довольно громоздко, учитывая, что у процессора есть инструкция bswap, которая делает это сразу для 32- или 64-битного регистра. А здесь получается для каждого байта сдвиг и AND, да потом ещё OR между результатами. Куча инструкций.

19

Re: AHK: Конвертация endians

Китаец какой-нибудь писал, не иначе.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder