bool CFI::Component::operator==(const ePub3::CFI::Component &o) const { // holy compound statements Batman! if ( (flags != o.flags) || (nodeIndex != o.nodeIndex) || (HasQualifier() && qualifier != o.qualifier) || (HasCharacterOffset() && characterOffset != o.characterOffset) || (HasSpatialOffset() && (spatialOffset.x != o.spatialOffset.x || spatialOffset.y != o.spatialOffset.y)) || (HasTemporalOffset() && temporalOffset != o.temporalOffset) || (HasTextQualifier() && textQualifier != o.textQualifier) ) { return false; } return true; }
void CFI::AppendComponents(std::stringstream& builder, ComponentList::const_iterator start, ComponentList::const_iterator end) { auto pos = start; while ( pos != end ) { builder << "/" << pos->nodeIndex; if ( pos->HasQualifier() ) { builder << "[" << pos->qualifier << "]"; } if ( pos->HasCharacterOffset() ) { builder << ":" << pos->characterOffset; if ( pos->HasTextQualifier() ) { builder << "[" << pos->textQualifier << "]"; } } else { if ( pos->HasTemporalOffset() ) { builder << "~" << pos->temporalOffset; } if ( pos->HasSpatialOffset() ) { builder << "@" << pos->spatialOffset.x << ":" << pos->spatialOffset.y; } } if ( pos->IsIndirector() ) { builder << "!"; } ++pos; } }
void CFI::Component::Parse(const string &str) { if ( str.empty() ) throw std::invalid_argument("Empty string supplied to CFI::Component"); std::string utf8 = str.stl_str(); std::istringstream iss(utf8); // read an integer iss >> nodeIndex; if ( nodeIndex == 0 && iss.fail() ) throw std::invalid_argument(_Str("No node value at start of CFI::Component string '", str, "'")); while ( !iss.eof() ) { char next = 0; iss >> next; switch ( next ) { case '[': { size_t pos = static_cast<size_t>(iss.tellg()); iss.ignore(std::numeric_limits<std::streamsize>::max(), ']'); size_t end = ((size_t)iss.tellg()) - 1; if ( iss.eof() ) throw std::invalid_argument(_Str("Invalid string supplied to CFI::Component: ", str)); if ( characterOffset != 0 ) { // this is a text qualifier textQualifier = utf8.substr(pos, end-pos); flags |= TextQualifier; } else { // it's a position qualifier qualifier = utf8.substr(pos, end-pos); flags |= Qualifier; } break; } case '~': { // character offsets and spatial/temporal offsets are mutually exclusive if ( HasCharacterOffset() ) break; // read a numeral iss >> temporalOffset; flags |= TemporalOffset; break; } case '@': { // character offsets and spatial/temporal offsets are mutually exclusive if ( HasCharacterOffset() ) break; // two floats, separated by a colon float x, y; // read x iss >> x; // check for and skip delimiter if ( iss.peek() != ':' ) break; iss.ignore(1); // read y iss >> y; spatialOffset.x = x; spatialOffset.y = y; flags |= SpatialOffset; break; } case ':': { // character offsets and spatial/temporal offsets are mutually exclusive if ( HasSpatialTemporalOffset() ) break; iss >> characterOffset; flags |= CharacterOffset; break; } case '!': { // must be the last character, and no offsets if ( ((int)iss.peek()) != -1 || HasSpatialTemporalOffset() || HasCharacterOffset() ) break; flags |= Indirector; break; } default: break; } } }
void CFI::Component::Parse(const string &str) { if ( str.empty() ) { HandleError(EPUBError::CFIParseFailed, "Empty string supplied to CFI::Component"); return; } std::string utf8 = str.stl_str(); std::istringstream iss(utf8); // read an integer iss >> nodeIndex; if ( nodeIndex == 0 && iss.fail() ) { HandleError(EPUBError::CFIParseFailed, _Str("No node value at start of CFI::Component string '", str, "'")); return; } while ( !iss.eof() ) { char next = 0; iss >> next; switch ( next ) { case '[': { size_t pos = static_cast<size_t>(iss.tellg()); iss.ignore(std::numeric_limits<std::streamsize>::max(), ']'); size_t end = ((size_t)iss.tellg()) - 1; if ( iss.eof() ) { HandleError(EPUBError::CFIParseFailed); return; } if ( characterOffset != 0 ) { // this is a text qualifier flags |= TextQualifier; std::string sub = utf8.substr(pos, end-pos); // is there a side-bias? auto biasPos = sub.find(";s="); if ( biasPos == std::string::npos ) { textQualifier = std::move(sub); } else { textQualifier = sub.substr(0, biasPos); if ( sub.size() > biasPos + 3 ) { switch ( sub[biasPos+3] ) { case 'b': sideBias = SideBias::Before; break; case 'a': sideBias = SideBias::After; break; default: sideBias = SideBias::Unspecified; break; } } } } else { // it's a position qualifier qualifier = utf8.substr(pos, end-pos); flags |= Qualifier; } break; } case '~': { // character offsets and spatial/temporal offsets are mutually exclusive if ( HasCharacterOffset() ) break; // read a numeral iss >> temporalOffset; flags |= TemporalOffset; break; } case '@': { // character offsets and spatial/temporal offsets are mutually exclusive if ( HasCharacterOffset() ) break; // two floats, separated by a colon float x, y; // read x iss >> x; // check for and skip delimiter if ( iss.peek() != ':' ) break; iss.ignore(1); // read y iss >> y; spatialOffset.x = x; spatialOffset.y = y; flags |= SpatialOffset; break; } case ':': { // character offsets and spatial/temporal offsets are mutually exclusive if ( HasSpatialTemporalOffset() ) break; iss >> characterOffset; flags |= CharacterOffset; break; } case '!': { // must be the last character, and no offsets if ( ((int)iss.peek()) != -1 || HasSpatialTemporalOffset() || HasCharacterOffset() ) break; flags |= Indirector; break; } default: break; } } }