#include <iostream>
using namespace std;

typedef unsigned char   u_char;
typedef char CCHAR; 
typedef int16_t WCHAR;
typedef uint32_t ULONG;
typedef uint32_t DWORD;
typedef uint64_t LARGE_INTEGER;

#pragma pack(1)

typedef struct smb2_FileBothDirectoryInformation {
	ULONG         NextEntryOffset;
	ULONG         FileIndex;
	LARGE_INTEGER CreationTime;
	LARGE_INTEGER LastAccessTime;
	LARGE_INTEGER LastWriteTime;
	LARGE_INTEGER ChangeTime;
	LARGE_INTEGER EndOfFile;
	LARGE_INTEGER AllocationSize;
	ULONG         FileAttributes;
	ULONG         FileNameLength;
	ULONG         EaSize;
	CCHAR         ShortNameLength;
	CCHAR         Reserved;
	WCHAR         ShortName[12];
	LARGE_INTEGER FileId; // Missing in [MS-FSCC]: File System Control Codes - 2.4.8 FileBothDirectoryInformation
	u_char         Reserved2[2]; // Missing in [MS-FSCC]: File System Control Codes - 2.4.8 FileBothDirectoryInformation
	WCHAR         FileName[1];
} smb2_FileBothDirectoryInformation_t;

typedef struct {
	uint16_t StructureSize;
	uint16_t OutputBufferOffset;
	uint32_t OutputBufferLength;
	u_char Buffer[1];
} smb2_query_directory_response_t;
#pragma pack()

//https://stackoverflow.com/questions/15934111/portable-and-safe-way-to-add-byte-offset-to-any-pointer
template <typename T> inline void addOffset(std::ptrdiff_t offset, T *&ptr) {
	if (!ptr) return;
	ptr = (T*)((const unsigned char*)ptr + offset);
}
template <typename T> inline T* offset(std::ptrdiff_t offset, T *ptr) {
	return (T*)((const unsigned char*)ptr + offset);
}
//SomeType* ptr; int offset = 12345; offset_ptr(offset, ptr);
template <typename T> inline void offset_ptr(std::ptrdiff_t byte_offset, const T* &ref_ptr) {
	ref_ptr = (T*)((const unsigned char*)ref_ptr + byte_offset);
}
 
//If you use this marco like `typedef struct {} SomeType; SomeType* ptr; OFFSET_PTR(16, ptr);`
//IDE error: expression must be a modifiable value. Compile: error C2106: '=': left operand must be l-value. 
#define OFFSET_PTR(byte_offset, ref_ptr) ((const unsigned char*)ref_ptr = (const unsigned char*)ref_ptr + byte_offset)

char packet_bytes[9] = {0};
 
int main() {
	printf("(int)sizeof(smb2_query_directory_response_t) = %d\n", (int)sizeof(smb2_query_directory_response_t));
	printf("(int)sizeof(smb2_FileBothDirectoryInformation_t) = %d\n", (int)sizeof(smb2_FileBothDirectoryInformation_t));
 
	const smb2_query_directory_response_t*  pQueryDirInfoRsp = (smb2_query_directory_response_t*)packet_bytes;
	const smb2_FileBothDirectoryInformation_t *pFileBothDirInfo = pQueryDirInfoRsp->OutputBufferLength ? reinterpret_cast<const smb2_FileBothDirectoryInformation_t*>(pQueryDirInfoRsp->Buffer) : NULL;
	while (pFileBothDirInfo)
	{
		// ideone runs on linux with a compiler who consider wchar_t 4 bytes?
		// https://stackoverflow.com/questions/16944750/c-unicode-characters-printing
		//wprintf(L"%.*s|%.*s\n", pFileBothDirInfo->FileNameLength/2, pFileBothDirInfo->FileName, pFileBothDirInfo->ShortNameLength/2, pFileBothDirInfo->ShortName);
		if (pFileBothDirInfo->NextEntryOffset)
		{
			offset_ptr(pFileBothDirInfo->NextEntryOffset, pFileBothDirInfo);
 
			const unsigned char *ptrTemp;
			ptrTemp = ((const unsigned char*)pFileBothDirInfo + 10);
			//be equivalent to 
			//((const unsigned char*)pFileBothDirInfo) = ( (const unsigned char*)pFileBothDirInfo + 10 );
			OFFSET_PTR(pFileBothDirInfo->NextEntryOffset, pFileBothDirInfo);
			printf("ptrTemp = %p", ptrTemp);
		} 
		else
		{
			break;
		}
	}
	return 0;
}