| /** @file | |
| Licensed to the Apache Software Foundation (ASF) under one | |
| or more contributor license agreements. See the NOTICE file | |
| distributed with this work for additional information | |
| regarding copyright ownership. The ASF licenses this file | |
| to you under the Apache License, Version 2.0 (the | |
| "License"); you may not use this file except in compliance | |
| with the License. You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, software | |
| distributed under the License is distributed on an "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| See the License for the specific language governing permissions and | |
| limitations under the License. | |
| */ | |
| #include "Range.h" | |
| #include "slice.h" | |
| #include <algorithm> | |
| #include <cinttypes> | |
| #include <cctype> | |
| #include <cstdio> | |
| #include <cstring> | |
| bool | |
| Range::isValid() const | |
| { | |
| return m_beg < m_end && (0 <= m_beg || 0 == m_end); | |
| } | |
| int64_t | |
| Range::size() const | |
| { | |
| return m_end - m_beg; | |
| } | |
| bool | |
| Range::fromStringClosed(char const *const rangestr) | |
| { | |
| static char const *const BYTESTR = "bytes="; | |
| static size_t const BYTESTRLEN = strlen(BYTESTR); | |
| m_beg = m_end = -1; // initialize invalid | |
| // make sure this is in byte units | |
| if (0 != strncmp(BYTESTR, rangestr, BYTESTRLEN)) { | |
| return false; | |
| } | |
| // advance past any white space | |
| char const *pstr = rangestr + BYTESTRLEN; | |
| while ('\0' != *pstr && isblank(*pstr)) { | |
| ++pstr; | |
| } | |
| // rip out any whitespace | |
| char rangebuf[1024]; | |
| int const rangelen = sizeof(rangebuf); | |
| char *pbuf = rangebuf; | |
| while ('\0' != *pstr && (pbuf - rangebuf) < rangelen) { | |
| if (!isblank(*pstr)) { | |
| *pbuf++ = *pstr; | |
| } | |
| ++pstr; | |
| } | |
| *pbuf = '\0'; | |
| int const rlen = (pbuf - rangebuf); | |
| int consumed = 0; | |
| // last 'n' bytes - result in range with negative begin and 0 end | |
| int64_t endbytes = 0; | |
| char const *const fmtend = "-%" PRId64 "%n"; | |
| int const fieldsend = sscanf(rangebuf, fmtend, &endbytes, &consumed); | |
| if (1 == fieldsend) { | |
| if (rlen == consumed) { | |
| m_beg = -endbytes; | |
| m_end = 0; | |
| return true; | |
| } else { | |
| return false; | |
| } | |
| } | |
| // normal range <front>-<back> | |
| char const *const fmtclosed = "%" PRId64 "-%" PRId64 "%n"; | |
| int64_t front = 0; | |
| int64_t back = 0; | |
| int const fieldsclosed = sscanf(rangebuf, fmtclosed, &front, &back, &consumed); | |
| if (2 == fieldsclosed) { | |
| if (0 <= front && front <= back && rlen == consumed) { | |
| m_beg = front; | |
| m_end = back + 1; | |
| return true; | |
| } else { | |
| return false; | |
| } | |
| } | |
| front = 0; | |
| char const *const fmtbeg = "%" PRId64 "-%n"; | |
| int const fieldsbeg = sscanf(rangebuf, fmtbeg, &front, &consumed); | |
| if (1 == fieldsbeg) { | |
| if (rlen == consumed) { | |
| m_beg = front; | |
| m_end = Range::maxval; | |
| return true; | |
| } else { | |
| return false; | |
| } | |
| } | |
| return false; | |
| } // parseRange | |
| bool | |
| Range::toStringClosed(char *const bufstr, | |
| int *const buflen // returns actual bytes used | |
| ) const | |
| { | |
| if (!isValid()) { | |
| if (0 < *buflen) { | |
| bufstr[0] = '\0'; | |
| } | |
| *buflen = 0; | |
| return false; | |
| } | |
| int const lenin = *buflen; | |
| if (m_end <= Range::maxval) { | |
| *buflen = snprintf(bufstr, lenin, "bytes=%" PRId64 "-%" PRId64, m_beg, m_end - 1); | |
| } else { | |
| *buflen = snprintf(bufstr, lenin, "bytes=%" PRId64 "-", m_beg); | |
| } | |
| return (0 < *buflen && *buflen < lenin); | |
| } | |
| int64_t | |
| Range::firstBlockFor(int64_t const blocksize) const | |
| { | |
| if (0 < blocksize && isValid()) { | |
| return std::max(static_cast<int64_t>(0), m_beg / blocksize); | |
| } else { | |
| return -1; | |
| } | |
| } | |
| int64_t | |
| Range::lastBlockFor(int64_t const blocksize) const | |
| { | |
| if (0 < blocksize && isValid()) { | |
| return std::max(static_cast<int64_t>(0), (m_end - 1) / blocksize); | |
| } else { | |
| return -1; | |
| } | |
| } | |
| Range | |
| Range::intersectedWith(Range const &other) const | |
| { | |
| return Range(std::max(m_beg, other.m_beg), std::min(m_end, other.m_end)); | |
| } | |
| bool | |
| Range::blockIsInside(int64_t const blocksize, int64_t const blocknum) const | |
| { | |
| Range const blockrange(blocksize * blocknum, blocksize * (blocknum + 1)); | |
| Range const isec(blockrange.intersectedWith(*this)); | |
| return isec.isValid(); | |
| } | |
| int64_t | |
| Range::skipBytesForBlock(int64_t const blocksize, int64_t const blocknum) const | |
| { | |
| int64_t const blockstart(blocksize * blocknum); | |
| if (m_beg < blockstart) { | |
| return 0; | |
| } else { | |
| return m_beg - blockstart; | |
| } | |
| } | |
| bool | |
| Range::isEndBytes() const | |
| { | |
| return m_beg < 0 && 0 == m_end; | |
| } |