/** ** Copyright (c) 2007-2009 Illumina, Inc. ** ** This software is covered by the "Illumina Genome Analyzer Software ** License Agreement" and the "Illumina Source Code License Agreement", ** and certain third party copyright/licenses, and any user of this ** source file is bound by the terms therein (see accompanying files ** Illumina_Genome_Analyzer_Software_License_Agreement.pdf and ** Illumina_Source_Code_License_Agreement.pdf and third party ** copyright/license notices). ** ** This file is part of the Consensus Assessment of Sequence And VAriation ** (CASAVA) software package. ** ** \file BclWriter.hh ** ** \brief Writes BCL files and other associated files (filter, position). ** ** \author Roman Petrovski **/ #ifndef CASAVA_IO_BCL_WRITER_HH #define CASAVA_IO_BCL_WRITER_HH #include #include #include #include #include #include "common/Exceptions.hh" #include "common/FastIo.hh" #include "common/Compression.hh" #include "common/FilteringStreams.hh" namespace casava { namespace io { namespace fs = boost::filesystem; namespace cc = casava::common; /** ** \brief Parallel ofstream storing sequences and qualities cluster by cluster. **/ class BclWriter { public: typedef std::pair Cluster; BclWriter(const fs::path &path, const cc::Compression &compressor, const unsigned int expectedClusters = 0); BclWriter(const fs::path &path, const unsigned int expectedClusters = 0); ~BclWriter(); void put(const Cluster& cluster) { writeBase(*cluster.first.begin(), *cluster.second.begin()); ++currentCluster_; } void close(); private: const fs::path outputFilePath_; cc::Ofstream os_; unsigned int currentCluster_; const unsigned int expectedClusters_; void open(); void writeBase(const char &base, const char &qual); BclWriter(); BclWriter(const BclWriter &); BclWriter &operator=(const BclWriter &); }; /** ** \brief ofstream storing filter values cluster by cluster. **/ class FiltersWriter { public: FiltersWriter(const fs::path &filePath, const cc::Compression &compressor, const unsigned int expectedClusters = 0) : filePath_(filePath.string() + compressor.getFileNameExtension()), os_(compressor), currentCluster_(0), expectedClusters_(expectedClusters) {open();} FiltersWriter(const fs::path &filePath, const unsigned int expectedClusters = 0) : filePath_(filePath), os_(cc::CompressionFactory::none()), currentCluster_(0), expectedClusters_(expectedClusters) {open();} void open() { if (fs::exists(filePath_)) { BOOST_THROW_EXCEPTION(cc::IoException(EPERM, "File already exists: " + filePath_.string())); } os_.open(filePath_.string().c_str(), std::ios_base::out | std::ios_base::binary); if (!os_) { BOOST_THROW_EXCEPTION(cc::IoException(errno, "Couldn't open filters file: " + filePath_.string())); } if (!cc::writeUnsignedInteger<4>(os_, expectedClusters_)){ BOOST_THROW_EXCEPTION(casava::common::IoException(errno, "Failed to write into: " + filePath_.string())); } } ~FiltersWriter(){ } void put(boost::uint_fast8_t filter){ putFilter(filter); } void putFilter(boost::uint_fast8_t filter){ if (!os_.is_open()) { BOOST_THROW_EXCEPTION(casava::common::PreConditionException("Method 'putFilter' called on a closed FiltersWriter")); } os_.put(filter); ++currentCluster_; } void close() { if(os_.is_open()) { if (expectedClusters_ != currentCluster_) { if (!os_.seekp(0, std::ios_base::beg) || !cc::writeUnsignedInteger<4>(os_, currentCluster_)) { BOOST_THROW_EXCEPTION(cc::IoException(errno, "Failed to write number of clusters into filters file: " + filePath_.string())); } } os_.close(); currentCluster_ = 0; } } private: const fs::path filePath_; cc::Ofstream os_; unsigned int currentCluster_; const unsigned int expectedClusters_; FiltersWriter(); FiltersWriter(const FiltersWriter &); FiltersWriter &operator=(const FiltersWriter &); }; /** ** \brief ofstream storing position values cluster by cluster. **/ class PositionsWriterBinary { public: typedef std::pair FloatPosition; PositionsWriterBinary(const fs::path &filePath, const cc::Compression &compressor, const unsigned int expectedClusters = 0) : filePath_(filePath.string() + compressor.getFileNameExtension()), os_(compressor), currentCluster_(0), expectedClusters_(expectedClusters) {open();} PositionsWriterBinary(const fs::path &filePath, const unsigned int expectedClusters = 0) : filePath_(filePath), os_(cc::CompressionFactory::none()), currentCluster_(0), expectedClusters_(expectedClusters) {open();} void open() { if (fs::exists(filePath_)) { BOOST_THROW_EXCEPTION(cc::IoException(EPERM, "File already exists: " + filePath_.string())); } os_.open(filePath_.string().c_str(), std::ios_base::out | std::ios_base::binary); if (!os_) { BOOST_THROW_EXCEPTION(cc::IoException(errno, "Couldn't open positions file: " + filePath_.string())); } // first 8 bytes are unused then goes the placeholder for cluster count if (!cc::writeUnsignedInteger<4>(os_, 0) || !cc::writeUnsignedInteger<4>(os_, 0) || !cc::writeUnsignedInteger<4>(os_, expectedClusters_)){ BOOST_THROW_EXCEPTION(casava::common::IoException(errno, "Failed to write into: " + filePath_.string())); } } ~PositionsWriterBinary(){ } void put(const FloatPosition &position){ putPosition(position); } void putPosition(const FloatPosition &position){ if (!(cc::writeFloat(os_, position.first) && cc::writeFloat(os_, position.second))) { BOOST_THROW_EXCEPTION(casava::common::IoException(errno, "Failed to write data into: " + filePath_.string())); } ++currentCluster_; } void close() { if(os_.is_open()) { if (expectedClusters_ != currentCluster_) { if (!os_.seekp(8, std::ios_base::beg) || !cc::writeUnsignedInteger<4>(os_, currentCluster_)) { BOOST_THROW_EXCEPTION(cc::IoException(errno, "Failed to write number of clusters into locs file: " + filePath_.string())); } } os_.close(); currentCluster_ = 0; } } private: const fs::path filePath_; cc::Ofstream os_; unsigned int currentCluster_; const unsigned int expectedClusters_; PositionsWriterBinary(); PositionsWriterBinary(const PositionsWriterBinary &); PositionsWriterBinary &operator=(const PositionsWriterBinary &); }; /** ** \brief ofstream storing position values cluster by cluster in text form. **/ class PositionsWriterText { public: typedef std::pair FloatPosition; PositionsWriterText(const fs::path &filePath, const cc::Compression &compressor) : filePath_(filePath.string() + compressor.getFileNameExtension()), os_(compressor) , currentCluster_(0) {open();} PositionsWriterText(const fs::path &filePath) : filePath_(filePath), os_(cc::CompressionFactory::none()), currentCluster_(0) {open();} void open() { if (fs::exists(filePath_)) { BOOST_THROW_EXCEPTION(cc::IoException(EPERM, "File already exists: " + filePath_.string())); } os_.open(filePath_.string().c_str()); if (!os_) { BOOST_THROW_EXCEPTION(cc::IoException(errno, "Couldn't open pos file: " + filePath_.string())); } os_.precision(2); os_ << std::fixed << std::showpoint; } ~PositionsWriterText(){ } void put(const FloatPosition &position){ putPosition(position); } void putPosition(const FloatPosition &position){ if (!(os_ << position.first << ' ' << position.second << "\n")) { BOOST_THROW_EXCEPTION(casava::common::IoException(errno, "Failed to write data into: " + filePath_.string())); } ++currentCluster_; } void close() { os_.close(); } private: const fs::path filePath_; cc::Ofstream os_; unsigned int currentCluster_; PositionsWriterText(); PositionsWriterText(const PositionsWriterText &); PositionsWriterText &operator=(const PositionsWriterText &); }; } // namespce io } // namespace casava #endif // CASAVA_IO_BCL_WRITER_HH