1. 4FIPS
  2. PHOTOS
  3. VIDEOS
  4. APPS
  5. CODE
  6. FORUMS
  7. ABOUT
/*---{fips-meta:file-header:public}-------------------------------------*\
| o     _______ __         _______  _   ______           __            o |
|      |    ___|__|.-----.|     __|| | |      |.-----.--|  |.-----.      |
|      |    ___|  ||  _  ||__     ||_| |   ---||  _  |  _  ||  -__|      |
|      |___|   |__||   __||_______|    |______||_____|_____||_____|      |
|       FipS' CODE |__| > > > > > > > > > > > > > > > > > > > > > >      |
|    (c) 2004-13 +++ Filip Stoklas, aka FipS, http://www.4FipS.com +++   |
| o         THIS CODE IS FREE - LICENSED UNDER THE MIT LICENSE         o |
\*----------------------------------------------------------------------*/
#include "bu_directory_ref.h"

namespace fs { namespace bundle {

Directory_ref::Directory_ref(fo::Bytes_ref dir_blob):
_filelist(nullptr),
_filenames(nullptr)
{
    using namespace blob::directory;

    FS_ASSERT(!dir_blob.empty());
    const Directory *dir = reinterpret_cast<const Directory *>(dir_blob.data());
    const Blob &blob = dir->blob;
    FS_ASSERT(tag(blob) == Tag('4', 'D', 'I', 'R'));
    FS_ASSERT(blob.size == dir_blob.size());
    const Block &header_block = dir->header_block;
    const Header *header = reinterpret_cast<const Header *>(dir_blob.data() + header_block.offset);
    FS_ASSERT(header->version == 1);
    const Block &filelist_block = dir->filelist_block;
    const Filelist *filelist = reinterpret_cast<const Filelist *>(dir_blob.data() + filelist_block.offset);
    const Block &filenames_block = dir->filenames_block;
    const Filenames *filenames = reinterpret_cast<const Filenames *>(dir_blob.data() + filenames_block.offset);

    _filelist = filelist;
    _filenames = filenames;
}

size_t Directory_ref::num_files() const
{
    return _filelist->num_files;
}

fo::String_ref Directory_ref::file(Index index) const
{
    FS_ASSERT(index.in_range(0, num_files()));
    const size_t fname_offset = _filelist->files[index.pos()].fname_offset;
    const char *fname = _filenames->data + fname_offset;
    return fname;
}

bool Directory_ref::has_file(fo::String_ref fname) const
{
    return find_file(fname).valid();
}

Directory_ref::Index Directory_ref::find_file(fo::String_ref fname) const
{
    using namespace blob::directory;

    // the linear search below, will be later replaced by a binary search,
    // using std::lower_bound(), but we need to implement an iterator for
    // 'blob::File' first, the sequence is always sorted...

    const char *fnames = _filenames->data;
    for(size_t i = 0, n = _filelist->num_files; i < n; ++i)
    {
        const File &cur_file = _filelist->files[i];
        const char *cur_fname = fnames + cur_file.fname_offset;
        if(strcmp(cur_fname, fname.cstr()) == 0)
            return Index::make(i);
    }

    return Index::invalid();
}

}} // namespace fs::bundle