Chromium Code Reviews| Index: tools/ipc_fuzzer/message_lib/message_file_writer.cc |
| diff --git a/tools/ipc_fuzzer/message_lib/message_file_writer.cc b/tools/ipc_fuzzer/message_lib/message_file_writer.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..0cf3bdc66f62b19449c4786727f612dcebb6d185 |
| --- /dev/null |
| +++ b/tools/ipc_fuzzer/message_lib/message_file_writer.cc |
| @@ -0,0 +1,174 @@ |
| +// Copyright 2013 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include <limits.h> |
| +#include <set> |
| + |
| +#include "base/logging.h" |
| +#include "base/platform_file.h" |
| +#include "tools/ipc_fuzzer/message_lib/message_file.h" |
| +#include "tools/ipc_fuzzer/message_lib/message_file_format.h" |
| +#include "tools/ipc_fuzzer/message_lib/message_names.h" |
| + |
| +namespace ipc_fuzzer { |
| + |
| +namespace { |
| + |
| +// Helper class to write a MessageVector + message names to a file. |
| +class Writer { |
| + public: |
| + Writer(const base::FilePath& path); |
| + ~Writer(); |
| + bool Write(const MessageVector& messages); |
| + |
| + private: |
| + bool OpenFile(); |
| + |
| + // Helper to append data to file_. |
| + bool WriteBlob(const void *buffer, size_t size); |
| + |
| + // Collects a set of MessageVector message types. Corresponding message |
| + // names need to be included in the file. |
| + bool CollectMessageTypes(); |
| + |
| + bool WriteHeader(); |
| + bool WriteMessages(); |
| + |
| + // Each name table entry is a message type + string table offset. |
| + bool WriteNameTable(); |
| + |
| + // String table contains the actual message names. |
| + bool WriteStringTable(); |
| + |
| + typedef std::set<uint32> TypesSet; |
| + base::FilePath path_; |
| + base::PlatformFile file_; |
| + const MessageVector* messages_; |
| + TypesSet types_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(Writer); |
| +}; |
| + |
| +Writer::Writer(const base::FilePath& path) |
| + : path_(path), |
| + file_(base::kInvalidPlatformFileValue), |
| + messages_(NULL) { |
| +} |
| + |
| +Writer::~Writer() { |
| + if (file_ != base::kInvalidPlatformFileValue) |
| + base::ClosePlatformFile(file_); |
| +} |
| + |
| +bool Writer::OpenFile() { |
| + file_ = base::CreatePlatformFile( |
| + path_, |
| + base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_WRITE, |
| + NULL, |
| + NULL); |
| + if (file_ == base::kInvalidPlatformFileValue) { |
| + LOG(ERROR) << "Failed to create IPC message file: " << path_.value(); |
| + return false; |
| + } |
| + return true; |
| +} |
| + |
| +bool Writer::WriteBlob(const void *buffer, size_t size) { |
| + if (size > INT_MAX) |
| + return false; |
| + const char* char_buffer = static_cast<const char*>(buffer); |
| + int ret = base::WritePlatformFileAtCurrentPos(file_, char_buffer, size); |
| + if (ret != size) { |
| + LOG(ERROR) << "Failed to write " << size << " bytes."; |
| + return false; |
| + } |
| + return true; |
| +} |
| + |
| +bool Writer::CollectMessageTypes() { |
| + for (size_t i = 0; i < messages_->size(); ++i) { |
| + uint32_t type = (*messages_)[i]->type(); |
| + if (!MessageNames::Get().TypeExists(type)) { |
| + LOG(ERROR) << "Unknown message type: " << type; |
| + return false; |
|
Tom Sepez
2013/12/06 18:57:16
Symptomatic of a missing message file in all_messa
aedla
2013/12/09 18:08:32
I actually do this check in the logging code. On f
|
| + } |
| + types_.insert(type); |
| + } |
| + return true; |
| +} |
| + |
| +bool Writer::WriteHeader() { |
| + FileHeader header; |
| + if (messages_->size() > UINT_MAX) |
| + return false; |
| + header.message_count = messages_->size(); |
| + header.name_count = types_.size(); |
| + if (!WriteBlob(&header, sizeof(FileHeader))) |
| + return false; |
| + return true; |
| +} |
| + |
| +bool Writer::WriteMessages() { |
| + for (size_t i = 0; i < messages_->size(); ++i) { |
| + IPC::Message* message = (*messages_)[i]; |
| + if (!WriteBlob(message->data(), message->size())) |
| + return false; |
| + } |
| + return true; |
| +} |
| + |
| +bool Writer::WriteNameTable() { |
| + size_t string_table_offset = 0; |
| + NameTableEntry entry; |
| + |
| + for (TypesSet::iterator it = types_.begin(); it != types_.end(); ++it) { |
| + if (string_table_offset > UINT_MAX) |
| + return false; |
| + entry.type = *it; |
| + entry.string_table_offset = string_table_offset; |
| + if (!WriteBlob(&entry, sizeof(NameTableEntry))) |
| + return false; |
| + const std::string& name = MessageNames::Get().TypeToName(*it); |
| + string_table_offset += name.length() + 1; |
| + } |
| + return true; |
| +} |
| + |
| +bool Writer::WriteStringTable() { |
| + for (TypesSet::iterator it = types_.begin(); it != types_.end(); ++it) { |
| + const std::string& name = MessageNames::Get().TypeToName(*it); |
| + if (!WriteBlob(name.c_str(), name.length() + 1)) |
| + return false; |
| + } |
| + return true; |
| +} |
| + |
| +bool Writer::Write(const MessageVector& messages) { |
| + messages_ = &messages; |
| + |
| + if (!OpenFile()) |
| + return false; |
| + if (!CollectMessageTypes()) |
| + return false; |
| + if (!WriteHeader()) |
| + return false; |
| + if (!WriteMessages()) |
| + return false; |
| + if (!WriteNameTable()) |
| + return false; |
| + if (!WriteStringTable()) |
| + return false; |
| + |
| + return true; |
| +} |
| + |
| +} // namespace |
| + |
| +bool MessageFile::Write(const base::FilePath& path, |
| + const MessageVector& messages) { |
| + Writer writer(path); |
| + return writer.Write(messages); |
| +} |
| + |
| +} // namespace ipc_fuzzer |