From 466472796c61a7d0e9b2d21438cfa7b003d01b0e Mon Sep 17 00:00:00 2001 From: Niels Moller Date: Fri, 18 Jan 2019 12:04:43 +0000 Subject: [PATCH] Revert "Trim down FileWrapper class to be merely a wrapper owning a FILE*" This reverts commit 80b95de7651caa0cfeb684ffc200860989f667dc. Reason for revert: Speculative revert for downstream breakage. Possibly FileAudioDevice broken? Original change's description: > Trim down FileWrapper class to be merely a wrapper owning a FILE* > > Bug: webrtc:6463 > Change-Id: If71e2f3a75dc1863bc805ab71de1e2d33294f805 > Reviewed-on: https://webrtc-review.googlesource.com/c/117881 > Reviewed-by: Karl Wiberg > Reviewed-by: Alex Loiko > Commit-Queue: Niels Moller > Cr-Commit-Position: refs/heads/master@{#26311} TBR=aleloi@webrtc.org,kwiberg@webrtc.org,nisse@webrtc.org,tommi@webrtc.org Change-Id: I46d37afbf9acb5f62f04e09d944114c1da96eb36 No-Presubmit: true No-Tree-Checks: true No-Try: true Bug: webrtc:6463 Reviewed-on: https://webrtc-review.googlesource.com/c/118380 Reviewed-by: Niels Moller Commit-Queue: Niels Moller Cr-Commit-Position: refs/heads/master@{#26318} --- .../debug_dump_writer.cc | 15 +- .../audio_device/dummy/file_audio_device.cc | 44 ++-- .../audio_device/dummy/file_audio_device.h | 4 +- .../aec_dump/aec_dump_impl.cc | 24 ++- .../audio_processing/aec_dump/aec_dump_impl.h | 4 +- .../aec_dump/write_to_file_task.cc | 8 +- .../aec_dump/write_to_file_task.h | 4 +- .../transient/click_annotate.cc | 20 +- .../transient/file_utils_unittest.cc | 188 ++++++++++-------- .../transient/transient_detector_unittest.cc | 24 ++- .../transient/wpd_tree_unittest.cc | 39 ++-- rtc_base/system/file_wrapper.cc | 109 ++++++++-- rtc_base/system/file_wrapper.h | 93 +++++---- 13 files changed, 346 insertions(+), 230 deletions(-) diff --git a/modules/audio_coding/audio_network_adaptor/debug_dump_writer.cc b/modules/audio_coding/audio_network_adaptor/debug_dump_writer.cc index 956d790685..8e04e8eafc 100644 --- a/modules/audio_coding/audio_network_adaptor/debug_dump_writer.cc +++ b/modules/audio_coding/audio_network_adaptor/debug_dump_writer.cc @@ -67,13 +67,14 @@ class DebugDumpWriterImpl final : public DebugDumpWriter { #endif private: - FileWrapper dump_file_; + std::unique_ptr dump_file_; }; -DebugDumpWriterImpl::DebugDumpWriterImpl(FILE* file_handle) { +DebugDumpWriterImpl::DebugDumpWriterImpl(FILE* file_handle) + : dump_file_(FileWrapper::Create()) { #if WEBRTC_ENABLE_PROTOBUF - dump_file_ = FileWrapper(file_handle); - RTC_CHECK(dump_file_.is_open()); + dump_file_->OpenFromFileHandle(file_handle); + RTC_CHECK(dump_file_->is_open()); #else RTC_NOTREACHED(); #endif @@ -109,7 +110,7 @@ void DebugDumpWriterImpl::DumpNetworkMetrics( *metrics.uplink_recoverable_packet_loss_fraction); } - DumpEventToFile(event, &dump_file_); + DumpEventToFile(event, dump_file_.get()); #endif // WEBRTC_ENABLE_PROTOBUF } @@ -142,7 +143,7 @@ void DebugDumpWriterImpl::DumpEncoderRuntimeConfig( if (config.num_channels) dump_config->set_num_channels(*config.num_channels); - DumpEventToFile(event, &dump_file_); + DumpEventToFile(event, dump_file_.get()); #endif // WEBRTC_ENABLE_PROTOBUF } @@ -156,7 +157,7 @@ void DebugDumpWriterImpl::DumpControllerManagerConfig( event.set_type(Event::CONTROLLER_MANAGER_CONFIG); event.mutable_controller_manager_config()->CopyFrom( controller_manager_config); - DumpEventToFile(event, &dump_file_); + DumpEventToFile(event, dump_file_.get()); } #endif // WEBRTC_ENABLE_PROTOBUF diff --git a/modules/audio_device/dummy/file_audio_device.cc b/modules/audio_device/dummy/file_audio_device.cc index cb3fa2792c..ea736e0bab 100644 --- a/modules/audio_device/dummy/file_audio_device.cc +++ b/modules/audio_device/dummy/file_audio_device.cc @@ -43,10 +43,15 @@ FileAudioDevice::FileAudioDevice(const char* inputFilename, _recording(false), _lastCallPlayoutMillis(0), _lastCallRecordMillis(0), + _outputFile(*FileWrapper::Create()), + _inputFile(*FileWrapper::Create()), _outputFilename(outputFilename), _inputFilename(inputFilename) {} -FileAudioDevice::~FileAudioDevice() {} +FileAudioDevice::~FileAudioDevice() { + delete &_outputFile; + delete &_inputFile; +} int32_t FileAudioDevice::ActiveAudioLayer( AudioDeviceModule::AudioLayer& audioLayer) const { @@ -205,15 +210,13 @@ int32_t FileAudioDevice::StartPlayout() { } // PLAYOUT - if (!_outputFilename.empty()) { - _outputFile = FileWrapper::OpenWriteOnly(_outputFilename.c_str()); - if (!_outputFile.is_open()) { - RTC_LOG(LS_ERROR) << "Failed to open playout file: " << _outputFilename; - _playing = false; - delete[] _playoutBuffer; - _playoutBuffer = NULL; - return -1; - } + if (!_outputFilename.empty() && + !_outputFile.OpenFile(_outputFilename.c_str(), false)) { + RTC_LOG(LS_ERROR) << "Failed to open playout file: " << _outputFilename; + _playing = false; + delete[] _playoutBuffer; + _playoutBuffer = NULL; + return -1; } _ptrThreadPlay.reset(new rtc::PlatformThread( @@ -243,7 +246,7 @@ int32_t FileAudioDevice::StopPlayout() { _playoutFramesLeft = 0; delete[] _playoutBuffer; _playoutBuffer = NULL; - _outputFile.Close(); + _outputFile.CloseFile(); RTC_LOG(LS_INFO) << "Stopped playout capture to output file: " << _outputFilename; @@ -264,16 +267,13 @@ int32_t FileAudioDevice::StartRecording() { _recordingBuffer = new int8_t[_recordingBufferSizeIn10MS]; } - if (!_inputFilename.empty()) { - _inputFile = FileWrapper::OpenReadOnly(_inputFilename.c_str()); - if (_inputFile.is_open()) { - RTC_LOG(LS_ERROR) << "Failed to open audio input file: " - << _inputFilename; - _recording = false; - delete[] _recordingBuffer; - _recordingBuffer = NULL; - return -1; - } + if (!_inputFilename.empty() && + !_inputFile.OpenFile(_inputFilename.c_str(), true)) { + RTC_LOG(LS_ERROR) << "Failed to open audio input file: " << _inputFilename; + _recording = false; + delete[] _recordingBuffer; + _recordingBuffer = NULL; + return -1; } _ptrThreadRec.reset(new rtc::PlatformThread( @@ -304,7 +304,7 @@ int32_t FileAudioDevice::StopRecording() { delete[] _recordingBuffer; _recordingBuffer = NULL; } - _inputFile.Close(); + _inputFile.CloseFile(); RTC_LOG(LS_INFO) << "Stopped recording from input file: " << _inputFilename; return 0; diff --git a/modules/audio_device/dummy/file_audio_device.h b/modules/audio_device/dummy/file_audio_device.h index 85dce077ef..375c6f6a73 100644 --- a/modules/audio_device/dummy/file_audio_device.h +++ b/modules/audio_device/dummy/file_audio_device.h @@ -154,8 +154,8 @@ class FileAudioDevice : public AudioDeviceGeneric { int64_t _lastCallPlayoutMillis; int64_t _lastCallRecordMillis; - FileWrapper _outputFile; - FileWrapper _inputFile; + FileWrapper& _outputFile; + FileWrapper& _inputFile; std::string _outputFilename; std::string _inputFilename; }; diff --git a/modules/audio_processing/aec_dump/aec_dump_impl.cc b/modules/audio_processing/aec_dump/aec_dump_impl.cc index 588d24dd5d..9020f2b9dc 100644 --- a/modules/audio_processing/aec_dump/aec_dump_impl.cc +++ b/modules/audio_processing/aec_dump/aec_dump_impl.cc @@ -55,7 +55,7 @@ void CopyFromConfigToEvent(const webrtc::InternalAPMConfig& config, } // namespace -AecDumpImpl::AecDumpImpl(FileWrapper debug_file, +AecDumpImpl::AecDumpImpl(std::unique_ptr debug_file, int64_t max_log_size_bytes, rtc::TaskQueue* worker_queue) : debug_file_(std::move(debug_file)), @@ -196,7 +196,7 @@ void AecDumpImpl::WriteRuntimeSetting( } std::unique_ptr AecDumpImpl::CreateWriteToFileTask() { - return absl::make_unique(&debug_file_, + return absl::make_unique(debug_file_.get(), &num_bytes_left_for_log_); } @@ -204,20 +204,24 @@ std::unique_ptr AecDumpFactory::Create(rtc::PlatformFile file, int64_t max_log_size_bytes, rtc::TaskQueue* worker_queue) { RTC_DCHECK(worker_queue); + std::unique_ptr debug_file(FileWrapper::Create()); FILE* handle = rtc::FdopenPlatformFileForWriting(file); if (!handle) { return nullptr; } - return absl::make_unique(FileWrapper(handle), max_log_size_bytes, - worker_queue); + if (!debug_file->OpenFromFileHandle(handle)) { + return nullptr; + } + return absl::make_unique(std::move(debug_file), + max_log_size_bytes, worker_queue); } std::unique_ptr AecDumpFactory::Create(std::string file_name, int64_t max_log_size_bytes, rtc::TaskQueue* worker_queue) { RTC_DCHECK(worker_queue); - FileWrapper debug_file = FileWrapper::OpenWriteOnly(file_name.c_str()); - if (!debug_file.is_open()) { + std::unique_ptr debug_file(FileWrapper::Create()); + if (!debug_file->OpenFile(file_name.c_str(), false)) { return nullptr; } return absl::make_unique(std::move(debug_file), @@ -229,7 +233,11 @@ std::unique_ptr AecDumpFactory::Create(FILE* handle, rtc::TaskQueue* worker_queue) { RTC_DCHECK(worker_queue); RTC_DCHECK(handle); - return absl::make_unique(FileWrapper(handle), max_log_size_bytes, - worker_queue); + std::unique_ptr debug_file(FileWrapper::Create()); + if (!debug_file->OpenFromFileHandle(handle)) { + return nullptr; + } + return absl::make_unique(std::move(debug_file), + max_log_size_bytes, worker_queue); } } // namespace webrtc diff --git a/modules/audio_processing/aec_dump/aec_dump_impl.h b/modules/audio_processing/aec_dump/aec_dump_impl.h index c247c1b63a..df949ca7bd 100644 --- a/modules/audio_processing/aec_dump/aec_dump_impl.h +++ b/modules/audio_processing/aec_dump/aec_dump_impl.h @@ -46,7 +46,7 @@ namespace webrtc { class AecDumpImpl : public AecDump { public: // Does member variables initialization shared across all c-tors. - AecDumpImpl(FileWrapper debug_file, + AecDumpImpl(std::unique_ptr debug_file, int64_t max_log_size_bytes, rtc::TaskQueue* worker_queue); @@ -73,7 +73,7 @@ class AecDumpImpl : public AecDump { private: std::unique_ptr CreateWriteToFileTask(); - FileWrapper debug_file_; + std::unique_ptr debug_file_; int64_t num_bytes_left_for_log_ = 0; rtc::RaceChecker race_checker_; rtc::TaskQueue* worker_queue_; diff --git a/modules/audio_processing/aec_dump/write_to_file_task.cc b/modules/audio_processing/aec_dump/write_to_file_task.cc index d11f10b23a..8dddd47992 100644 --- a/modules/audio_processing/aec_dump/write_to_file_task.cc +++ b/modules/audio_processing/aec_dump/write_to_file_task.cc @@ -39,15 +39,17 @@ void WriteToFileTask::UpdateBytesLeft(size_t event_byte_size) { } bool WriteToFileTask::Run() { + if (!debug_file_->is_open()) { + return true; + } + ProtoString event_string; event_.SerializeToString(&event_string); const size_t event_byte_size = event_.ByteSizeLong(); if (!IsRoomForNextEvent(event_byte_size)) { - // Ensure that no further events are written, even if they're smaller than - // the current event. - *num_bytes_left_for_log_ = 0; + debug_file_->CloseFile(); return true; } diff --git a/modules/audio_processing/aec_dump/write_to_file_task.h b/modules/audio_processing/aec_dump/write_to_file_task.h index 4b04a45b20..711afb218a 100644 --- a/modules/audio_processing/aec_dump/write_to_file_task.h +++ b/modules/audio_processing/aec_dump/write_to_file_task.h @@ -48,9 +48,9 @@ class WriteToFileTask : public rtc::QueuedTask { bool Run() override; - webrtc::FileWrapper* const debug_file_; + webrtc::FileWrapper* debug_file_; audioproc::Event event_; - int64_t* const num_bytes_left_for_log_; + int64_t* num_bytes_left_for_log_; }; } // namespace webrtc diff --git a/modules/audio_processing/transient/click_annotate.cc b/modules/audio_processing/transient/click_annotate.cc index 21641f85cc..ce646b51be 100644 --- a/modules/audio_processing/transient/click_annotate.cc +++ b/modules/audio_processing/transient/click_annotate.cc @@ -39,14 +39,16 @@ int main(int argc, char* argv[]) { return 0; } - FileWrapper pcm_file = FileWrapper::OpenReadOnly(argv[1]); - if (!pcm_file.is_open()) { + std::unique_ptr pcm_file(FileWrapper::Create()); + pcm_file->OpenFile(argv[1], true); + if (!pcm_file->is_open()) { printf("\nThe %s could not be opened.\n\n", argv[1]); return -1; } - FileWrapper dat_file = FileWrapper::OpenWriteOnly(argv[2]); - if (!dat_file.is_open()) { + std::unique_ptr dat_file(FileWrapper::Create()); + dat_file->OpenFile(argv[2], false); + if (!dat_file->is_open()) { printf("\nThe %s could not be opened.\n\n", argv[2]); return -1; } @@ -71,7 +73,7 @@ int main(int argc, char* argv[]) { // Read first buffer from the PCM test file. size_t file_samples_read = ReadInt16FromFileToFloatBuffer( - &pcm_file, audio_buffer_length, audio_buffer.get()); + pcm_file.get(), audio_buffer_length, audio_buffer.get()); for (int time = 0; file_samples_read > 0; time += chunk_size_ms) { // Pad the rest of the buffer with zeros. for (size_t i = file_samples_read; i < audio_buffer_length; ++i) { @@ -89,19 +91,19 @@ int main(int argc, char* argv[]) { // Read next buffer from the PCM test file. file_samples_read = ReadInt16FromFileToFloatBuffer( - &pcm_file, audio_buffer_length, audio_buffer.get()); + pcm_file.get(), audio_buffer_length, audio_buffer.get()); } size_t floats_written = - WriteFloatBufferToFile(&dat_file, send_times.size(), &send_times[0]); + WriteFloatBufferToFile(dat_file.get(), send_times.size(), &send_times[0]); if (floats_written == 0) { printf("\nThe send times could not be written to DAT file\n\n"); return -1; } - pcm_file.Close(); - dat_file.Close(); + pcm_file->CloseFile(); + dat_file->CloseFile(); return lost_packets; } diff --git a/modules/audio_processing/transient/file_utils_unittest.cc b/modules/audio_processing/transient/file_utils_unittest.cc index 0bded020b1..ced06b197d 100644 --- a/modules/audio_processing/transient/file_utils_unittest.cc +++ b/modules/audio_processing/transient/file_utils_unittest.cc @@ -158,20 +158,22 @@ TEST_F(TransientFileUtilsTest, MAYBE_ConvertDoubleToByteArray) { TEST_F(TransientFileUtilsTest, MAYBE_ReadInt16BufferFromFile) { std::string test_filename = kTestFileName; - FileWrapper file = FileWrapper::OpenReadOnly(test_filename.c_str()); - ASSERT_TRUE(file.is_open()) << "File could not be opened:\n" - << kTestFileName.c_str(); + std::unique_ptr file(FileWrapper::Create()); + + file->OpenFile(test_filename.c_str(), true); // Read only. + ASSERT_TRUE(file->is_open()) << "File could not be opened:\n" + << kTestFileName.c_str(); const size_t kBufferLength = 12; std::unique_ptr buffer(new int16_t[kBufferLength]); EXPECT_EQ(kBufferLength, - ReadInt16BufferFromFile(&file, kBufferLength, buffer.get())); + ReadInt16BufferFromFile(file.get(), kBufferLength, buffer.get())); EXPECT_EQ(22377, buffer[4]); EXPECT_EQ(16389, buffer[7]); EXPECT_EQ(17631, buffer[kBufferLength - 1]); - file.Rewind(); + file->Rewind(); // The next test is for checking the case where there are not as much data as // needed in the file, but reads to the end, and it returns the number of @@ -179,7 +181,7 @@ TEST_F(TransientFileUtilsTest, MAYBE_ReadInt16BufferFromFile) { const size_t kBufferLenghtLargerThanFile = kBufferLength * 2; buffer.reset(new int16_t[kBufferLenghtLargerThanFile]); EXPECT_EQ(kBufferLength, - ReadInt16BufferFromFile(&file, kBufferLenghtLargerThanFile, + ReadInt16BufferFromFile(file.get(), kBufferLenghtLargerThanFile, buffer.get())); EXPECT_EQ(11544, buffer[0]); EXPECT_EQ(22377, buffer[4]); @@ -196,22 +198,24 @@ TEST_F(TransientFileUtilsTest, MAYBE_ReadInt16BufferFromFile) { TEST_F(TransientFileUtilsTest, MAYBE_ReadInt16FromFileToFloatBuffer) { std::string test_filename = kTestFileName; - FileWrapper file = FileWrapper::OpenReadOnly(test_filename.c_str()); - ASSERT_TRUE(file.is_open()) << "File could not be opened:\n" - << kTestFileName.c_str(); + std::unique_ptr file(FileWrapper::Create()); + + file->OpenFile(test_filename.c_str(), true); // Read only. + ASSERT_TRUE(file->is_open()) << "File could not be opened:\n" + << kTestFileName.c_str(); const size_t kBufferLength = 12; std::unique_ptr buffer(new float[kBufferLength]); - EXPECT_EQ(kBufferLength, - ReadInt16FromFileToFloatBuffer(&file, kBufferLength, buffer.get())); + EXPECT_EQ(kBufferLength, ReadInt16FromFileToFloatBuffer( + file.get(), kBufferLength, buffer.get())); EXPECT_DOUBLE_EQ(11544, buffer[0]); EXPECT_DOUBLE_EQ(22377, buffer[4]); EXPECT_DOUBLE_EQ(16389, buffer[7]); EXPECT_DOUBLE_EQ(17631, buffer[kBufferLength - 1]); - file.Rewind(); + file->Rewind(); // The next test is for checking the case where there are not as much data as // needed in the file, but reads to the end, and it returns the number of @@ -219,8 +223,8 @@ TEST_F(TransientFileUtilsTest, MAYBE_ReadInt16FromFileToFloatBuffer) { const size_t kBufferLenghtLargerThanFile = kBufferLength * 2; buffer.reset(new float[kBufferLenghtLargerThanFile]); EXPECT_EQ(kBufferLength, - ReadInt16FromFileToFloatBuffer(&file, kBufferLenghtLargerThanFile, - buffer.get())); + ReadInt16FromFileToFloatBuffer( + file.get(), kBufferLenghtLargerThanFile, buffer.get())); EXPECT_DOUBLE_EQ(11544, buffer[0]); EXPECT_DOUBLE_EQ(22377, buffer[4]); EXPECT_DOUBLE_EQ(16389, buffer[7]); @@ -236,21 +240,23 @@ TEST_F(TransientFileUtilsTest, MAYBE_ReadInt16FromFileToFloatBuffer) { TEST_F(TransientFileUtilsTest, MAYBE_ReadInt16FromFileToDoubleBuffer) { std::string test_filename = kTestFileName; - FileWrapper file = FileWrapper::OpenReadOnly(test_filename.c_str()); - ASSERT_TRUE(file.is_open()) << "File could not be opened:\n" - << kTestFileName.c_str(); + std::unique_ptr file(FileWrapper::Create()); + + file->OpenFile(test_filename.c_str(), true); // Read only. + ASSERT_TRUE(file->is_open()) << "File could not be opened:\n" + << kTestFileName.c_str(); const size_t kBufferLength = 12; std::unique_ptr buffer(new double[kBufferLength]); - EXPECT_EQ(kBufferLength, ReadInt16FromFileToDoubleBuffer(&file, kBufferLength, - buffer.get())); + EXPECT_EQ(kBufferLength, ReadInt16FromFileToDoubleBuffer( + file.get(), kBufferLength, buffer.get())); EXPECT_DOUBLE_EQ(11544, buffer[0]); EXPECT_DOUBLE_EQ(22377, buffer[4]); EXPECT_DOUBLE_EQ(16389, buffer[7]); EXPECT_DOUBLE_EQ(17631, buffer[kBufferLength - 1]); - file.Rewind(); + file->Rewind(); // The next test is for checking the case where there are not as much data as // needed in the file, but reads to the end, and it returns the number of @@ -258,8 +264,8 @@ TEST_F(TransientFileUtilsTest, MAYBE_ReadInt16FromFileToDoubleBuffer) { const size_t kBufferLenghtLargerThanFile = kBufferLength * 2; buffer.reset(new double[kBufferLenghtLargerThanFile]); EXPECT_EQ(kBufferLength, - ReadInt16FromFileToDoubleBuffer(&file, kBufferLenghtLargerThanFile, - buffer.get())); + ReadInt16FromFileToDoubleBuffer( + file.get(), kBufferLenghtLargerThanFile, buffer.get())); EXPECT_DOUBLE_EQ(11544, buffer[0]); EXPECT_DOUBLE_EQ(22377, buffer[4]); EXPECT_DOUBLE_EQ(16389, buffer[7]); @@ -274,20 +280,22 @@ TEST_F(TransientFileUtilsTest, MAYBE_ReadInt16FromFileToDoubleBuffer) { TEST_F(TransientFileUtilsTest, MAYBE_ReadFloatBufferFromFile) { std::string test_filename = kTestFileNamef; - FileWrapper file = FileWrapper::OpenReadOnly(test_filename.c_str()); - ASSERT_TRUE(file.is_open()) << "File could not be opened:\n" - << kTestFileNamef.c_str(); + std::unique_ptr file(FileWrapper::Create()); + + file->OpenFile(test_filename.c_str(), true); // Read only. + ASSERT_TRUE(file->is_open()) << "File could not be opened:\n" + << kTestFileNamef.c_str(); const size_t kBufferLength = 3; std::unique_ptr buffer(new float[kBufferLength]); EXPECT_EQ(kBufferLength, - ReadFloatBufferFromFile(&file, kBufferLength, buffer.get())); + ReadFloatBufferFromFile(file.get(), kBufferLength, buffer.get())); EXPECT_FLOAT_EQ(kPi, buffer[0]); EXPECT_FLOAT_EQ(kE, buffer[1]); EXPECT_FLOAT_EQ(kAvogadro, buffer[2]); - file.Rewind(); + file->Rewind(); // The next test is for checking the case where there are not as much data as // needed in the file, but reads to the end, and it returns the number of @@ -295,7 +303,7 @@ TEST_F(TransientFileUtilsTest, MAYBE_ReadFloatBufferFromFile) { const size_t kBufferLenghtLargerThanFile = kBufferLength * 2; buffer.reset(new float[kBufferLenghtLargerThanFile]); EXPECT_EQ(kBufferLength, - ReadFloatBufferFromFile(&file, kBufferLenghtLargerThanFile, + ReadFloatBufferFromFile(file.get(), kBufferLenghtLargerThanFile, buffer.get())); EXPECT_FLOAT_EQ(kPi, buffer[0]); EXPECT_FLOAT_EQ(kE, buffer[1]); @@ -310,20 +318,22 @@ TEST_F(TransientFileUtilsTest, MAYBE_ReadFloatBufferFromFile) { TEST_F(TransientFileUtilsTest, MAYBE_ReadDoubleBufferFromFile) { std::string test_filename = kTestFileName; - FileWrapper file = FileWrapper::OpenReadOnly(test_filename.c_str()); - ASSERT_TRUE(file.is_open()) << "File could not be opened:\n" - << kTestFileName.c_str(); + std::unique_ptr file(FileWrapper::Create()); + + file->OpenFile(test_filename.c_str(), true); // Read only. + ASSERT_TRUE(file->is_open()) << "File could not be opened:\n" + << kTestFileName.c_str(); const size_t kBufferLength = 3; std::unique_ptr buffer(new double[kBufferLength]); EXPECT_EQ(kBufferLength, - ReadDoubleBufferFromFile(&file, kBufferLength, buffer.get())); + ReadDoubleBufferFromFile(file.get(), kBufferLength, buffer.get())); EXPECT_DOUBLE_EQ(kPi, buffer[0]); EXPECT_DOUBLE_EQ(kE, buffer[1]); EXPECT_DOUBLE_EQ(kAvogadro, buffer[2]); - file.Rewind(); + file->Rewind(); // The next test is for checking the case where there are not as much data as // needed in the file, but reads to the end, and it returns the number of @@ -331,7 +341,7 @@ TEST_F(TransientFileUtilsTest, MAYBE_ReadDoubleBufferFromFile) { const size_t kBufferLenghtLargerThanFile = kBufferLength * 2; buffer.reset(new double[kBufferLenghtLargerThanFile]); EXPECT_EQ(kBufferLength, - ReadDoubleBufferFromFile(&file, kBufferLenghtLargerThanFile, + ReadDoubleBufferFromFile(file.get(), kBufferLenghtLargerThanFile, buffer.get())); EXPECT_DOUBLE_EQ(kPi, buffer[0]); EXPECT_DOUBLE_EQ(kE, buffer[1]); @@ -344,12 +354,14 @@ TEST_F(TransientFileUtilsTest, MAYBE_ReadDoubleBufferFromFile) { #define MAYBE_WriteInt16BufferToFile WriteInt16BufferToFile #endif TEST_F(TransientFileUtilsTest, MAYBE_WriteInt16BufferToFile) { + std::unique_ptr file(FileWrapper::Create()); + std::string kOutFileName = CreateTempFilename(test::OutputPath(), "utils_test"); - FileWrapper file = FileWrapper::OpenWriteOnly(kOutFileName.c_str()); - ASSERT_TRUE(file.is_open()) << "File could not be opened:\n" - << kOutFileName.c_str(); + file->OpenFile(kOutFileName.c_str(), false); // Write mode. + ASSERT_TRUE(file->is_open()) << "File could not be opened:\n" + << kOutFileName.c_str(); const size_t kBufferLength = 3; std::unique_ptr written_buffer(new int16_t[kBufferLength]); @@ -359,17 +371,17 @@ TEST_F(TransientFileUtilsTest, MAYBE_WriteInt16BufferToFile) { written_buffer[1] = 2; written_buffer[2] = 3; - EXPECT_EQ(kBufferLength, - WriteInt16BufferToFile(&file, kBufferLength, written_buffer.get())); + EXPECT_EQ(kBufferLength, WriteInt16BufferToFile(file.get(), kBufferLength, + written_buffer.get())); - file.Close(); + file->CloseFile(); - file = FileWrapper::OpenReadOnly(kOutFileName.c_str()); - ASSERT_TRUE(file.is_open()) << "File could not be opened:\n" - << kOutFileName.c_str(); + file->OpenFile(kOutFileName.c_str(), true); // Read only. + ASSERT_TRUE(file->is_open()) << "File could not be opened:\n" + << kOutFileName.c_str(); - EXPECT_EQ(kBufferLength, - ReadInt16BufferFromFile(&file, kBufferLength, read_buffer.get())); + EXPECT_EQ(kBufferLength, ReadInt16BufferFromFile(file.get(), kBufferLength, + read_buffer.get())); EXPECT_EQ(0, memcmp(written_buffer.get(), read_buffer.get(), kBufferLength * sizeof(written_buffer[0]))); } @@ -380,12 +392,14 @@ TEST_F(TransientFileUtilsTest, MAYBE_WriteInt16BufferToFile) { #define MAYBE_WriteFloatBufferToFile WriteFloatBufferToFile #endif TEST_F(TransientFileUtilsTest, MAYBE_WriteFloatBufferToFile) { + std::unique_ptr file(FileWrapper::Create()); + std::string kOutFileName = CreateTempFilename(test::OutputPath(), "utils_test"); - FileWrapper file = FileWrapper::OpenWriteOnly(kOutFileName.c_str()); - ASSERT_TRUE(file.is_open()) << "File could not be opened:\n" - << kOutFileName.c_str(); + file->OpenFile(kOutFileName.c_str(), false); // Write mode. + ASSERT_TRUE(file->is_open()) << "File could not be opened:\n" + << kOutFileName.c_str(); const size_t kBufferLength = 3; std::unique_ptr written_buffer(new float[kBufferLength]); @@ -395,17 +409,17 @@ TEST_F(TransientFileUtilsTest, MAYBE_WriteFloatBufferToFile) { written_buffer[1] = static_cast(kE); written_buffer[2] = static_cast(kAvogadro); - EXPECT_EQ(kBufferLength, - WriteFloatBufferToFile(&file, kBufferLength, written_buffer.get())); + EXPECT_EQ(kBufferLength, WriteFloatBufferToFile(file.get(), kBufferLength, + written_buffer.get())); - file.Close(); + file->CloseFile(); - file = FileWrapper::OpenReadOnly(kOutFileName.c_str()); - ASSERT_TRUE(file.is_open()) << "File could not be opened:\n" - << kOutFileName.c_str(); + file->OpenFile(kOutFileName.c_str(), true); // Read only. + ASSERT_TRUE(file->is_open()) << "File could not be opened:\n" + << kOutFileName.c_str(); - EXPECT_EQ(kBufferLength, - ReadFloatBufferFromFile(&file, kBufferLength, read_buffer.get())); + EXPECT_EQ(kBufferLength, ReadFloatBufferFromFile(file.get(), kBufferLength, + read_buffer.get())); EXPECT_EQ(0, memcmp(written_buffer.get(), read_buffer.get(), kBufferLength * sizeof(written_buffer[0]))); } @@ -416,12 +430,14 @@ TEST_F(TransientFileUtilsTest, MAYBE_WriteFloatBufferToFile) { #define MAYBE_WriteDoubleBufferToFile WriteDoubleBufferToFile #endif TEST_F(TransientFileUtilsTest, MAYBE_WriteDoubleBufferToFile) { + std::unique_ptr file(FileWrapper::Create()); + std::string kOutFileName = CreateTempFilename(test::OutputPath(), "utils_test"); - FileWrapper file = FileWrapper::OpenWriteOnly(kOutFileName.c_str()); - ASSERT_TRUE(file.is_open()) << "File could not be opened:\n" - << kOutFileName.c_str(); + file->OpenFile(kOutFileName.c_str(), false); // Write mode. + ASSERT_TRUE(file->is_open()) << "File could not be opened:\n" + << kOutFileName.c_str(); const size_t kBufferLength = 3; std::unique_ptr written_buffer(new double[kBufferLength]); @@ -431,17 +447,17 @@ TEST_F(TransientFileUtilsTest, MAYBE_WriteDoubleBufferToFile) { written_buffer[1] = kE; written_buffer[2] = kAvogadro; - EXPECT_EQ(kBufferLength, WriteDoubleBufferToFile(&file, kBufferLength, + EXPECT_EQ(kBufferLength, WriteDoubleBufferToFile(file.get(), kBufferLength, written_buffer.get())); - file.Close(); + file->CloseFile(); - file = FileWrapper::OpenReadOnly(kOutFileName.c_str()); - ASSERT_TRUE(file.is_open()) << "File could not be opened:\n" - << kOutFileName.c_str(); + file->OpenFile(kOutFileName.c_str(), true); // Read only. + ASSERT_TRUE(file->is_open()) << "File could not be opened:\n" + << kOutFileName.c_str(); - EXPECT_EQ(kBufferLength, - ReadDoubleBufferFromFile(&file, kBufferLength, read_buffer.get())); + EXPECT_EQ(kBufferLength, ReadDoubleBufferFromFile(file.get(), kBufferLength, + read_buffer.get())); EXPECT_EQ(0, memcmp(written_buffer.get(), read_buffer.get(), kBufferLength * sizeof(written_buffer[0]))); } @@ -457,7 +473,7 @@ TEST_F(TransientFileUtilsTest, MAYBE_ExpectedErrorReturnValues) { double value; std::unique_ptr int16_buffer(new int16_t[1]); std::unique_ptr double_buffer(new double[1]); - FileWrapper file; + std::unique_ptr file(FileWrapper::Create()); EXPECT_EQ(-1, ConvertByteArrayToDouble(NULL, &value)); EXPECT_EQ(-1, ConvertByteArrayToDouble(kPiBytes, NULL)); @@ -465,35 +481,37 @@ TEST_F(TransientFileUtilsTest, MAYBE_ExpectedErrorReturnValues) { EXPECT_EQ(-1, ConvertDoubleToByteArray(kPi, NULL)); // Tests with file not opened. - EXPECT_EQ(0u, ReadInt16BufferFromFile(&file, 1, int16_buffer.get())); - EXPECT_EQ(0u, ReadInt16FromFileToDoubleBuffer(&file, 1, double_buffer.get())); - EXPECT_EQ(0u, ReadDoubleBufferFromFile(&file, 1, double_buffer.get())); - EXPECT_EQ(0u, WriteInt16BufferToFile(&file, 1, int16_buffer.get())); - EXPECT_EQ(0u, WriteDoubleBufferToFile(&file, 1, double_buffer.get())); + EXPECT_EQ(0u, ReadInt16BufferFromFile(file.get(), 1, int16_buffer.get())); + EXPECT_EQ( + 0u, ReadInt16FromFileToDoubleBuffer(file.get(), 1, double_buffer.get())); + EXPECT_EQ(0u, ReadDoubleBufferFromFile(file.get(), 1, double_buffer.get())); + EXPECT_EQ(0u, WriteInt16BufferToFile(file.get(), 1, int16_buffer.get())); + EXPECT_EQ(0u, WriteDoubleBufferToFile(file.get(), 1, double_buffer.get())); - file = FileWrapper::OpenReadOnly(test_filename.c_str()); - ASSERT_TRUE(file.is_open()) << "File could not be opened:\n" - << kTestFileName.c_str(); + file->OpenFile(test_filename.c_str(), true); // Read only. + ASSERT_TRUE(file->is_open()) << "File could not be opened:\n" + << kTestFileName.c_str(); EXPECT_EQ(0u, ReadInt16BufferFromFile(NULL, 1, int16_buffer.get())); - EXPECT_EQ(0u, ReadInt16BufferFromFile(&file, 1, NULL)); - EXPECT_EQ(0u, ReadInt16BufferFromFile(&file, 0, int16_buffer.get())); + EXPECT_EQ(0u, ReadInt16BufferFromFile(file.get(), 1, NULL)); + EXPECT_EQ(0u, ReadInt16BufferFromFile(file.get(), 0, int16_buffer.get())); EXPECT_EQ(0u, ReadInt16FromFileToDoubleBuffer(NULL, 1, double_buffer.get())); - EXPECT_EQ(0u, ReadInt16FromFileToDoubleBuffer(&file, 1, NULL)); - EXPECT_EQ(0u, ReadInt16FromFileToDoubleBuffer(&file, 0, double_buffer.get())); + EXPECT_EQ(0u, ReadInt16FromFileToDoubleBuffer(file.get(), 1, NULL)); + EXPECT_EQ( + 0u, ReadInt16FromFileToDoubleBuffer(file.get(), 0, double_buffer.get())); EXPECT_EQ(0u, ReadDoubleBufferFromFile(NULL, 1, double_buffer.get())); - EXPECT_EQ(0u, ReadDoubleBufferFromFile(&file, 1, NULL)); - EXPECT_EQ(0u, ReadDoubleBufferFromFile(&file, 0, double_buffer.get())); + EXPECT_EQ(0u, ReadDoubleBufferFromFile(file.get(), 1, NULL)); + EXPECT_EQ(0u, ReadDoubleBufferFromFile(file.get(), 0, double_buffer.get())); EXPECT_EQ(0u, WriteInt16BufferToFile(NULL, 1, int16_buffer.get())); - EXPECT_EQ(0u, WriteInt16BufferToFile(&file, 1, NULL)); - EXPECT_EQ(0u, WriteInt16BufferToFile(&file, 0, int16_buffer.get())); + EXPECT_EQ(0u, WriteInt16BufferToFile(file.get(), 1, NULL)); + EXPECT_EQ(0u, WriteInt16BufferToFile(file.get(), 0, int16_buffer.get())); EXPECT_EQ(0u, WriteDoubleBufferToFile(NULL, 1, double_buffer.get())); - EXPECT_EQ(0u, WriteDoubleBufferToFile(&file, 1, NULL)); - EXPECT_EQ(0u, WriteDoubleBufferToFile(&file, 0, double_buffer.get())); + EXPECT_EQ(0u, WriteDoubleBufferToFile(file.get(), 1, NULL)); + EXPECT_EQ(0u, WriteDoubleBufferToFile(file.get(), 0, double_buffer.get())); } } // namespace webrtc diff --git a/modules/audio_processing/transient/transient_detector_unittest.cc b/modules/audio_processing/transient/transient_detector_unittest.cc index 0425133fba..11dd8aa384 100644 --- a/modules/audio_processing/transient/transient_detector_unittest.cc +++ b/modules/audio_processing/transient/transient_detector_unittest.cc @@ -47,10 +47,13 @@ TEST(TransientDetectorTest, CorrectnessBasedOnFiles) { detect_file_name << "audio_processing/transient/detect" << (sample_rate_hz / 1000) << "kHz"; - FileWrapper detect_file = FileWrapper::OpenReadOnly( - test::ResourcePath(detect_file_name.str(), "dat").c_str()); + std::unique_ptr detect_file(FileWrapper::Create()); - bool file_opened = detect_file.is_open(); + detect_file->OpenFile( + test::ResourcePath(detect_file_name.str(), "dat").c_str(), + true); // Read only. + + bool file_opened = detect_file->is_open(); ASSERT_TRUE(file_opened) << "File could not be opened.\n" << detect_file_name.str().c_str(); @@ -59,8 +62,11 @@ TEST(TransientDetectorTest, CorrectnessBasedOnFiles) { audio_file_name << "audio_processing/transient/audio" << (sample_rate_hz / 1000) << "kHz"; - FileWrapper audio_file = FileWrapper::OpenReadOnly( - test::ResourcePath(audio_file_name.str(), "pcm").c_str()); + std::unique_ptr audio_file(FileWrapper::Create()); + + audio_file->OpenFile( + test::ResourcePath(audio_file_name.str(), "pcm").c_str(), + true); // Read only. // Create detector. TransientDetector detector(sample_rate_hz); @@ -72,14 +78,14 @@ TEST(TransientDetectorTest, CorrectnessBasedOnFiles) { size_t frames_read = 0; - while (ReadInt16FromFileToFloatBuffer(&audio_file, buffer_length, + while (ReadInt16FromFileToFloatBuffer(audio_file.get(), buffer_length, buffer.get()) == buffer_length) { ++frames_read; float detector_value = detector.Detect(buffer.get(), buffer_length, NULL, 0); double file_value; - ASSERT_EQ(1u, ReadDoubleBufferFromFile(&detect_file, 1, &file_value)) + ASSERT_EQ(1u, ReadDoubleBufferFromFile(detect_file.get(), 1, &file_value)) << "Detect test file is malformed.\n"; // Compare results with data from the matlab test file. @@ -87,8 +93,8 @@ TEST(TransientDetectorTest, CorrectnessBasedOnFiles) { << "Frame: " << frames_read; } - detect_file.Close(); - audio_file.Close(); + detect_file->CloseFile(); + audio_file->CloseFile(); } } diff --git a/modules/audio_processing/transient/wpd_tree_unittest.cc b/modules/audio_processing/transient/wpd_tree_unittest.cc index 11f75e6fb0..1d6dbe8e49 100644 --- a/modules/audio_processing/transient/wpd_tree_unittest.cc +++ b/modules/audio_processing/transient/wpd_tree_unittest.cc @@ -80,27 +80,31 @@ TEST(WPDTreeTest, CorrectnessBasedOnMatlabFiles) { kDaubechies8LowPassCoefficients, kDaubechies8CoefficientsLength, kLevels); // Allocate and open all matlab and out files. - FileWrapper matlab_files_data[kLeaves]; - FileWrapper out_files_data[kLeaves]; + std::unique_ptr matlab_files_data[kLeaves]; + std::unique_ptr out_files_data[kLeaves]; for (int i = 0; i < kLeaves; ++i) { // Matlab files. + matlab_files_data[i].reset(FileWrapper::Create()); + rtc::StringBuilder matlab_stream; matlab_stream << "audio_processing/transient/wpd" << i; std::string matlab_string = test::ResourcePath(matlab_stream.str(), "dat"); - matlab_files_data[i] = FileWrapper::OpenReadOnly(matlab_string.c_str()); + matlab_files_data[i]->OpenFile(matlab_string.c_str(), true); // Read only. - bool file_opened = matlab_files_data[i].is_open(); + bool file_opened = matlab_files_data[i]->is_open(); ASSERT_TRUE(file_opened) << "File could not be opened.\n" << matlab_string; // Out files. + out_files_data[i].reset(FileWrapper::Create()); + rtc::StringBuilder out_stream; out_stream << test::OutputPath() << "wpd_" << i << ".out"; std::string out_string = out_stream.str(); - out_files_data[i] = FileWrapper::OpenWriteOnly(out_string.c_str()); + out_files_data[i]->OpenFile(out_string.c_str(), false); // Write mode. - file_opened = out_files_data[i].is_open(); + file_opened = out_files_data[i]->is_open(); ASSERT_TRUE(file_opened) << "File could not be opened.\n" << out_string; } @@ -108,9 +112,11 @@ TEST(WPDTreeTest, CorrectnessBasedOnMatlabFiles) { std::string test_file_name = test::ResourcePath( "audio_processing/transient/ajm-macbook-1-spke16m", "pcm"); - FileWrapper test_file = FileWrapper::OpenReadOnly(test_file_name.c_str()); + std::unique_ptr test_file(FileWrapper::Create()); - bool file_opened = test_file.is_open(); + test_file->OpenFile(test_file_name.c_str(), true); // Read only. + + bool file_opened = test_file->is_open(); ASSERT_TRUE(file_opened) << "File could not be opened.\n" << test_file_name; float test_buffer[kTestBufferSize]; @@ -123,8 +129,8 @@ TEST(WPDTreeTest, CorrectnessBasedOnMatlabFiles) { size_t frames_read = 0; // Read first buffer from the PCM test file. - size_t file_samples_read = - ReadInt16FromFileToFloatBuffer(&test_file, kTestBufferSize, test_buffer); + size_t file_samples_read = ReadInt16FromFileToFloatBuffer( + test_file.get(), kTestBufferSize, test_buffer); while (file_samples_read > 0 && frames_read < kMaxFramesToTest) { ++frames_read; @@ -141,7 +147,7 @@ TEST(WPDTreeTest, CorrectnessBasedOnMatlabFiles) { for (int i = 0; i < kLeaves; ++i) { // Compare data values size_t matlab_samples_read = ReadDoubleBufferFromFile( - &matlab_files_data[i], kLeavesSamples, matlab_buffer); + matlab_files_data[i].get(), kLeavesSamples, matlab_buffer); ASSERT_EQ(kLeavesSamples, matlab_samples_read) << "Matlab test files are malformed.\n" @@ -156,21 +162,22 @@ TEST(WPDTreeTest, CorrectnessBasedOnMatlabFiles) { } // Write results to out files. - WriteFloatBufferToFile(&out_files_data[i], kLeavesSamples, node_data); + WriteFloatBufferToFile(out_files_data[i].get(), kLeavesSamples, + node_data); } // Read next buffer from the PCM test file. file_samples_read = ReadInt16FromFileToFloatBuffer( - &test_file, kTestBufferSize, test_buffer); + test_file.get(), kTestBufferSize, test_buffer); } // Close all matlab and out files. for (int i = 0; i < kLeaves; ++i) { - matlab_files_data[i].Close(); - out_files_data[i].Close(); + matlab_files_data[i]->CloseFile(); + out_files_data[i]->CloseFile(); } - test_file.Close(); + test_file->CloseFile(); } } // namespace webrtc diff --git a/rtc_base/system/file_wrapper.cc b/rtc_base/system/file_wrapper.cc index dbea1ca907..c033a792a5 100644 --- a/rtc_base/system/file_wrapper.cc +++ b/rtc_base/system/file_wrapper.cc @@ -34,13 +34,22 @@ FILE* FileOpen(const char* file_name_utf8, bool read_only) { } // namespace // static -FileWrapper FileWrapper::OpenReadOnly(const char* file_name_utf8) { - return FileWrapper(FileOpen(file_name_utf8, true)); +FileWrapper* FileWrapper::Create() { + return new FileWrapper(); } // static -FileWrapper FileWrapper::OpenWriteOnly(const char* file_name_utf8) { - return FileWrapper(FileOpen(file_name_utf8, false)); +FileWrapper FileWrapper::Open(const char* file_name_utf8, bool read_only) { + return FileWrapper(FileOpen(file_name_utf8, read_only), 0); +} + +FileWrapper::FileWrapper() {} + +FileWrapper::FileWrapper(FILE* file, size_t max_size) + : file_(file), max_size_in_bytes_(max_size) {} + +FileWrapper::~FileWrapper() { + CloseFileImpl(); } FileWrapper::FileWrapper(FileWrapper&& other) { @@ -48,39 +57,95 @@ FileWrapper::FileWrapper(FileWrapper&& other) { } FileWrapper& FileWrapper::operator=(FileWrapper&& other) { - Close(); file_ = other.file_; + max_size_in_bytes_ = other.max_size_in_bytes_; + position_ = other.position_; other.file_ = nullptr; return *this; } -bool FileWrapper::Rewind() { - RTC_DCHECK(file_); - return fseek(file_, 0, SEEK_SET) == 0; +void FileWrapper::CloseFile() { + rtc::CritScope lock(&lock_); + CloseFileImpl(); } -bool FileWrapper::Flush() { - RTC_DCHECK(file_); - return fflush(file_) == 0; +int FileWrapper::Rewind() { + rtc::CritScope lock(&lock_); + if (file_ != nullptr) { + position_ = 0; + return fseek(file_, 0, SEEK_SET); + } + return -1; } -size_t FileWrapper::Read(void* buf, size_t length) { - RTC_DCHECK(file_); - return fread(buf, 1, length, file_); +void FileWrapper::SetMaxFileSize(size_t bytes) { + rtc::CritScope lock(&lock_); + max_size_in_bytes_ = bytes; +} + +int FileWrapper::Flush() { + rtc::CritScope lock(&lock_); + return FlushImpl(); +} + +bool FileWrapper::OpenFile(const char* file_name_utf8, bool read_only) { + size_t length = strlen(file_name_utf8); + if (length > kMaxFileNameSize - 1) + return false; + + rtc::CritScope lock(&lock_); + if (file_ != nullptr) + return false; + + file_ = FileOpen(file_name_utf8, read_only); + return file_ != nullptr; +} + +bool FileWrapper::OpenFromFileHandle(FILE* handle) { + if (!handle) + return false; + rtc::CritScope lock(&lock_); + CloseFileImpl(); + file_ = handle; + return true; +} + +int FileWrapper::Read(void* buf, size_t length) { + rtc::CritScope lock(&lock_); + if (file_ == nullptr) + return -1; + + size_t bytes_read = fread(buf, 1, length, file_); + return static_cast(bytes_read); } bool FileWrapper::Write(const void* buf, size_t length) { - RTC_DCHECK(file_); - return fwrite(buf, 1, length, file_) == length; + if (buf == nullptr) + return false; + + rtc::CritScope lock(&lock_); + + if (file_ == nullptr) + return false; + + // Check if it's time to stop writing. + if (max_size_in_bytes_ > 0 && (position_ + length) > max_size_in_bytes_) + return false; + + size_t num_bytes = fwrite(buf, 1, length, file_); + position_ += num_bytes; + + return num_bytes == length; } -bool FileWrapper::Close() { - if (file_ == nullptr) - return true; - - bool success = fclose(file_) == 0; +void FileWrapper::CloseFileImpl() { + if (file_ != nullptr) + fclose(file_); file_ = nullptr; - return success; +} + +int FileWrapper::FlushImpl() { + return (file_ != nullptr) ? fflush(file_) : -1; } } // namespace webrtc diff --git a/rtc_base/system/file_wrapper.h b/rtc_base/system/file_wrapper.h index d56e131cfa..f2ed51ae3c 100644 --- a/rtc_base/system/file_wrapper.h +++ b/rtc_base/system/file_wrapper.h @@ -20,57 +20,64 @@ namespace webrtc { +// TODO(tommi): Rename to rtc::File and move to base. class FileWrapper final { public: - // Opens a file, in read or write mode. Use the is_open() method on the - // returned object to check if the open operation was successful. The file is - // closed by the destructor. - static FileWrapper OpenReadOnly(const char* file_name_utf8); - static FileWrapper OpenWriteOnly(const char* file_name_utf8); + static const size_t kMaxFileNameSize = 1024; - FileWrapper() = default; + // Factory methods. + // TODO(tommi): Remove Create(). + static FileWrapper* Create(); + static FileWrapper Open(const char* file_name_utf8, bool read_only); - // Takes over ownership of |file|, closing it on destruction. - explicit FileWrapper(FILE* file) : file_(file) {} - ~FileWrapper() { Close(); } + FileWrapper(FILE* file, size_t max_size); + ~FileWrapper(); + + // Support for move semantics. + FileWrapper(FileWrapper&& other); + FileWrapper& operator=(FileWrapper&& other); + + // Returns true if a file has been opened. + bool is_open() const { return file_ != nullptr; } + + // Opens a file in read or write mode, decided by the read_only parameter. + bool OpenFile(const char* file_name_utf8, bool read_only); + + // Initializes the wrapper from an existing handle. The wrapper + // takes ownership of |handle| and closes it in CloseFile(). + bool OpenFromFileHandle(FILE* handle); + + void CloseFile(); + + // Limits the file size to |bytes|. Writing will fail after the cap + // is hit. Pass zero to use an unlimited size. + // TODO(tommi): Could we move this out into a separate class? + void SetMaxFileSize(size_t bytes); + + // Flush any pending writes. Note: Flushing when closing, is not required. + int Flush(); + + // Rewinds the file to the start. + int Rewind(); + int Read(void* buf, size_t length); + bool Write(const void* buf, size_t length); + + private: + FileWrapper(); + + void CloseFileImpl(); + int FlushImpl(); + + // TODO(tommi): Remove the lock. + rtc::CriticalSection lock_; + + FILE* file_ = nullptr; + size_t position_ = 0; + size_t max_size_in_bytes_ = 0; // Copying is not supported. FileWrapper(const FileWrapper&) = delete; FileWrapper& operator=(const FileWrapper&) = delete; - - // Support for move semantics. - FileWrapper(FileWrapper&&); - FileWrapper& operator=(FileWrapper&&); - - // Returns true if a file has been opened. If the file is not open, no methods - // but is_open and Close may be called. - bool is_open() const { return file_ != nullptr; } - - // Closes the file, and implies Flush. Returns true on success, false if - // writing buffered data fails. On failure, the file is nevertheless closed. - // Calling Close on an already closed file does nothing and returns success. - bool Close(); - - // Write any buffered data to the underlying file. Returns true on success, - // false on write error. Note: Flushing when closing, is not required. - // TODO(nisse): Delete this method. - bool Flush(); - - // Seeks to the beginning of file. Returns true on success, false on failure, - // e.g., if the underlying file isn't seekable. - // TODO(nisse): Delete this method. - bool Rewind(); - - // Returns number of bytes read. Short count indicates EOF or error. - size_t Read(void* buf, size_t length); - - // Returns true if all data was successfully written (or buffered), or false - // if there was an error. Writing buffered data can fail later, and is - // reported with return value from Flush or Close. - bool Write(const void* buf, size_t length); - - private: - FILE* file_ = nullptr; }; } // namespace webrtc