gff_reader.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:24k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: gff_reader.cpp,v $
  4.  * PRODUCTION Revision 1000.1  2004/06/01 19:46:20  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.6
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: gff_reader.cpp,v 1000.1 2004/06/01 19:46:20 gouriano Exp $
  10. * ===========================================================================
  11. *
  12. *                            PUBLIC DOMAIN NOTICE
  13. *               National Center for Biotechnology Information
  14. *
  15. *  This software/database is a "United States Government Work" under the
  16. *  terms of the United States Copyright Act.  It was written as part of
  17. *  the author's official duties as a United States Government employee and
  18. *  thus cannot be copyrighted.  This software/database is freely available
  19. *  to the public for use. The National Library of Medicine and the U.S.
  20. *  Government have not placed any restriction on its use or reproduction.
  21. *
  22. *  Although all reasonable efforts have been taken to ensure the accuracy
  23. *  and reliability of the software and data, the NLM and the U.S.
  24. *  Government do not and cannot warrant the performance or results that
  25. *  may be obtained by using this software or data. The NLM and the U.S.
  26. *  Government disclaim all warranties, express or implied, including
  27. *  warranties of performance, merchantability or fitness for any particular
  28. *  purpose.
  29. *
  30. *  Please cite the author in any work or product based on this material.
  31. *
  32. * ===========================================================================
  33. *
  34. * Authors:  Aaron Ucko, Wratko Hlavina
  35. *
  36. * File Description:
  37. *   Reader for GFF (including GTF) files.
  38. *
  39. * ===========================================================================
  40. */
  41. #include <ncbi_pch.hpp>
  42. #include <objtools/readers/gff_reader.hpp>
  43. #include <corelib/ncbitime.hpp>
  44. #include <corelib/ncbiutil.hpp>
  45. #include <serial/iterator.hpp>
  46. #include <objects/general/Date.hpp>
  47. #include <objects/seq/Seq_annot.hpp>
  48. #include <objects/seq/Seq_descr.hpp>
  49. #include <objects/seq/Seq_inst.hpp>
  50. #include <objects/seq/Seqdesc.hpp>
  51. #include <objects/seqfeat/Cdregion.hpp>
  52. #include <objects/seqfeat/Gb_qual.hpp>
  53. #include <objects/seqloc/Seq_interval.hpp>
  54. #include <objects/seqloc/Seq_point.hpp>
  55. #include <objects/seqset/Bioseq_set.hpp>
  56. #include <objtools/readers/readfeat.hpp>
  57. #include <algorithm>
  58. #include <ctype.h>
  59. BEGIN_NCBI_SCOPE
  60. BEGIN_SCOPE(objects)
  61. CRef<CSeq_entry> CGFFReader::Read(CNcbiIstream& in, TFlags flags)
  62. {
  63.     x_Reset();
  64.     m_Flags  = flags;
  65.     m_Stream = &in;
  66.     string line;
  67.     while (x_GetNextLine(line)) {
  68.         if (NStr::StartsWith(line, "##")) {
  69.             x_ParseStructuredComment(line);
  70.         } else if (NStr::StartsWith(line, "#")) {
  71.             // regular comment; ignore
  72.         } else {
  73.             CRef<SRecord> record = x_ParseFeatureInterval(line);
  74.             if (record) {
  75.                 string id = x_FeatureID(*record);
  76.                 if (id.empty()) {
  77.                     x_PlaceFeature(*x_ParseRecord(*record), *record);
  78.                 } else {
  79.                     CRef<SRecord>& match = m_DelayedFeats[id];
  80.                     if (match) {
  81.                         x_MergeRecords(*match, *record);
  82.                     } else {
  83.                         match.Reset(record);
  84.                     }
  85.                 }
  86.             }
  87.         }
  88.     }
  89.     ITERATE (TDelayedFeats, it, m_DelayedFeats) {
  90.         x_PlaceFeature(*x_ParseRecord(*it->second), *it->second);
  91.     }
  92.     CRef<CSeq_entry> tse(m_TSE); // need to save before resetting.
  93.     x_Reset();
  94.     return tse;
  95. }
  96. void CGFFReader::x_Warn(const string& message, unsigned int line)
  97. {
  98.     if (line) {
  99.         ERR_POST(Warning << message << " [GFF input, line " << line << ']');
  100.     } else {
  101.         ERR_POST(Warning << message << " [GFF input]");
  102.     }
  103. }
  104. void CGFFReader::x_Reset(void)
  105. {
  106.     m_TSE.Reset(new CSeq_entry);
  107.     m_SeqNameCache.clear();
  108.     m_SeqCache.clear();
  109.     m_DelayedFeats.clear();
  110.     m_DefMol.erase();
  111.     m_LineNumber = 0;
  112. }
  113. bool CGFFReader::x_GetNextLine(string& line)
  114. {
  115.     ++m_LineNumber;
  116.     return NcbiGetlineEOL(*m_Stream, line)  ||  !line.empty();
  117. }
  118. void CGFFReader::x_ParseStructuredComment(const string& line)
  119. {
  120.     vector<string> v;
  121.     NStr::Tokenize(line, "# t", v, NStr::eMergeDelims);
  122.     if (v[0] == "date"  &&  v.size() > 1) {
  123.         x_ParseDateComment(v[1]);
  124.     } else if (v[0] == "type"  &&  v.size() > 1) {
  125.         x_ParseTypeComment(v[1], v.size() > 2 ? v[2] : kEmptyStr);
  126.     }
  127.     // etc.
  128. }
  129. void CGFFReader::x_ParseDateComment(const string& date)
  130. {
  131.     try {
  132.         CRef<CSeqdesc> desc(new CSeqdesc);
  133.         desc->SetUpdate_date().SetToTime(CTime(date, "Y-M-D"),
  134.                                          CDate::ePrecision_day);
  135.         m_TSE->SetSet().SetDescr().Set().push_back(desc);
  136.     } catch (CTimeException& e) {
  137.         x_Warn(string("Bad ISO date: ") + e.what(), x_GetLineNumber());
  138.     }
  139. }
  140. void CGFFReader::x_ParseTypeComment(const string& moltype,
  141.                                     const string& seqname)
  142. {
  143.     if (seqname.empty()) {
  144.         m_DefMol = moltype;
  145.     } else {
  146.         // automatically adds to m_TSE if new
  147.         x_ResolveID(*x_ResolveSeqName(seqname), moltype);
  148.     }
  149. }
  150. CRef<CGFFReader::SRecord>
  151. CGFFReader::x_ParseFeatureInterval(const string& line)
  152. {
  153.     vector<string> v;
  154.     bool           misdelimited = false;
  155.     NStr::Tokenize(line, "t", v, NStr::eNoMergeDelims);
  156.     if (v.size() < 8) {
  157.         NStr::Tokenize(line, " t", v, NStr::eMergeDelims);
  158.         if (v.size() < 8) {
  159.             x_Warn("Skipping line due to insufficient fields",
  160.                    x_GetLineNumber());
  161.             return null;
  162.         } else {
  163.             x_Warn("Bad delimiters (should use tabs)", x_GetLineNumber());
  164.             misdelimited = true;
  165.         }
  166.     } else {
  167.         // XXX - warn about extra fields (if any), but only if they're
  168.         // not comments
  169.         v.resize(9);
  170.     }
  171.     CRef<SRecord> record(x_NewRecord());
  172.     string        accession;
  173.     TSeqPos       from = 0, to = numeric_limits<TSeqPos>::max();
  174.     ENa_strand    strand = eNa_strand_unknown;
  175.     accession      = v[0];
  176.     record->source = v[1];
  177.     record->key    = v[2];
  178.     try {
  179.         from = NStr::StringToUInt(v[3]) - 1;
  180.     } catch (std::exception& e) {
  181.         x_Warn(string("Bad FROM position: ") + e.what(), x_GetLineNumber());
  182.     }
  183.     try {
  184.         to = NStr::StringToUInt(v[4]) - 1;
  185.     } catch (std::exception& e) {
  186.         x_Warn(string("Bad TO position: ") + e.what(), x_GetLineNumber());
  187.     }
  188.     record->score = v[5];
  189.     if (v[6] == "+") {
  190.         strand = eNa_strand_plus;
  191.     } else if (v[6] == "-") {
  192.         strand = eNa_strand_minus;
  193.     } else if (v[6] != ".") {
  194.         x_Warn("Bad strand " + v[6] + " (should be [+-.])", x_GetLineNumber());
  195.     }
  196.     if (v[7] == "0"  ||  v[7] == "1"  ||  v[7] == "2") {
  197.         record->frame = v[7][0] - '0';
  198.     } else if (v[7] == ".") {
  199.         record->frame = -1;
  200.     } else {
  201.         x_Warn("Bad frame " + v[7] + " (should be [012.])", x_GetLineNumber());
  202.         record->frame = -1;
  203.     }
  204.     {{
  205.         SRecord::SSubLoc subloc;
  206.         subloc.accession = accession;
  207.         subloc.strand    = strand;
  208.         subloc.ranges.insert(TSeqRange(from, to));
  209.         record->loc.push_back(subloc);
  210.     }}
  211.    
  212.     string         attr_last_value;
  213.     vector<string> attr_values;
  214.     char           quote_char = 0;
  215.     for (SIZE_TYPE i = 8;  i < v.size();  ++i) {
  216.         string s = v[i] + ' ';
  217.         if ( !misdelimited  &&  i > 8) {
  218.             SIZE_TYPE pos = s.find_first_not_of(" ");
  219.             if (pos != NPOS) {
  220.                 if (s[pos] == '#') {
  221.                     break;
  222.                 } else {
  223.                     x_Warn("Extra non-comment fields", x_GetLineNumber());
  224.                 }
  225.             } else {
  226.                 continue; // just spaces anyway...
  227.             }
  228.         }
  229.         SIZE_TYPE pos = 0;
  230.         while (pos < s.size()) {
  231.             SIZE_TYPE pos2;
  232.             if (quote_char) { // must be inside a value
  233.                 pos2 = s.find_first_of(" '"\", pos);
  234.                 _ASSERT(pos2 != NPOS); // due to trailing space
  235.                 if (s[pos2] == quote_char) {
  236.                     if (attr_values.empty()) {
  237.                         x_Warn("quoted attribute tag " + attr_last_value,
  238.                                x_GetLineNumber());
  239.                     }
  240.                     quote_char = 0;
  241.                     attr_last_value += s.substr(pos, pos2 - pos);
  242.                     try {
  243.                         attr_values.push_back(NStr::ParseEscapes
  244.                                               (attr_last_value));
  245.                     } catch (CStringException& e) {
  246.                         attr_values.push_back(attr_last_value);
  247.                         x_Warn(e.what() + (" in value of " + attr_values[0]),
  248.                                x_GetLineNumber());
  249.                     }
  250.                     attr_last_value.erase();
  251.                 } else if (s[pos2] == '\') {
  252.                     _VERIFY(++pos2 != s.size());
  253.                     attr_last_value += s.substr(pos, pos2 + 1 - pos);
  254.                 } else {
  255.                     attr_last_value += s.substr(pos, pos2 + 1 - pos);
  256.                 }
  257.             } else {
  258.                 pos2 = s.find_first_of(" #;"", pos); // also look for '?
  259.                 _ASSERT(pos2 != NPOS); // due to trailing space
  260.                 if (pos != pos2) {
  261.                     // grab and place the preceding token
  262.                     attr_last_value += s.substr(pos, pos2 - pos);
  263.                     attr_values.push_back(attr_last_value);
  264.                     attr_last_value.erase();
  265.                 }
  266.                 switch (s[pos2]) {
  267.                 case ' ':
  268.                     break;
  269.                 case '#':
  270.                     i = v.size();
  271.                     break;
  272.                 case ';':
  273.                     if (attr_values.empty()) {
  274.                         x_Warn("null attribute", x_GetLineNumber());
  275.                     } else {
  276.                         x_AddAttribute(*record, attr_values);
  277.                         attr_values.clear();
  278.                     }
  279.                     break;
  280.                 // NB: we don't currently search for single quotes.
  281.                 case '"': case ''':
  282.                     quote_char = s[pos2];
  283.                     break;
  284.                 default:
  285.                     _TROUBLE;
  286.                 }
  287.             }
  288.             pos = pos2 + 1;
  289.         }
  290.     }
  291.     if ( !attr_values.empty() ) {
  292.         x_Warn("unterminated attribute " + attr_values[0], x_GetLineNumber());
  293.         x_AddAttribute(*record, attr_values);
  294.     }
  295.     return record;
  296. }
  297. CRef<CSeq_feat> CGFFReader::x_ParseRecord(const SRecord& record)
  298. {
  299.     CRef<CSeq_feat> feat(CFeature_table_reader::CreateSeqFeat
  300.                          (record.key, *x_ResolveLoc(record.loc),
  301.                           CFeature_table_reader::fKeepBadKey));
  302.     if (record.frame >= 0  &&  feat->GetData().IsCdregion()) {
  303.         feat->SetData().SetCdregion().SetFrame
  304.             (static_cast<CCdregion::EFrame>(record.frame + 1));
  305.     }
  306.     ITERATE (SRecord::TAttrs, it, record.attrs) {
  307.         string tag = it->front();
  308.         string value;
  309.         switch (it->size()) {
  310.         case 1:
  311.             break;
  312.         case 2:
  313.             value = (*it)[1];
  314.             break;
  315.         default:
  316.             x_Warn("Ignoring extra fields in value of " + tag, record.line_no);
  317.             value = (*it)[1];
  318.             break;
  319.         }
  320.         if (x_GetFlags() & fGBQuals) {
  321.             if ( !(x_GetFlags() & fNoGTF) ) { // translate
  322.                 if (tag == "transcript_id") {
  323.                     //continue;
  324.                 } else if (tag == "gene_id") {
  325.                     tag = "gene";
  326.                     SIZE_TYPE colon = value.find(':');
  327.                     if (colon != NPOS) {
  328.                         value.erase(0, colon + 1);
  329.                     }
  330.                 } else if (tag == "exon_number") {
  331.                     tag = "number";
  332.                 }
  333.             }
  334.             CFeature_table_reader::AddFeatQual
  335.                 (feat, tag, value, CFeature_table_reader::fKeepBadKey);
  336.         } else { // don't attempt to parse, just treat as imported
  337.             CRef<CGb_qual> qual(new CGb_qual);
  338.             qual->SetQual(tag);
  339.             qual->SetVal(value);
  340.             feat->SetQual().push_back(qual);
  341.         }
  342.     }
  343.     return feat;
  344. }
  345. CRef<CSeq_loc> CGFFReader::x_ResolveLoc(const SRecord::TLoc& loc)
  346. {
  347.     CRef<CSeq_loc> seqloc(new CSeq_loc);
  348.     ITERATE (SRecord::TLoc, it, loc) {
  349.         CRef<CSeq_id> id = x_ResolveSeqName(it->accession);
  350.         ITERATE (set<TSeqRange>, range, it->ranges) {
  351.             CRef<CSeq_loc> segment(new CSeq_loc);
  352.             if (range->GetLength() == 1) {
  353.                 CSeq_point& pnt = segment->SetPnt();
  354.                 pnt.SetId   (*id);
  355.                 pnt.SetPoint(range->GetFrom());
  356.                 if (it->strand != eNa_strand_unknown) {
  357.                     pnt.SetStrand(it->strand);
  358.                 }
  359.             } else {
  360.                 CSeq_interval& si = segment->SetInt();
  361.                 si.SetId  (*id);
  362.                 si.SetFrom(range->GetFrom());
  363.                 si.SetTo  (range->GetTo());
  364.                 if (it->strand != eNa_strand_unknown) {
  365.                     si.SetStrand(it->strand);
  366.                 }
  367.             }
  368.             if (IsReverse(it->strand)) {
  369.                 seqloc->SetMix().Set().push_front(segment);
  370.             } else {
  371.                 seqloc->SetMix().Set().push_back(segment);
  372.             }
  373.         }
  374.     }
  375.     if (seqloc->GetMix().Get().size() == 1) {
  376.         return seqloc->SetMix().Set().front();
  377.     } else {
  378.         return seqloc;
  379.     }
  380. }
  381. void CGFFReader::x_AddAttribute(SRecord& record, vector<string>& attr)
  382. {
  383.     if (x_GetFlags() & fGBQuals) {
  384.         if (attr[0] == "gbkey"  &&  attr.size() == 2) {
  385.             record.key = attr[1];
  386.             return;
  387.         }
  388.     }
  389.     record.attrs.insert(attr);
  390. }
  391. string CGFFReader::x_FeatureID(const SRecord& record)
  392. {
  393.     if (x_GetFlags() & fNoGTF) {
  394.         return kEmptyStr;
  395.     }
  396.     static const vector<string> sc_GeneId(1, "gene_id");
  397.     SRecord::TAttrs::const_iterator gene_it
  398.         = record.attrs.lower_bound(sc_GeneId);
  399.     static const vector<string> sc_TranscriptId(1, "transcript_id");
  400.     SRecord::TAttrs::const_iterator transcript_it
  401.         = record.attrs.lower_bound(sc_TranscriptId);
  402.     static const vector<string> sc_ProteinId(1, "protein_id");
  403.     SRecord::TAttrs::const_iterator protein_it
  404.         = record.attrs.lower_bound(sc_ProteinId);
  405.     // concatenate our IDs from above, if found
  406.     string id;
  407.     if (gene_it != record.attrs.end()  &&
  408.         gene_it->front() == "gene_id") {
  409.         id += (*gene_it)[1];
  410.     }
  411.     if (transcript_it != record.attrs.end()  &&
  412.         transcript_it->front() == "transcript_id") {
  413.         if ( !id.empty() ) {
  414.             id += ' ';
  415.         }
  416.         id += (*transcript_it)[1];
  417.     }
  418.     if (protein_it != record.attrs.end()  &&
  419.         protein_it->front() == "protein_id") {
  420.         if ( !id.empty() ) {
  421.             id += ' ';
  422.         }
  423.         id += (*protein_it)[1];
  424.     }
  425.     // look for db xrefs
  426.     static const vector<string> sc_Dbxref(1, "db_xref");
  427.     SRecord::TAttrs::const_iterator dbxref_it
  428.         = record.attrs.lower_bound(sc_Dbxref);
  429.     for ( ; dbxref_it != record.attrs.end()  &&
  430.             dbxref_it->front() == "db_xref";  ++dbxref_it) {
  431.         if ( !id.empty() ) {
  432.             id += ' ';
  433.         }
  434.         id += (*dbxref_it)[1];
  435.     }
  436.     if ( id.empty() ) {
  437.         return id;
  438.     }
  439.     if (record.key == "start_codon" ||  record.key == "stop_codon") {
  440.         //id += " " + record.key;
  441.         id += "CDS";
  442.     } else if (record.key == "CDS"
  443.                ||  NStr::FindNoCase(record.key, "rna") != NPOS) {
  444.         //id += " " + record.key;
  445.         id += record.key;
  446.     } else { // probably an intron, exon, or single site
  447.         return kEmptyStr;
  448.     }
  449.     _TRACE("id = " << id);
  450.     return id;
  451. }
  452. void CGFFReader::x_MergeRecords(SRecord& dest, const SRecord& src)
  453. {
  454.     // XXX - perform sanity checks and warn on mismatch
  455.     bool merge_overlaps = false;
  456.     if ((src.key == "start_codon"  ||  src.key == "stop_codon")  &&
  457.         dest.key == "CDS") {
  458.         // start_codon and stop_codon features should be contained inside of
  459.         // existing CDS locations
  460.         merge_overlaps = true;
  461.     }
  462.     ITERATE (SRecord::TLoc, slit, src.loc) {
  463.         bool merged = false;
  464.         NON_CONST_ITERATE (SRecord::TLoc, dlit, dest.loc) {
  465.             if (slit->accession != dlit->accession) {
  466.                 if (dest.loc.size() == 1) {
  467.                     x_Warn("Multi-accession feature", src.line_no);
  468.                 }
  469.                 continue;
  470.             } else if (slit->strand != dlit->strand) {
  471.                 if (dest.loc.size() == 1) {
  472.                     x_Warn("Multi-orientation feature", src.line_no);
  473.                 }
  474.                 continue;
  475.             } else {
  476.                 if (merge_overlaps) {
  477.                     ITERATE (set<TSeqRange>, src_iter, slit->ranges) {
  478.                         TSeqRange range(*src_iter);
  479.                         set<TSeqRange>::iterator dst_iter =
  480.                             dlit->ranges.begin();
  481.                         for ( ;  dst_iter != dlit->ranges.end();  ) {
  482.                             if (dst_iter->IntersectingWith(range)) {
  483.                                 range += *dst_iter;
  484.                                 _TRACE("merging overlapping ranges: "
  485.                                        << range.GetFrom() << " - "
  486.                                        << range.GetTo() << " <-> "
  487.                                        << dst_iter->GetFrom() << " - "
  488.                                        << dst_iter->GetTo());
  489.                                 dlit->ranges.erase(dst_iter++);
  490.                             } else {
  491.                                 ++dst_iter;
  492.                             }
  493.                         }
  494.                         dlit->ranges.insert(range);
  495.                     }
  496.                 } else {
  497.                     ITERATE (set<TSeqRange>, set_iter, slit->ranges) {
  498.                         dlit->ranges.insert(*set_iter);
  499.                     }
  500.                 }
  501.                 merged = true;
  502.                 break;
  503.             }
  504.         }
  505.         if ( !merged ) {
  506.             dest.loc.push_back(*slit);
  507.         }
  508.     }
  509.     if (src.key != dest.key) {
  510.         if (dest.key == "CDS"  &&  NStr::EndsWith(src.key, "_codon")
  511.             &&  !(x_GetFlags() & fNoGTF) ) {
  512.             // ok
  513.         } else if (src.key == "CDS" &&  NStr::EndsWith(dest.key, "_codon")
  514.             &&  !(x_GetFlags() & fNoGTF) ) {
  515.             dest.key == "CDS";
  516.         } else {
  517.             x_Warn("Merging features with different keys: " + dest.key
  518.                    + " != " + src.key, src.line_no);
  519.         }
  520.     }
  521.     x_MergeAttributes(dest, src);
  522. }
  523. void CGFFReader::x_MergeAttributes(SRecord& dest, const SRecord& src)
  524. {
  525.     SRecord::TAttrs::iterator dait     = dest.attrs.begin();
  526.     SRecord::TAttrs::iterator dait_end = dest.attrs.end();
  527.     SRecord::TAttrs::iterator dait_tag = dait_end;
  528.     ITERATE (SRecord::TAttrs, sait, src.attrs) {
  529.         const string& tag = sait->front();
  530.         while (dait != dait_end  &&  dait->front() < tag) {
  531.             ++dait;
  532.         }
  533.         if (dait->front() == tag) {
  534.             if (dait_tag == dait_end  ||  dait_tag->front() != tag) {
  535.                 dait_tag = dait;
  536.             }
  537.             while (dait != dait_end  &&  *dait < *sait) {
  538.                 ++dait;
  539.             }
  540.         }
  541.         if (dait != dait_end  &&  *dait == *sait) {
  542.             continue; // identical
  543.         } else if ( !(x_GetFlags() & fNoGTF)  &&  tag == "exon_number") {
  544.             if (dait_tag != dait_end) {
  545.                 while (dait != dait_end  &&  dait->front() == tag) {
  546.                     ++dait;
  547.                 }
  548.                 dest.attrs.erase(dait_tag, dait);
  549.             }
  550.         } else {
  551.             dest.attrs.insert(dait, *sait);
  552.         }
  553.     }
  554. }
  555. void CGFFReader::x_PlaceFeature(CSeq_feat& feat, const SRecord&)
  556. {
  557.     CRef<CBioseq> seq;
  558.     if ( !feat.IsSetProduct() ) {
  559.         for (CTypeConstIterator<CSeq_id> it(feat.GetLocation());  it;  ++it) {
  560.             CRef<CBioseq> seq2 = x_ResolveID(*it, kEmptyStr);
  561.             if ( !seq ) {
  562.                 seq.Reset(seq2);
  563.             } else if ( seq2.NotEmpty()  &&  seq != seq2) {
  564.                 seq.Reset();
  565.                 BREAK(it);
  566.             }
  567.         }
  568.     }
  569.     CBioseq::TAnnot& annots
  570.         = seq ? seq->SetAnnot() : m_TSE->SetSet().SetAnnot();
  571.     NON_CONST_ITERATE (CBioseq::TAnnot, it, annots) {
  572.         if ((*it)->GetData().IsFtable()) {
  573.             (*it)->SetData().SetFtable().push_back(CRef<CSeq_feat>(&feat));
  574.             return;
  575.         }
  576.     }
  577.     CRef<CSeq_annot> annot(new CSeq_annot);
  578.     annot->SetData().SetFtable().push_back(CRef<CSeq_feat>(&feat));
  579.     annots.push_back(annot);
  580. }
  581. CRef<CSeq_id> CGFFReader::x_ResolveSeqName(const string& name)
  582. {
  583.     CRef<CSeq_id>& id = m_SeqNameCache[name];
  584.     if ( !id ) {
  585.         id.Reset(x_ResolveNewSeqName(name));
  586.     }
  587.     if ( !id ) {
  588.         x_Warn("x_ResolveNewSeqName returned null for " + name);
  589.         id.Reset(new CSeq_id(CSeq_id::e_Local, name, name));
  590.     }
  591.     return id;
  592. }
  593. CRef<CSeq_id> CGFFReader::x_ResolveNewSeqName(const string& name)
  594. {
  595.     return CRef<CSeq_id>(new CSeq_id(name));
  596. }
  597. CRef<CBioseq> CGFFReader::x_ResolveID(const CSeq_id& id, const string& mol)
  598. {
  599.     CRef<CBioseq>& seq = m_SeqCache[CConstRef<CSeq_id>(&id)];
  600.     if ( !seq ) {
  601.         seq.Reset(x_ResolveNewID(id, mol));
  602.         // Derived versions of x_ResolveNewID may legimately return null
  603.         // results....
  604.         if (seq) {
  605.             x_PlaceSeq(*seq);
  606.             ITERATE (CBioseq::TId, it, seq->GetId()) {
  607.                 m_SeqCache.insert(make_pair(CConstRef<CSeq_id>(*it), seq));
  608.             }
  609.         }
  610.     }
  611.     return seq;
  612. }
  613. CRef<CBioseq> CGFFReader::x_ResolveNewID(const CSeq_id& id, const string& mol0)
  614. {
  615.     CRef<CBioseq> seq(new CBioseq);
  616.     CRef<CSeq_id> id_copy(new CSeq_id);
  617.     id_copy->Assign(id);
  618.     seq->SetId().push_back(id_copy);
  619.     seq->SetInst().SetRepr(CSeq_inst::eRepr_virtual);
  620.     const string& mol = mol0.empty() ? m_DefMol : mol0;
  621.     if (mol.empty()  ||  mol == "dna") {
  622.         seq->SetInst().SetMol(CSeq_inst::eMol_dna);
  623.     } else if (mol == "rna")  {
  624.         seq->SetInst().SetMol(CSeq_inst::eMol_rna);
  625.     } else if (mol == "protein")  {
  626.         seq->SetInst().SetMol(CSeq_inst::eMol_aa);
  627.     } else {
  628.         x_Warn("unrecognized sequence type " + mol + "; assuming DNA");
  629.         seq->SetInst().SetMol(CSeq_inst::eMol_dna);
  630.     }
  631.     return seq;
  632. }
  633. void CGFFReader::x_PlaceSeq(CBioseq& seq)
  634. {
  635.     bool found = false;
  636.     for (CTypeConstIterator<CBioseq> it(*m_TSE);  it;  ++it) {
  637.         if (&*it == &seq) {
  638.             found = true;
  639.             BREAK(it);
  640.         }
  641.     }
  642.     if ( !found ) {
  643.         CRef<CSeq_entry> se(new CSeq_entry);
  644.         se->SetSeq(seq);
  645.         m_TSE->SetSet().SetSeq_set().push_back(se);
  646.     }
  647. }
  648. END_SCOPE(objects)
  649. END_NCBI_SCOPE
  650. /*
  651. * ===========================================================================
  652. *
  653. * $Log: gff_reader.cpp,v $
  654. * Revision 1000.1  2004/06/01 19:46:20  gouriano
  655. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.6
  656. *
  657. * Revision 1.6  2004/05/21 21:42:55  gorelenk
  658. * Added PCH ncbi_pch.hpp
  659. *
  660. * Revision 1.5  2004/05/08 12:13:24  dicuccio
  661. * Switched away from using CRangeCollection<> for locations, as this lead to
  662. * inadvertent merging of correctly overlapping exons
  663. *
  664. * Revision 1.4  2004/01/06 17:02:40  dicuccio
  665. * (From Aaron Ucko): Fixed ordering of intervals in a seq-loc-mix on the negative
  666. * strand
  667. *
  668. * Revision 1.3  2003/12/31 12:48:29  dicuccio
  669. * Fixed interpretation of positions - GFF/GTF is 1-based, ASN.1 is 0-based
  670. *
  671. * Revision 1.2  2003/12/04 00:58:24  ucko
  672. * Fix for WorkShop's context-insensitive make_pair.
  673. *
  674. * Revision 1.1  2003/12/03 20:56:36  ucko
  675. * Initial commit.
  676. *
  677. *
  678. * ===========================================================================
  679. */