PageRenderTime 350ms CodeModel.GetById 90ms app.highlight 175ms RepoModel.GetById 78ms app.codeStats 0ms

/mordor/streams/cat.cpp

http://github.com/mozy/mordor
C++ | 103 lines | 93 code | 9 blank | 1 comment | 28 complexity | 746a23cbb4a72493333e60f63a9ff253 MD5 | raw file
  1// Copyright (c) 2009 - Mozy, Inc.
  2
  3#include "cat.h"
  4
  5#include "mordor/assert.h"
  6
  7namespace Mordor {
  8
  9CatStream::CatStream(const std::vector<Stream::ptr> &streams)
 10: m_streams(streams),
 11  m_seekable(true),
 12  m_size(0ll),
 13  m_pos(0ll)
 14{
 15    m_it = m_streams.begin();
 16    for (std::vector<Stream::ptr>::iterator it = m_streams.begin();
 17        it != m_streams.end();
 18        ++it) {
 19        if (!(*it)->supportsSeek()) {
 20            m_seekable = false;
 21            if (m_size == -1ll)
 22                break;
 23        }
 24        if (!(*it)->supportsSize()) {
 25            m_seekable = false;
 26            m_size = -1ll;
 27            break;
 28        } else {
 29            m_size += (*it)->size();
 30        }
 31    }
 32}
 33
 34size_t
 35CatStream::read(Buffer &buffer, size_t length)
 36{
 37    MORDOR_ASSERT(length != 0);
 38    if (m_it == m_streams.end())
 39        return 0;
 40    while (true) {
 41        size_t result = (*m_it)->read(buffer, length);
 42        m_pos += result;
 43        if (result == 0) {
 44            if (++m_it == m_streams.end())
 45                return 0;
 46            if ((*m_it)->supportsSeek())
 47                (*m_it)->seek(0);
 48            continue;
 49        }
 50        return result;
 51    }
 52}
 53
 54long long
 55CatStream::seek(long long offset, Anchor anchor)
 56{
 57    if (offset == 0 && anchor == CURRENT)
 58        return m_pos;
 59    MORDOR_ASSERT(m_seekable);
 60    long long newPos = 0;
 61    switch (anchor) {
 62        case BEGIN:
 63            newPos = offset;
 64            break;
 65        case CURRENT:
 66            newPos = m_pos + offset;
 67            break;
 68        case END:
 69            newPos = m_size + offset;
 70            break;
 71        default:
 72            MORDOR_NOTREACHED();
 73    }
 74    if (newPos < 0) {
 75        MORDOR_THROW_EXCEPTION(std::invalid_argument("Can't seek below 0"));
 76    } else if (newPos >= m_size) {
 77        MORDOR_THROW_EXCEPTION(std::invalid_argument("Can't seek above max size"));
 78    }
 79
 80    long long cursor = 0;
 81    for (std::vector<Stream::ptr>::iterator it = m_streams.begin();
 82        it != m_streams.end();
 83        ++it) {
 84        long long size = (*it)->size();
 85        if (newPos < cursor + size) {
 86            m_it = it;
 87            (*m_it)->seek(newPos - cursor);
 88            break;
 89        }
 90        cursor += size;
 91    }
 92    m_pos = newPos;
 93    return m_pos;
 94}
 95
 96long long
 97CatStream::size()
 98{
 99    MORDOR_ASSERT(m_size != -1ll);
100    return m_size;
101}
102
103}