iso9660_file_reader

Joliet対応でぐちゃぐちゃになったコードを整理しました。
iso9660_file_source_impl.hppの差分


実装上、ISO 9660とJolietの違いは、

  • ファイルIDの比較方法
  • ファイルIDからファイルパスへの変換

だけなので、これらの操作だけ抽象クラスにまとめれば、至るところにあるJoliet用の分岐を消せそうなのですが、比較対象も抽象オブジェクトとなるため、自分と同じ型であるか確認するか、そうであると決め打ちすることになります。


どうにもこれが嫌だったので、

class FileId
{
public:
    FileId();
    explicit FileId(char c);
    explicit FileId(const std::string& s);

    int filename_compare(const FileId& rhs) const;
    int version_compare(const FileId& rhs) const;
    int compare(const FileId& rhs) const;
    boost::filesystem::path to_path() const;
};

のようなコンセプトでファイルIDを実装し、これを使って、

class iso9660_file_reader_base
{
public:
    virtual ~iso9660_file_reader_base(){};

    bool next_entry(iso9660::header& head)
    {
        return do_next_entry(head);
    }

    bool is_latest() const
    {
        return do_is_latest();
    }

private:
    virtual bool do_next_entry(iso9660::header& head) = 0;
    virtual bool do_is_latest() const = 0;
};

template<class Source, class FileId>
class iso9660_file_reader : public iso9660_file_reader_base
{
    // ...
};

template<class Source>
class basic_iso9660_file_source_impl : private boost::noncopyable
{
public:
    explicit basic_iso9660_file_source_impl(const Source& src)
    {
        // ...

        if (is_joliet)
        {
            typedef iso9660_file_reader<Source,joliet_id> parser_type;
            parser_.reset(new parser_type(src_, volume_desc));
        }
        else
        {
            typedef iso9660_file_reader<Source,iso9660_id> parser_type;
            parser_.reset(new parser_type(src_, volume_desc));
        }
    }

private:
    // ...

    std::auto_ptr<iso9660_file_reader_base> parser_;
};

のように、個々のフォーマット用にiso9660_file_sourceの実装を持つようにしました。
コードの重複が少し多くなっていますが、分岐の頻度は下がっているはずなので、ファイル数が多い場合はこちらの方が速いのではないかと思います。
余計にコードが複雑になった気もしますが、、、。