147 lines
4.7 KiB
C++
147 lines
4.7 KiB
C++
#pragma once
|
|
|
|
#include "common/base/logging/logger.h"
|
|
|
|
#include "google/protobuf/io/zero_copy_stream_impl.h"
|
|
#include "google/protobuf/text_format.h"
|
|
|
|
#include <cerrno>
|
|
#include <cstring>
|
|
#include <fcntl.h>
|
|
#include <fstream>
|
|
#include <string>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
class ProtoMessageIo
|
|
{
|
|
public:
|
|
// -------------------- Binary (protobuf wire format) --------------------
|
|
static bool setProtoToBinaryFile(const google::protobuf::Message& message,
|
|
const std::string& fileName)
|
|
{
|
|
std::ofstream output(fileName, std::ios::out | std::ios::trunc | std::ios::binary);
|
|
if (!output.good())
|
|
{
|
|
CMVR_LOG(WARNING) << "Failed to open file for binary write: " << fileName;
|
|
return false;
|
|
}
|
|
|
|
if (!message.SerializePartialToOstream(&output))
|
|
{
|
|
CMVR_LOG(WARNING) << "Failed to serialize proto to binary file: " << fileName;
|
|
return false;
|
|
}
|
|
|
|
CMVR_LOG(INFO) << "Successfully wrote binary proto file: " << fileName;
|
|
return true;
|
|
}
|
|
|
|
static bool getProtoFromBinaryFile(const std::string& fileName,
|
|
google::protobuf::Message* message)
|
|
{
|
|
if (message == nullptr)
|
|
{
|
|
CMVR_LOG(ERROR) << "Null message pointer when reading binary proto file: " << fileName;
|
|
return false;
|
|
}
|
|
|
|
std::ifstream input(fileName, std::ios::in | std::ios::binary);
|
|
if (!input.good())
|
|
{
|
|
CMVR_LOG(WARNING) << "Failed to open file for binary read: " << fileName;
|
|
return false;
|
|
}
|
|
|
|
if (!message->ParseFromIstream(&input))
|
|
{
|
|
CMVR_LOG(WARNING) << "Failed to parse binary proto file: " << fileName;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// -------------------- ASCII (TextFormat) --------------------
|
|
static bool setProtoToAsciiFile(const google::protobuf::Message& message,
|
|
const std::string& fileName)
|
|
{
|
|
// 0600: owner read/write
|
|
const int fd = ::open(fileName.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
|
|
if (fd < 0)
|
|
{
|
|
CMVR_LOG(WARNING) << "Failed to open file for ASCII write: " << fileName
|
|
<< ": " << std::strerror(errno);
|
|
return false;
|
|
}
|
|
|
|
const bool ok = setProtoToAsciiFile(message, fd);
|
|
if (ok)
|
|
CMVR_LOG(INFO) << "Successfully wrote ASCII proto file: " << fileName;
|
|
else
|
|
CMVR_LOG(WARNING) << "Failed to write ASCII proto file: " << fileName;
|
|
|
|
return ok;
|
|
}
|
|
|
|
static bool setProtoToAsciiFile(const google::protobuf::Message& message,
|
|
int fileDescriptor)
|
|
{
|
|
using google::protobuf::TextFormat;
|
|
using google::protobuf::io::FileOutputStream;
|
|
|
|
if (fileDescriptor < 0)
|
|
{
|
|
CMVR_LOG(WARNING) << "Invalid file descriptor for ASCII write.";
|
|
return false;
|
|
}
|
|
|
|
google::protobuf::io::FileOutputStream output(fileDescriptor);
|
|
output.SetCloseOnDelete(true); // avoid fd leak; also avoid double-close elsewhere
|
|
|
|
bool ok = TextFormat::Print(message, &output);
|
|
ok = ok && output.Flush();
|
|
return ok;
|
|
}
|
|
|
|
static bool getProtoFromAsciiFile(const std::string& fileName,
|
|
google::protobuf::Message* message,
|
|
bool isOptional = false)
|
|
{
|
|
using google::protobuf::TextFormat;
|
|
using google::protobuf::io::FileInputStream;
|
|
|
|
if (message == nullptr)
|
|
{
|
|
CMVR_LOG(ERROR) << "Null message pointer when reading ASCII proto file: " << fileName;
|
|
return false;
|
|
}
|
|
|
|
const int fd = ::open(fileName.c_str(), O_RDONLY);
|
|
if (fd < 0)
|
|
{
|
|
if (isOptional) {
|
|
CMVR_LOG(INFO) << "Optional ASCII proto file not found/openable: " << fileName
|
|
<< ": " << std::strerror(errno);
|
|
} else {
|
|
CMVR_LOG(ERROR) << "Failed to open ASCII proto file: " << fileName
|
|
<< ": " << std::strerror(errno);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
FileInputStream input(fd);
|
|
input.SetCloseOnDelete(true);
|
|
|
|
const bool ok = TextFormat::Parse(&input, message);
|
|
if (!ok)
|
|
{
|
|
if (isOptional)
|
|
CMVR_LOG(INFO) << "Failed to parse optional ASCII proto file: " << fileName;
|
|
else
|
|
CMVR_LOG(ERROR) << "Failed to parse ASCII proto file: " << fileName;
|
|
}
|
|
return ok;
|
|
}
|
|
};
|