| 85 | using namespace IECore; |
| 86 | |
| 87 | void IECore::findSequences( const std::vector< std::string > &names, std::vector< FileSequencePtr > &sequences, size_t minSequenceSize ) |
| 88 | { |
| 89 | sequences.clear(); |
| 90 | |
| 91 | /// this matches names of the form $prefix$frameNumber$suffix |
| 92 | /// placing each of those in a group of the resulting match. |
| 93 | /// both $prefix and $suffix may be the empty string and $frameNumber |
| 94 | /// may be preceded by a minus sign. |
| 95 | /// It also matches file extensions with 3 or 4 characters that contain numbers (for example: CR2, MP3 ) |
| 96 | boost::regex matchExpression( std::string( "^([^#]*?)(-?[0-9]+)([^0-9#]*|[^0-9#]*\\.[a-zA-Z]{2,3}[0-9])$" ) ); |
| 97 | |
| 98 | /// build a mapping from ($prefix, $suffix) to a list of $frameNumbers |
| 99 | typedef std::vector< std::string > Frames; |
| 100 | typedef std::map< std::pair< std::string, std::string >, Frames > SequenceMap; |
| 101 | |
| 102 | SequenceMap sequenceMap; |
| 103 | |
| 104 | for ( std::vector< std::string >::const_iterator it = names.begin(); it != names.end(); ++it ) |
| 105 | { |
| 106 | boost::smatch matches; |
| 107 | if ( boost::regex_match( *it, matches, matchExpression ) ) |
| 108 | { |
| 109 | sequenceMap[ |
| 110 | SequenceMap::key_type( |
| 111 | std::string( matches[1].first, matches[1].second ), |
| 112 | std::string( matches[3].first, matches[3].second ) |
| 113 | ) |
| 114 | ].push_back( std::string( matches[2].first, matches[2].second ) ); |
| 115 | } |
| 116 | } |
| 117 | |
| 118 | for ( SequenceMap::const_iterator it = sequenceMap.begin(); it != sequenceMap.end(); ++it ) |
| 119 | { |
| 120 | const SequenceMap::key_type &fixes = it->first; |
| 121 | const Frames &frames = it->second; |
| 122 | // todo: could be more efficient by writing a custom comparison function that uses indexes |
| 123 | // into the const Frames vector rather than duplicating the strings and sorting them directly |
| 124 | Frames sortedFrames = frames; |
| 125 | std::sort( sortedFrames.begin(), sortedFrames.end() ); |
| 126 | |
| 127 | /// in diabolical cases the elements of frames may not all have the same padding |
| 128 | /// so we'll sort them out into padded and unpadded frame sequences here, by creating |
| 129 | /// a map of padding->list of frames. unpadded things will be considered to have a padding |
| 130 | /// of 1. |
| 131 | typedef std::vector< FrameList::Frame > NumericFrames; |
| 132 | typedef std::map< unsigned int, NumericFrames > PaddingToFramesMap; |
| 133 | PaddingToFramesMap paddingToFrames; |
| 134 | for ( Frames::const_iterator fIt = sortedFrames.begin(); fIt != sortedFrames.end(); ++fIt ) |
| 135 | { |
| 136 | std::string frame = *fIt; |
| 137 | int sign = 1; |
| 138 | |
| 139 | assert( frame.size() ); |
| 140 | if ( *frame.begin() == '-' ) |
| 141 | { |
| 142 | frame = frame.substr( 1, frame.size() - 1 ); |
| 143 | sign = -1; |
| 144 | } |