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; }