/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#pragma once
#include
#include
#include
namespace haze {
class PtpDataParser final {
private:
AsyncUsbServer *m_server;
u32 m_received_size;
u32 m_offset;
u8 *m_data;
bool m_eot;
private:
Result Flush() {
R_UNLESS(!m_eot, haze::ResultEndOfTransmission());
m_received_size = 0;
m_offset = 0;
ON_SCOPE_EXIT {
/* End of transmission occurs when receiving a bulk transfer less than the buffer size. */
/* PTP uses zero-length termination, so zero is a possible size to receive. */
m_eot = m_received_size < haze::UsbBulkPacketBufferSize;
};
R_RETURN(m_server->ReadPacket(m_data, haze::UsbBulkPacketBufferSize, std::addressof(m_received_size)));
}
public:
constexpr explicit PtpDataParser(void *data, AsyncUsbServer *server) : m_server(server), m_received_size(), m_offset(), m_data(static_cast(data)), m_eot() { /* ... */ }
Result Finalize() {
/* Read until the transmission completes. */
while (true) {
Result rc = this->Flush();
R_SUCCEED_IF(m_eot || haze::ResultEndOfTransmission::Includes(rc));
R_TRY(rc);
}
}
Result ReadBuffer(u8 *buffer, u32 count, u32 *out_read_count) {
*out_read_count = 0;
while (count > 0) {
/* If we cannot read more bytes now, flush. */
if (m_offset == m_received_size) {
R_TRY(this->Flush());
}
/* Calculate how many bytes we can read now. */
u32 read_size = std::min(count, m_received_size - m_offset);
/* Read this number of bytes. */
std::memcpy(buffer + *out_read_count, m_data + m_offset, read_size);
*out_read_count += read_size;
m_offset += read_size;
count -= read_size;
}
R_SUCCEED();
}
template
Result Read(T *out_t) {
u32 read_count;
u8 bytes[sizeof(T)];
R_TRY(this->ReadBuffer(bytes, sizeof(T), std::addressof(read_count)));
std::memcpy(out_t, bytes, sizeof(T));
R_SUCCEED();
}
/* NOTE: out_string must contain room for 256 bytes. */
/* The result will be null-terminated on successful completion. */
Result ReadString(char *out_string) {
u8 len;
R_TRY(this->Read(std::addressof(len)));
/* Read characters one by one. */
for (size_t i = 0; i < len; i++) {
u16 chr;
R_TRY(this->Read(std::addressof(chr)));
*out_string++ = static_cast(chr);
}
/* Write null terminator. */
*out_string++ = '\x00';
R_SUCCEED();
}
};
}