Some NtQueryInformation classes.
This commit is contained in:
parent
956496fb99
commit
a41827942e
|
@ -91,7 +91,7 @@ Entry* DiscImageDevice::ResolvePath(const char* path) {
|
||||||
XEIGNORE(xestrcpya(remaining, XECOUNT(remaining), next_slash + 1));
|
XEIGNORE(xestrcpya(remaining, XECOUNT(remaining), next_slash + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
Entry::Type type = gdfx_entry->attributes & GDFXEntry::kAttrFolder ?
|
Entry::Type type = gdfx_entry->attributes & X_FILE_ATTRIBUTE_DIRECTORY ?
|
||||||
Entry::kTypeDirectory : Entry::kTypeFile;
|
Entry::kTypeDirectory : Entry::kTypeFile;
|
||||||
return new DiscImageEntry(
|
return new DiscImageEntry(
|
||||||
type, this, path, mmap_, gdfx_entry);
|
type, this, path, mmap_, gdfx_entry);
|
||||||
|
|
|
@ -29,6 +29,19 @@ DiscImageFile::DiscImageFile(
|
||||||
DiscImageFile::~DiscImageFile() {
|
DiscImageFile::~DiscImageFile() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
X_STATUS DiscImageFile::QueryInfo(FileInfo* out_info) {
|
||||||
|
XEASSERTNOTNULL(out_info);
|
||||||
|
GDFXEntry* gdfx_entry = entry_->gdfx_entry();
|
||||||
|
out_info->creation_time = 0;
|
||||||
|
out_info->last_access_time = 0;
|
||||||
|
out_info->last_write_time = 0;
|
||||||
|
out_info->change_time = 0;
|
||||||
|
out_info->allocation_size = 2048;
|
||||||
|
out_info->file_length = gdfx_entry->size;
|
||||||
|
out_info->attributes = gdfx_entry->attributes;
|
||||||
|
return X_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
X_STATUS DiscImageFile::ReadSync(
|
X_STATUS DiscImageFile::ReadSync(
|
||||||
void* buffer, size_t buffer_length, size_t byte_offset,
|
void* buffer, size_t buffer_length, size_t byte_offset,
|
||||||
size_t* out_bytes_read) {
|
size_t* out_bytes_read) {
|
||||||
|
|
|
@ -1,50 +1,51 @@
|
||||||
/**
|
/**
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef XENIA_KERNEL_MODULES_XBOXKRNL_FS_DEVICES_DISC_IMAGE_FILE_H_
|
#ifndef XENIA_KERNEL_MODULES_XBOXKRNL_FS_DEVICES_DISC_IMAGE_FILE_H_
|
||||||
#define XENIA_KERNEL_MODULES_XBOXKRNL_FS_DEVICES_DISC_IMAGE_FILE_H_
|
#define XENIA_KERNEL_MODULES_XBOXKRNL_FS_DEVICES_DISC_IMAGE_FILE_H_
|
||||||
|
|
||||||
#include <xenia/common.h>
|
#include <xenia/common.h>
|
||||||
#include <xenia/core.h>
|
#include <xenia/core.h>
|
||||||
|
|
||||||
#include <xenia/kernel/modules/xboxkrnl/objects/xfile.h>
|
#include <xenia/kernel/modules/xboxkrnl/objects/xfile.h>
|
||||||
|
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
namespace xboxkrnl {
|
namespace xboxkrnl {
|
||||||
namespace fs {
|
namespace fs {
|
||||||
|
|
||||||
class DiscImageEntry;
|
class DiscImageEntry;
|
||||||
|
|
||||||
|
|
||||||
class DiscImageFile : public XFile {
|
class DiscImageFile : public XFile {
|
||||||
public:
|
public:
|
||||||
DiscImageFile(KernelState* kernel_state, uint32_t desired_access,
|
DiscImageFile(KernelState* kernel_state, uint32_t desired_access,
|
||||||
DiscImageEntry* entry);
|
DiscImageEntry* entry);
|
||||||
virtual ~DiscImageFile();
|
virtual ~DiscImageFile();
|
||||||
|
|
||||||
|
virtual X_STATUS QueryInfo(FileInfo* out_info);
|
||||||
protected:
|
|
||||||
|
protected:
|
||||||
virtual X_STATUS ReadSync(
|
virtual X_STATUS ReadSync(
|
||||||
void* buffer, size_t buffer_length, size_t byte_offset,
|
void* buffer, size_t buffer_length, size_t byte_offset,
|
||||||
size_t* out_bytes_read);
|
size_t* out_bytes_read);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DiscImageEntry* entry_;
|
DiscImageEntry* entry_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
} // namespace fs
|
} // namespace fs
|
||||||
} // namespace xboxkrnl
|
} // namespace xboxkrnl
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
||||||
|
|
||||||
#endif // XENIA_KERNEL_MODULES_XBOXKRNL_FS_DEVICES_DISC_IMAGE_FILE_H_
|
#endif // XENIA_KERNEL_MODULES_XBOXKRNL_FS_DEVICES_DISC_IMAGE_FILE_H_
|
||||||
|
|
|
@ -29,6 +29,26 @@ HostPathFile::~HostPathFile() {
|
||||||
CloseHandle(file_handle_);
|
CloseHandle(file_handle_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
X_STATUS HostPathFile::QueryInfo(FileInfo* out_info) {
|
||||||
|
XEASSERTNOTNULL(out_info);
|
||||||
|
|
||||||
|
WIN32_FILE_ATTRIBUTE_DATA data;
|
||||||
|
if (!GetFileAttributesEx(
|
||||||
|
entry_->local_path(), GetFileExInfoStandard, &data)) {
|
||||||
|
return X_STATUS_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define COMBINE_TIME(t) (((uint64_t)t.dwHighDateTime << 32) | t.dwLowDateTime)
|
||||||
|
out_info->creation_time = COMBINE_TIME(data.ftCreationTime);
|
||||||
|
out_info->last_access_time = COMBINE_TIME(data.ftLastAccessTime);
|
||||||
|
out_info->last_write_time = COMBINE_TIME(data.ftLastWriteTime);
|
||||||
|
out_info->change_time = COMBINE_TIME(data.ftLastWriteTime);
|
||||||
|
out_info->allocation_size = 4096;
|
||||||
|
out_info->file_length = ((uint64_t)data.nFileSizeHigh << 32) | data.nFileSizeLow;
|
||||||
|
out_info->attributes = (X_FILE_ATTRIBUTES)data.dwFileAttributes;
|
||||||
|
return X_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
X_STATUS HostPathFile::ReadSync(
|
X_STATUS HostPathFile::ReadSync(
|
||||||
void* buffer, size_t buffer_length, size_t byte_offset,
|
void* buffer, size_t buffer_length, size_t byte_offset,
|
||||||
size_t* out_bytes_read) {
|
size_t* out_bytes_read) {
|
||||||
|
|
|
@ -30,6 +30,8 @@ public:
|
||||||
HostPathEntry* entry, HANDLE file_handle);
|
HostPathEntry* entry, HANDLE file_handle);
|
||||||
virtual ~HostPathFile();
|
virtual ~HostPathFile();
|
||||||
|
|
||||||
|
virtual X_STATUS QueryInfo(FileInfo* out_info);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual X_STATUS ReadSync(
|
virtual X_STATUS ReadSync(
|
||||||
void* buffer, size_t buffer_length, size_t byte_offset,
|
void* buffer, size_t buffer_length, size_t byte_offset,
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace {
|
||||||
|
|
||||||
|
|
||||||
GDFXEntry::GDFXEntry() :
|
GDFXEntry::GDFXEntry() :
|
||||||
attributes(0), offset(0), size(0) {
|
attributes(X_FILE_ATTRIBUTE_NONE), offset(0), size(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
GDFXEntry::~GDFXEntry() {
|
GDFXEntry::~GDFXEntry() {
|
||||||
|
@ -144,7 +144,7 @@ GDFX::Error GDFX::ReadAllEntries(ParseState& state,
|
||||||
root_entry_->offset = 0;
|
root_entry_->offset = 0;
|
||||||
root_entry_->size = 0;
|
root_entry_->size = 0;
|
||||||
root_entry_->name = "";
|
root_entry_->name = "";
|
||||||
root_entry_->attributes = GDFXEntry::kAttrFolder;
|
root_entry_->attributes = X_FILE_ATTRIBUTE_DIRECTORY;
|
||||||
|
|
||||||
if (!ReadEntry(state, root_buffer, 0, root_entry_)) {
|
if (!ReadEntry(state, root_buffer, 0, root_entry_)) {
|
||||||
return kErrorOutOfMemory;
|
return kErrorOutOfMemory;
|
||||||
|
@ -172,12 +172,12 @@ bool GDFX::ReadEntry(ParseState& state, const uint8_t* buffer,
|
||||||
GDFXEntry* entry = new GDFXEntry();
|
GDFXEntry* entry = new GDFXEntry();
|
||||||
entry->name = std::string(name, name_length);
|
entry->name = std::string(name, name_length);
|
||||||
entry->name.append(1, '\0');
|
entry->name.append(1, '\0');
|
||||||
entry->attributes = attributes;
|
entry->attributes = (X_FILE_ATTRIBUTES)attributes;
|
||||||
|
|
||||||
// Add to parent.
|
// Add to parent.
|
||||||
parent->children.push_back(entry);
|
parent->children.push_back(entry);
|
||||||
|
|
||||||
if (attributes & GDFXEntry::kAttrFolder) {
|
if (attributes & X_FILE_ATTRIBUTE_DIRECTORY) {
|
||||||
// Folder.
|
// Folder.
|
||||||
entry->offset = 0;
|
entry->offset = 0;
|
||||||
entry->size = 0;
|
entry->size = 0;
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <xenia/kernel/xbox.h>
|
||||||
#include <xenia/kernel/modules/xboxkrnl/fs/entry.h>
|
#include <xenia/kernel/modules/xboxkrnl/fs/entry.h>
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,16 +30,6 @@ class GDFX;
|
||||||
|
|
||||||
class GDFXEntry {
|
class GDFXEntry {
|
||||||
public:
|
public:
|
||||||
enum Attributes {
|
|
||||||
kAttrNone = 0x00000000,
|
|
||||||
kAttrReadOnly = 0x00000001,
|
|
||||||
kAttrHidden = 0x00000002,
|
|
||||||
kAttrSystem = 0x00000004,
|
|
||||||
kAttrFolder = 0x00000010,
|
|
||||||
kAttrArchived = 0x00000020,
|
|
||||||
kAttrNormal = 0x00000080,
|
|
||||||
};
|
|
||||||
|
|
||||||
GDFXEntry();
|
GDFXEntry();
|
||||||
~GDFXEntry();
|
~GDFXEntry();
|
||||||
|
|
||||||
|
@ -46,10 +37,10 @@ public:
|
||||||
|
|
||||||
void Dump(int indent);
|
void Dump(int indent);
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
uint32_t attributes;
|
X_FILE_ATTRIBUTES attributes;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
||||||
std::vector<GDFXEntry*> children;
|
std::vector<GDFXEntry*> children;
|
||||||
};
|
};
|
||||||
|
|
|
@ -38,6 +38,12 @@ X_STATUS XFile::Wait(uint32_t wait_reason, uint32_t processor_mode,
|
||||||
wait_reason, processor_mode, alertable, opt_timeout);
|
wait_reason, processor_mode, alertable, opt_timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
X_STATUS XFile::QueryInfo(FileInfo* out_info) {
|
||||||
|
XEASSERTNOTNULL(out_info);
|
||||||
|
xe_zero_struct(out_info, sizeof(FileInfo));
|
||||||
|
return X_STATUS_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
X_STATUS XFile::Read(void* buffer, size_t buffer_length, size_t byte_offset,
|
X_STATUS XFile::Read(void* buffer, size_t buffer_length, size_t byte_offset,
|
||||||
size_t* out_bytes_read) {
|
size_t* out_bytes_read) {
|
||||||
if (byte_offset == -1) {
|
if (byte_offset == -1) {
|
||||||
|
|
|
@ -28,9 +28,22 @@ public:
|
||||||
XFile(KernelState* kernel_state, uint32_t desired_access);
|
XFile(KernelState* kernel_state, uint32_t desired_access);
|
||||||
virtual ~XFile();
|
virtual ~XFile();
|
||||||
|
|
||||||
|
size_t position() const { return position_; }
|
||||||
|
|
||||||
virtual X_STATUS Wait(uint32_t wait_reason, uint32_t processor_mode,
|
virtual X_STATUS Wait(uint32_t wait_reason, uint32_t processor_mode,
|
||||||
uint32_t alertable, uint64_t* opt_timeout);
|
uint32_t alertable, uint64_t* opt_timeout);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64_t creation_time;
|
||||||
|
uint64_t last_access_time;
|
||||||
|
uint64_t last_write_time;
|
||||||
|
uint64_t change_time;
|
||||||
|
uint64_t allocation_size;
|
||||||
|
uint64_t file_length;
|
||||||
|
X_FILE_ATTRIBUTES attributes;
|
||||||
|
} FileInfo;
|
||||||
|
virtual X_STATUS QueryInfo(FileInfo* out_info);
|
||||||
|
|
||||||
X_STATUS Read(void* buffer, size_t buffer_length, size_t byte_offset,
|
X_STATUS Read(void* buffer, size_t buffer_length, size_t byte_offset,
|
||||||
size_t* out_bytes_read);
|
size_t* out_bytes_read);
|
||||||
X_STATUS Read(void* buffer, size_t buffer_length, size_t byte_offset,
|
X_STATUS Read(void* buffer, size_t buffer_length, size_t byte_offset,
|
||||||
|
|
|
@ -233,7 +233,79 @@ SHIM_CALL NtQueryInformationFile_shim(
|
||||||
length,
|
length,
|
||||||
file_info_class);
|
file_info_class);
|
||||||
|
|
||||||
SHIM_SET_RETURN(X_STATUS_NO_SUCH_FILE);
|
X_STATUS result = X_STATUS_SUCCESS;
|
||||||
|
uint32_t info = 0;
|
||||||
|
|
||||||
|
// Grab file.
|
||||||
|
XFile* file = NULL;
|
||||||
|
result = state->object_table()->GetObject(
|
||||||
|
file_handle, (XObject**)&file);
|
||||||
|
|
||||||
|
if (XSUCCEEDED(result)) {
|
||||||
|
result = X_STATUS_SUCCESS;
|
||||||
|
switch (file_info_class) {
|
||||||
|
case XFilePositionInformation:
|
||||||
|
// struct FILE_POSITION_INFORMATION {
|
||||||
|
// LARGE_INTEGER CurrentByteOffset;
|
||||||
|
// };
|
||||||
|
XEASSERT(length == 8);
|
||||||
|
info = 8;
|
||||||
|
SHIM_SET_MEM_64(file_info_ptr, file->position());
|
||||||
|
break;
|
||||||
|
case XFileNetworkOpenInformation:
|
||||||
|
// struct FILE_NETWORK_OPEN_INFORMATION {
|
||||||
|
// LARGE_INTEGER CreationTime;
|
||||||
|
// LARGE_INTEGER LastAccessTime;
|
||||||
|
// LARGE_INTEGER LastWriteTime;
|
||||||
|
// LARGE_INTEGER ChangeTime;
|
||||||
|
// LARGE_INTEGER AllocationSize;
|
||||||
|
// LARGE_INTEGER EndOfFile;
|
||||||
|
// ULONG FileAttributes;
|
||||||
|
// ULONG Unknown;
|
||||||
|
// };
|
||||||
|
XEASSERT(length == 56);
|
||||||
|
XFile::FileInfo file_info;
|
||||||
|
result = file->QueryInfo(&file_info);
|
||||||
|
if (XSUCCEEDED(result)) {
|
||||||
|
info = 56;
|
||||||
|
SHIM_SET_MEM_64(file_info_ptr,
|
||||||
|
file_info.creation_time);
|
||||||
|
SHIM_SET_MEM_64(file_info_ptr + 8,
|
||||||
|
file_info.last_access_time);
|
||||||
|
SHIM_SET_MEM_64(file_info_ptr + 16,
|
||||||
|
file_info.last_write_time);
|
||||||
|
SHIM_SET_MEM_64(file_info_ptr + 24,
|
||||||
|
file_info.change_time);
|
||||||
|
SHIM_SET_MEM_64(file_info_ptr + 32,
|
||||||
|
file_info.allocation_size);
|
||||||
|
SHIM_SET_MEM_64(file_info_ptr + 40,
|
||||||
|
file_info.file_length);
|
||||||
|
SHIM_SET_MEM_32(file_info_ptr + 48,
|
||||||
|
file_info.attributes);
|
||||||
|
SHIM_SET_MEM_32(file_info_ptr + 52, 0); // Unknown!
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Unsupported, for now.
|
||||||
|
XEASSERTALWAYS();
|
||||||
|
info = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (XFAILED(result)) {
|
||||||
|
info = 0;
|
||||||
|
}
|
||||||
|
if (io_status_block_ptr) {
|
||||||
|
SHIM_SET_MEM_32(io_status_block_ptr, result); // Status
|
||||||
|
SHIM_SET_MEM_32(io_status_block_ptr + 4, info); // Information
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file) {
|
||||||
|
file->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
SHIM_SET_RETURN(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
SHIM_CALL NtQueryFullAttributesFile_shim(
|
SHIM_CALL NtQueryFullAttributesFile_shim(
|
||||||
|
|
|
@ -107,6 +107,82 @@ typedef uint32_t X_STATUS;
|
||||||
#define X_LANGUAGE_JAPANESE 2
|
#define X_LANGUAGE_JAPANESE 2
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum _X_FILE_ATTRIBUTES {
|
||||||
|
X_FILE_ATTRIBUTE_NONE = 0x0000,
|
||||||
|
X_FILE_ATTRIBUTE_READONLY = 0x0001,
|
||||||
|
X_FILE_ATTRIBUTE_HIDDEN = 0x0002,
|
||||||
|
X_FILE_ATTRIBUTE_SYSTEM = 0x0004,
|
||||||
|
X_FILE_ATTRIBUTE_DIRECTORY = 0x0010,
|
||||||
|
X_FILE_ATTRIBUTE_ARCHIVE = 0x0020,
|
||||||
|
X_FILE_ATTRIBUTE_DEVICE = 0x0040,
|
||||||
|
X_FILE_ATTRIBUTE_NORMAL = 0x0080,
|
||||||
|
X_FILE_ATTRIBUTE_TEMPORARY = 0x0100,
|
||||||
|
X_FILE_ATTRIBUTE_COMPRESSED = 0x0800,
|
||||||
|
X_FILE_ATTRIBUTE_ENCRYPTED = 0x4000,
|
||||||
|
} X_FILE_ATTRIBUTES;
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum _X_FILE_INFORMATION_CLASS {
|
||||||
|
XFileDirectoryInformation = 1,
|
||||||
|
XFileFullDirectoryInformation,
|
||||||
|
XFileBothDirectoryInformation,
|
||||||
|
XFileBasicInformation,
|
||||||
|
XFileStandardInformation,
|
||||||
|
XFileInternalInformation,
|
||||||
|
XFileEaInformation,
|
||||||
|
XFileAccessInformation,
|
||||||
|
XFileNameInformation,
|
||||||
|
XFileRenameInformation,
|
||||||
|
XFileLinkInformation,
|
||||||
|
XFileNamesInformation,
|
||||||
|
XFileDispositionInformation,
|
||||||
|
XFilePositionInformation,
|
||||||
|
XFileFullEaInformation,
|
||||||
|
XFileModeInformation,
|
||||||
|
XFileAlignmentInformation,
|
||||||
|
XFileAllInformation,
|
||||||
|
XFileAllocationInformation,
|
||||||
|
XFileEndOfFileInformation,
|
||||||
|
XFileAlternateNameInformation,
|
||||||
|
XFileStreamInformation,
|
||||||
|
XFilePipeInformation,
|
||||||
|
XFilePipeLocalInformation,
|
||||||
|
XFilePipeRemoteInformation,
|
||||||
|
XFileMailslotQueryInformation,
|
||||||
|
XFileMailslotSetInformation,
|
||||||
|
XFileCompressionInformation,
|
||||||
|
XFileObjectIdInformation,
|
||||||
|
XFileCompletionInformation,
|
||||||
|
XFileMoveClusterInformation,
|
||||||
|
XFileQuotaInformation,
|
||||||
|
XFileReparsePointInformation,
|
||||||
|
XFileNetworkOpenInformation,
|
||||||
|
XFileAttributeTagInformation,
|
||||||
|
XFileTrackingInformation,
|
||||||
|
XFileIdBothDirectoryInformation,
|
||||||
|
XFileIdFullDirectoryInformation,
|
||||||
|
XFileValidDataLengthInformation,
|
||||||
|
XFileShortNameInformation,
|
||||||
|
XFileIoCompletionNotificationInformation,
|
||||||
|
XFileIoStatusBlockRangeInformation,
|
||||||
|
XFileIoPriorityHintInformation,
|
||||||
|
XFileSfioReserveInformation,
|
||||||
|
XFileSfioVolumeInformation,
|
||||||
|
XFileHardLinkInformation,
|
||||||
|
XFileProcessIdsUsingFileInformation,
|
||||||
|
XFileNormalizedNameInformation,
|
||||||
|
XFileNetworkPhysicalNameInformation,
|
||||||
|
XFileIdGlobalTxDirectoryInformation,
|
||||||
|
XFileIsRemoteDeviceInformation,
|
||||||
|
XFileAttributeCacheInformation,
|
||||||
|
XFileNumaNodeInformation,
|
||||||
|
XFileStandardLinkInformation,
|
||||||
|
XFileRemoteProtocolInformation,
|
||||||
|
XFileReplaceCompletionInformation,
|
||||||
|
XFileMaximumInformation
|
||||||
|
} X_FILE_INFORMATION_CLASS;
|
||||||
|
|
||||||
|
|
||||||
class X_ANSI_STRING {
|
class X_ANSI_STRING {
|
||||||
public:
|
public:
|
||||||
uint16_t length;
|
uint16_t length;
|
||||||
|
|
Loading…
Reference in New Issue