Exemple #1
0
bool CFI::CompileCFI(const string &str)
{
    // strip the 'epubcfi(...)' wrapping
    string cfi(str);
    if ( str.find("epubcfi(") == 0 )
    {
        cfi = cfi.substr(8, (str.size()-1)-8);
    }
    else if ( str.size() == 0 || str[0] != '/' )
    {
        // invalid CFI
        return false;
    }
    
    StringList rangePieces = RangedCFIComponents(cfi);
    if ( rangePieces.size() != 1 && rangePieces.size() != 3 )
        return false;
    
    if ( CompileComponentsToList(CFIComponentStrings(rangePieces[0]), &_components) == false )
        return false;
    
    if ( rangePieces.size() == 3 )
    {
        if ( CompileComponentsToList(CFIComponentStrings(rangePieces[1]), &_rangeStart) == false )
            return false;
        if ( CompileComponentsToList(CFIComponentStrings(rangePieces[2]), &_rangeEnd) == false )
            return false;
        
        // now sanity-check the range delimiters:
        
        // neither should be empty
        if ( _rangeStart.empty() || _rangeEnd.empty() )
            return false;
        
        // check the offsets at the end of each— they should be the same type
        if ( (_rangeStart.back().flags & Component::OffsetsMask) != (_rangeEnd.back().flags & Component::OffsetsMask) )
            return false;
        
        // where the delimiters' component ranges overlap, start must be <= end
        auto maxsz = std::max(_rangeStart.size(), _rangeEnd.size());
        bool inequalNodeIndexFound = false;
        for ( decltype(maxsz) i = 0; i < maxsz; i++ )
        {
            if ( _rangeStart[i].nodeIndex > _rangeEnd[i].nodeIndex )
                return false;
            else if ( !inequalNodeIndexFound && _rangeStart[i].nodeIndex < _rangeEnd[i].nodeIndex )
                inequalNodeIndexFound = true;
        }
        
        // if the two ranges are equal aside from their offsets, the end offset must be > the start offset
        if ( !inequalNodeIndexFound && _rangeStart.size() == _rangeEnd.size() )
        {
            Component &s = _rangeStart.back(), &e = _rangeEnd.back();
            if ( s.HasCharacterOffset() && s.characterOffset > e.characterOffset )
            {
                return false;
            }
            else
            {
                if ( s.HasTemporalOffset() && s.temporalOffset > e.temporalOffset )
                    return false;
                if ( s.HasSpatialOffset() && s.spatialOffset > e.spatialOffset )
                    return false;
            }
        }
        
        _options |= RangeTriplet;
    }
    
    return true;
}
bool CFI::CompileCFI(const string &str)
{
    // strip the 'epubcfi(...)' wrapping
    string cfi(str);
    if ( str.find("epubcfi(") == 0 )
    {
        cfi = cfi.substr(8, (str.size()-1)-8);
    }
    else if ( str.size() == 0 )
    {
        HandleError(EPUBError::CFIParseFailed, "Empty CFI string");
        return false;
    }
    else if ( str[0] != '/' )
    {
        HandleError(EPUBError::CFINonSlashStartCharacter);
    }
    
    StringList rangePieces = RangedCFIComponents(cfi);
    if ( rangePieces.size() != 1 && rangePieces.size() != 3 )
    {
        HandleError(EPUBError::CFIRangeComponentCountInvalid, _Str("Expected 1 or 3 range components, got ", rangePieces.size()));
        if ( rangePieces.size() == 0 )
            return false;
    }
    
    if ( CompileComponentsToList(CFIComponentStrings(rangePieces[0]), &_components) == false )
        return false;
    
    if ( rangePieces.size() >= 3 )
    {
        if ( CompileComponentsToList(CFIComponentStrings(rangePieces[1]), &_rangeStart) == false )
            return false;
        if ( CompileComponentsToList(CFIComponentStrings(rangePieces[2]), &_rangeEnd) == false )
            return false;
        
        // now sanity-check the range delimiters:
        
        // neither should be empty
        if ( _rangeStart.empty() || _rangeEnd.empty() )
        {
            HandleError(EPUBError::CFIRangeInvalid, "One of the supplied range components was empty.");
            return false;
        }
        
        // check the offsets at the end of each— they should be the same type
        if ( (_rangeStart.back().flags & Component::OffsetsMask) != (_rangeEnd.back().flags & Component::OffsetsMask) )
        {
            HandleError(EPUBError::CFIRangeInvalid, "Offsets at the end of range components are of different types.");
            return false;
        }
        
        // ensure that there are no side-bias values
        if ( (_rangeStart.back().sideBias != SideBias::Unspecified) ||
             (_rangeEnd.back().sideBias != SideBias::Unspecified) )
        {
            HandleError(EPUBError::CFIRangeContainsSideBias);
            // can safely ignore this one
        }
        
        // where the delimiters' component ranges overlap, start must be <= end
        auto maxsz = std::max(_rangeStart.size(), _rangeEnd.size());
        bool inequalNodeIndexFound = false;
        for ( decltype(maxsz) i = 0; i < maxsz; i++ )
        {
            if ( _rangeStart[i].nodeIndex > _rangeEnd[i].nodeIndex )
            {
                HandleError(EPUBError::CFIRangeInvalid, "Range components appear to be out of order.");
            }
            else if ( !inequalNodeIndexFound && _rangeStart[i].nodeIndex < _rangeEnd[i].nodeIndex )
            {
                inequalNodeIndexFound = true;
            }
        }
        
        // if the two ranges are equal aside from their offsets, the end offset must be > the start offset
        if ( !inequalNodeIndexFound && _rangeStart.size() == _rangeEnd.size() )
        {
            Component &s = _rangeStart.back(), &e = _rangeEnd.back();
            if ( s.HasCharacterOffset() && s.characterOffset > e.characterOffset )
            {
                HandleError(EPUBError::CFIRangeInvalid, "Range components appear to be out of order.");
            }
            else
            {
                if ( s.HasTemporalOffset() && s.temporalOffset > e.temporalOffset )
                    HandleError(EPUBError::CFIRangeInvalid, "Range components appear to be out of order.");
                if ( s.HasSpatialOffset() && s.spatialOffset > e.spatialOffset )
                    HandleError(EPUBError::CFIRangeInvalid, "Range components appear to be out of order.");
            }
        }
        
        _options |= RangeTriplet;
    }
    
    return true;
}