// Parser public static CIndividualEventStructure Parse( CGedcom gedcom, int nLevel ) { CGedcomLine gedcomLine; // Temporary holders for class members. Saves constructing a class early. string sType; string sValue; string sSubtype = ""; CEventDetail ed, eventDetail=null; // There must be one of these, it defines the object. if( (gedcomLine = gedcom.GetLine(nLevel, "_NMR")) == null // Never married (brother's keeper) && (gedcomLine = gedcom.GetLine(nLevel, "_AKA")) == null // Also known as (brother's keeper) && (gedcomLine = gedcom.GetLine(nLevel, "_AKAN")) == null // Also known as (brother's keeper) && (gedcomLine = gedcom.GetLine(nLevel, "BIRT")) == null && (gedcomLine = gedcom.GetLine(nLevel, "CHR")) == null && (gedcomLine = gedcom.GetLine(nLevel, "DEAT")) == null && (gedcomLine = gedcom.GetLine(nLevel, "BURI")) == null && (gedcomLine = gedcom.GetLine(nLevel, "CREM")) == null && (gedcomLine = gedcom.GetLine(nLevel, "ADOP")) == null && (gedcomLine = gedcom.GetLine(nLevel, "BAPM")) == null && (gedcomLine = gedcom.GetLine(nLevel, "BAP")) == null && (gedcomLine = gedcom.GetLine(nLevel, "BARM")) == null && (gedcomLine = gedcom.GetLine(nLevel, "BASM")) == null && (gedcomLine = gedcom.GetLine(nLevel, "BLES")) == null && (gedcomLine = gedcom.GetLine(nLevel, "CHRA")) == null && (gedcomLine = gedcom.GetLine(nLevel, "CONF")) == null && (gedcomLine = gedcom.GetLine(nLevel, "FCOM")) == null && (gedcomLine = gedcom.GetLine(nLevel, "ORDN")) == null && (gedcomLine = gedcom.GetLine(nLevel, "NATU")) == null && (gedcomLine = gedcom.GetLine(nLevel, "EMIG")) == null && (gedcomLine = gedcom.GetLine(nLevel, "IMMI")) == null && (gedcomLine = gedcom.GetLine(nLevel, "CENS")) == null && (gedcomLine = gedcom.GetLine(nLevel, "PROB")) == null && (gedcomLine = gedcom.GetLine(nLevel, "WILL")) == null && (gedcomLine = gedcom.GetLine(nLevel, "GRAD")) == null && (gedcomLine = gedcom.GetLine(nLevel, "RETI")) == null && (gedcomLine = gedcom.GetLine(nLevel, "EVEN")) == null && (gedcomLine = gedcom.GetLine(nLevel, "CAST")) == null && (gedcomLine = gedcom.GetLine(nLevel, "DSCR")) == null && (gedcomLine = gedcom.GetLine(nLevel, "EDUC")) == null && (gedcomLine = gedcom.GetLine(nLevel, "IDNO")) == null && (gedcomLine = gedcom.GetLine(nLevel, "NATI")) == null && (gedcomLine = gedcom.GetLine(nLevel, "NCHI")) == null && (gedcomLine = gedcom.GetLine(nLevel, "NMR")) == null && (gedcomLine = gedcom.GetLine(nLevel, "OCCU")) == null && (gedcomLine = gedcom.GetLine(nLevel, "PROP")) == null && (gedcomLine = gedcom.GetLine(nLevel, "RELI")) == null && (gedcomLine = gedcom.GetLine(nLevel, "RESI")) == null && (gedcomLine = gedcom.GetLine(nLevel, "SSN")) == null && (gedcomLine = gedcom.GetLine(nLevel, "TITL")) == null && (gedcomLine = gedcom.GetLine(nLevel, "FACT")) == null ) { return null; } sType = gedcomLine.Tag; if( sType == "BAP" ) { sType = "BAPM"; } sValue = gedcomLine.LineItem; gedcom.IncrementLineIndex(1); bool bParsingFinished; do { bParsingFinished = true; if( (gedcomLine = gedcom.GetLine(nLevel+1, "TYPE")) != null ) { sSubtype = gedcomLine.LineItem; gedcom.IncrementLineIndex(1); bParsingFinished = false; } if( (gedcomLine = gedcom.GetLine(nLevel+1, "CONC")) != null ) { sValue += gedcomLine.LineItem; gedcom.IncrementLineIndex(1); bParsingFinished = false; } else if( (gedcomLine = gedcom.GetLine(nLevel+1, "CONT")) != null ) { sValue += "\n" + gedcomLine.LineItem; gedcom.IncrementLineIndex(1); bParsingFinished = false; } else if( (ed = CEventDetail.Parse( gedcom, nLevel+1 )) != null ) { eventDetail = ed; bParsingFinished = false; } else if( ( gedcomLine = gedcom.GetLine()).Level > nLevel ) { LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Warning, "Unknown tag :" ); LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Warning, gedcomLine.ToString() ); gedcom.IncrementLineIndex(1); bParsingFinished = false; } } while( !bParsingFinished ); // Parsing went ok. Construct a new object and return it. CIndividualEventStructure ies = new CIndividualEventStructure( gedcom ); ies.Type = sType; ies.m_sSubtype = sSubtype; ies.Value = sValue; ies.m_eventDetail = eventDetail; return ies; }
// Reads a GEDCOM file into a hierarchy of data structures public void ParseFile() { LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Note, "ParseFile()" ); CThreadError threaderror = new CThreadError( 1, "No error" ); // 2 = process was aborted, for signalling back to calling thread. 1= cancelled by user action m_nLineIndex = -1; // Used to indicate to exception handling that stage2 parsing hasn't started FileStream fileStream = null; StreamReader streamReader = null; ClearOutParser(); LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Note, "ParseFile() ClearOutParser" ); string sParseLine=""; try { m_progressWindow.Begin( 0, 100 ); LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Note, "Progress window begun" ); // Discern file character set by reading first 2 bytes of file FileStream fsCharsetDetection = new FileStream( Filename, FileMode.Open, FileAccess.Read ); StreamReader srCharsetDetection = null; try { byte[] abFirstBytes = new byte[2]; fsCharsetDetection.Read( abFirstBytes, 0, 2 ); fsCharsetDetection.Seek( 0, SeekOrigin.Begin ); m_ecCharset = ECharset.Unknown8bit; string sCharset = "ANSI"; if( (abFirstBytes[0] == 0xff && abFirstBytes[1] == 0xfe) || (abFirstBytes[0] == 0x30 && abFirstBytes[1] == 0x00) ) { m_ecCharset = ECharset.Unicode; } else if( (abFirstBytes[0] == 0xfe && abFirstBytes[1] == 0xff) || (abFirstBytes[0] == 0x00 && abFirstBytes[1] == 0x30) ) { m_ecCharset = ECharset.UnicodeReversed; } switch( m_ecCharset ) { case ECharset.Unicode: srCharsetDetection = new StreamReader( fsCharsetDetection, System.Text.Encoding.GetEncoding("UTF-16BE") ); break; case ECharset.UnicodeReversed: srCharsetDetection = new StreamReader( fsCharsetDetection, System.Text.Encoding.GetEncoding("UTF-16LE") ); break; default: srCharsetDetection = new StreamReader( fsCharsetDetection, System.Text.Encoding.GetEncoding("utf-8") ); break; } if( srCharsetDetection != null ) { string sCharsetDetectionLine = ""; do { sCharsetDetectionLine = srCharsetDetection.ReadLine(); if( sCharsetDetectionLine != "" && sCharsetDetectionLine != null ) { sCharsetDetectionLine = sCharsetDetectionLine.ToUpper(); sCharsetDetectionLine = sCharsetDetectionLine.Trim(); } } while( sCharsetDetectionLine != null && ( sCharsetDetectionLine.Length < 7 || sCharsetDetectionLine.Substring(0,7) != "1 CHAR " ) ); if( sCharsetDetectionLine != null ) { sCharset = sCharsetDetectionLine.Substring(7); if( m_ecCharset != ECharset.Unicode && m_ecCharset != ECharset.UnicodeReversed ) // If file is in unicode format, ignore charset string cos we already know format. { // Using substring here to ignore trailing spaces if( sCharset.Length >= 5 && sCharset.Substring(0,5) == "ASCII" ) { m_ecCharset = ECharset.Ascii; } else if( sCharset.Length >= 4 && sCharset.Substring(0,4) == "ANSI" ) { m_ecCharset = ECharset.Ansi; } else if( sCharset.Length >= 5 && sCharset.Substring(0,5) == "ANSEL" ) { m_ecCharset = ECharset.Ansel; } else if( sCharset.Length >= 4 && sCharset.Substring(0,4) == "UTF8" ) { m_ecCharset = ECharset.UTF8; } else if( sCharset.Length >= 5 && sCharset.Substring(0,5) == "UTF-8" ) { m_ecCharset = ECharset.UTF8; } else if( sCharset.Length >= 7 && sCharset.Substring(0,7) == "UNICODE" ) { m_ecCharset = ECharset.Unicode; } else if( sCharset.Length >= 5 && sCharset.Substring(0,5) == "UTF16" ) { m_ecCharset = ECharset.Unicode; } else if( sCharset.Length >= 6 && sCharset.Substring(0,6) == "UTF-16" ) { m_ecCharset = ECharset.Unicode; } } } } } catch( Exception e ) { LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Note, "Caught exception while trying to discern character set :" + e.ToString() ); m_ecCharset = ECharset.UTF8; } if( srCharsetDetection != null ) { srCharsetDetection.Close(); } if( fsCharsetDetection != null ) { fsCharsetDetection.Close(); } LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Note, "Opening file with charset " + m_ecCharset.ToString() ); fileStream = new FileStream( Filename, FileMode.Open, FileAccess.Read ); System.Text.Encoding encoding = System.Text.Encoding.GetEncoding("iso-8859-1"); switch( m_ecCharset ) { case ECharset.Ascii: encoding = System.Text.Encoding.GetEncoding("ascii"); break; case ECharset.Ansi: encoding = System.Text.Encoding.GetEncoding("iso-8859-1"); break; case ECharset.Ansel: encoding = System.Text.Encoding.GetEncoding("iso-8859-1"); break; case ECharset.UTF8: encoding = System.Text.Encoding.GetEncoding("utf-8"); break; case ECharset.Unicode: encoding = System.Text.Encoding.GetEncoding("UTF-16BE"); break; case ECharset.UnicodeReversed: encoding = System.Text.Encoding.GetEncoding("UTF-16LE"); break; default: encoding = System.Text.Encoding.GetEncoding("utf-8"); break; } streamReader = new StreamReader( fileStream, encoding ); LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Note, "Stream created" ); m_nBytesRead = 0; m_nBytesTotal = fileStream.Length; uint uLineInFile = 0; // Read all lines in file into memory int nPercentComplete, nPreviousPercentComplete = 0; for(;;) { if( m_progressWindow.IsAborting ) { LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Note, "Progress window aborting (1)" ); return; } sParseLine = streamReader.ReadLine(); if( m_ecCharset == ECharset.Ansel ) { sParseLine = ConvertAnsel( sParseLine ); } if( sParseLine == null ) { LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Note, "No more lines, end of file" ); // No more lines, end of file break; } uLineInFile++; m_nBytesRead += sParseLine.Length + 1; // Interim fix. Should actually count bytes according to whether gedcomLine ends with CR or CRLF. nPercentComplete = (int)(m_nBytesRead * 100 / m_nBytesTotal); if( nPercentComplete != nPreviousPercentComplete ) { nPreviousPercentComplete = nPercentComplete; m_progressWindow.SetText( String.Format( "Bytes read: {0}", m_nBytesRead ) ); if( nPercentComplete > 100 ) { LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Note, "Percent set to 100 (1)" ); // Safety valve. Prevents control from throwing. nPercentComplete = 100; } m_progressWindow.StepTo( nPercentComplete ); } if( sParseLine.Length != 0 ) { try { CGedcomLine gedcomLine = ParseLine( sParseLine, uLineInFile ); if( gedcomLine != null ) { m_alLines.Add( gedcomLine ); } } catch( CParsingException ) { LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Warning, String.Concat("Unable to parse line ", uLineInFile.ToString(), ":", sParseLine ) ); } } // Signal waiting app that parse has finished } if( m_progressWindow.IsAborting ) { LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Note, "Progress window aborting (2)" ); return; } // Parse lines of file m_nLineIndex = 0; sParseLine=""; int nLines = m_alLines.Count; m_progressWindow.SetText( String.Format( "Parsing file line: {0} out of {1}", m_nLineIndex, nLines ) ); nPercentComplete = (int)(m_nLineIndex * 100 / nLines); if( nPercentComplete > 100 ) { // Safety valve. Prevents control from throwing. nPercentComplete = 100; } m_progressWindow.StepTo( nPercentComplete ); if( m_progressWindow.IsAborting ) { LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Note, "Progress window aborting (3)" ); return; } if( !ParseHeader() ) { // Mandatory header missing/corrupt throw new CParsingException( "Header missing or corrupt" ); } m_progressWindow.SetText( String.Format( "Parsing file line: {0} out of {1}", m_nLineIndex, nLines ) ); nPercentComplete = (int)(m_nLineIndex * 100 / nLines); if( nPercentComplete > 100 ) { // Safety valve. Prevents control from throwing. nPercentComplete = 100; } m_progressWindow.StepTo( nPercentComplete ); if( m_progressWindow.IsAborting ) { LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Note, "Progress window aborting (4)" ); return; } m_submissionRecord = CSubmissionRecord.Parse( this, 0 ); m_progressWindow.SetText( String.Format( "Parsing file line: {0} out of {1}", m_nLineIndex, nLines ) ); nPercentComplete = (int)(m_nLineIndex * 100 / nLines); if( nPercentComplete > 100 ) { // Safety valve. Prevents control from throwing. LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Note, "Percent set to 100 (2)" ); nPercentComplete = 100; } m_progressWindow.StepTo( nPercentComplete ); if( m_progressWindow.IsAborting ) { LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Note, "Progress window aborting (5)" ); return; } int nRecords = 0; CFamilyRecord fr; CIndividualRecord ir; CMultimediaRecord mr; CNoteRecord nr; CRepositoryRecord rr; CSourceRecord sr; CSubmitterRecord smr; CGedcomLine gedcomLine2; bool bParsingSuccessful = false; bool bParsingFinished; do { bParsingFinished = false; m_progressWindow.SetText( String.Format( "Parsing file line: {0} out of {1}", m_nLineIndex, nLines ) ); nPercentComplete = (int)(m_nLineIndex * 100 / nLines); if( nPercentComplete > 100 ) { // Safety valve. Prevents control from throwing. nPercentComplete = 100; } m_progressWindow.StepTo( nPercentComplete ); if( m_progressWindow.IsAborting ) { LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Note, "Progress window aborting (6)" ); return; } if( (fr = CFamilyRecord.Parse( this, 0 )) != null ) { m_alFamilyRecords.Add( fr ); m_htFamilyRecordsXref.Add( fr.m_xref, fr ); ++nRecords; bParsingFinished = false; } else if( (ir = CIndividualRecord.Parse( this, 0)) != null ) { m_alIndividualRecords.Add( ir ); m_htIndividualRecordsXref.Add( ir.m_xref, ir ); ++nRecords; bParsingFinished = false; } else if( (mr = CMultimediaRecord.Parse( this, 0 )) != null ) { m_alMultimediaRecords.Add( mr ); ++nRecords; bParsingFinished = false; } else if( (nr = CNoteRecord.Parse( this, 0 )) != null ) { m_alNoteRecords.Add( nr ); ++nRecords; bParsingFinished = false; } else if( (rr = CRepositoryRecord.Parse( this, 0 )) != null ) { m_alRepositoryRecords.Add( rr ); ++nRecords; bParsingFinished = false; } else if( (sr = CSourceRecord.Parse( this, 0 )) != null ) { m_alSourceRecords.Add( sr ); m_htSourceRecordsXref.Add( sr.m_xref, sr ); ++nRecords; bParsingFinished = false; } else if( ( smr = CSubmitterRecord.Parse( this, 0 )) != null ) { m_alSubmitterRecords.Add( smr ); ++nRecords; bParsingFinished = false; } else if( ( gedcomLine2 = GetLine( 0, "TRLR" )) != null ) { LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Note, "TRLR found OK" ); bParsingSuccessful = true; } else { // Skip this unknown gedcomLine LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Warning, "WARNING: Couldn't parse line:" ); LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Warning, GetLine().ToString() ); m_nLineIndex++; } } // end do while( m_nLineIndex < nLines && !bParsingSuccessful && !bParsingFinished ); LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Note, "Parsing ended normally." ); // Tie up adopted individuals with their associated fr LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Note, "Linking adoptees." ); foreach( CIndividualRecord adopIr in m_alAdoptedIndividuals ) { CEventDetail adopEvent = adopIr.GetEvent( "ADOP" ); if( adopEvent != null ) { string adopFamXref = adopEvent.m_xrefFam; bool adopHusband = adopEvent.m_bAdoptedByHusband; bool adopWife = adopEvent.m_bAdoptedByWife; CFamilyRecord adopFam = GetFamilyRecord( adopFamXref ); if( adopFam!=null && (adopHusband || adopWife) ) { if( adopHusband ) { CIndividualRecord irAdopHusband = GetIndividualRecord( adopFam.m_xrefHusband ); if( irAdopHusband != null ) { CIndividualEventStructure husbandAdopEvent = new CIndividualEventStructure( adopEvent ); husbandAdopEvent.Type = "GEDMILL_ADOPTION_OF_CHILD"; // Special GEDmill only event husbandAdopEvent.m_eventDetail.m_xrefAdoptedChild = adopIr.m_xref; irAdopHusband.m_alIndividualEventStructures.Add( husbandAdopEvent ); } } if( adopWife ) { CIndividualRecord irAdopWife = GetIndividualRecord( adopFam.m_xrefWife ); if( irAdopWife != null ) { CIndividualEventStructure wifeAdopEvent = new CIndividualEventStructure( adopEvent ); wifeAdopEvent.Type = "GEDMILL_ADOPTION_OF_CHILD"; // Special GEDmill only event wifeAdopEvent.m_eventDetail.m_xrefAdoptedChild = adopIr.m_xref; irAdopWife.m_alIndividualEventStructures.Add( wifeAdopEvent ); } } } } } LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Note, "Linking indi backreferences." ); foreach( CIndividualRecord brir in m_alIndividualRecords ) { foreach( CIndividualEventStructure ies in brir.m_alIndividualEventStructures ) { if( ies.m_eventDetail != null ) { foreach( CSourceCitation sc in ies.m_eventDetail.m_alSourceCitations ) { sc.AddBackreference(new CBackReference(ERecordType.Individual, brir.m_xref, ies.Type)); sc.AddPicFromCitationToRecord(); } foreach( CNoteStructure ns in ies.m_eventDetail.m_alNoteStructures ) { if( ns != null && ns.m_alSourceCitations != null ) { foreach( CSourceCitation sc in ns.m_alSourceCitations ) { sc.AddBackreference(new CBackReference(ERecordType.Individual, brir.m_xref, ies.Type)); sc.AddPicFromCitationToRecord(); } } } } } foreach( CPersonalNameStructure pns in brir.m_alPersonalNameStructures ) { if( pns.m_personalNamePieces != null ) { foreach( CSourceCitation sc in pns.m_personalNamePieces.m_alSourceCitations ) { sc.AddBackreference( new CBackReference( ERecordType.Individual, brir.m_xref, "NAME" ) ); sc.AddPicFromCitationToRecord(); } } } foreach( CSourceCitation sc in brir.m_alSourceCitations ) { sc.AddBackreference( new CBackReference( ERecordType.Individual, brir.m_xref, "" ) ); sc.AddPicFromCitationToRecord(); } } foreach( CFamilyRecord brfr in m_alFamilyRecords ) { foreach( CFamilyEventStructure fes in brfr.m_alFamilyEventStructures ) { if( fes.m_eventDetail != null ) { foreach( CSourceCitation sc in fes.m_eventDetail.m_alSourceCitations ) { sc.AddBackreference(new CBackReference(ERecordType.Family, brfr.m_xref, fes.Type)); sc.AddPicFromCitationToRecord(); } foreach( CNoteStructure ns in fes.m_eventDetail.m_alNoteStructures ) { if( ns != null && ns.m_alSourceCitations != null ) { foreach( CSourceCitation sc in ns.m_alSourceCitations ) { sc.AddBackreference(new CBackReference(ERecordType.Family, brfr.m_xref, fes.Type)); sc.AddPicFromCitationToRecord(); } } } } } foreach( CSourceCitation sc in brfr.m_alSourceCitations ) { sc.AddBackreference( new CBackReference( ERecordType.Family, brfr.m_xref, "" ) ); sc.AddPicFromCitationToRecord(); } } foreach( CNoteRecord brnr in m_alNoteRecords ) { foreach( CSourceCitation sc in brnr.m_alSourceCitations ) { sc.AddBackreference( new CBackReference( ERecordType.Note, brnr.m_xref, "" ) ); sc.AddPicFromCitationToRecord(); } } // Join together fragmented multimedia files LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Note, "Joining multimedia fragments." ); // Go through all the MFRs in every link in every record. foreach( CSourceRecord isr in m_alSourceRecords ) { JoinMultimedia( isr.m_alMultimediaLinks ); } foreach( CIndividualRecord iir in m_alIndividualRecords ) { JoinMultimedia( iir.m_alMultimediaLinks ); } // Create a list of MFRs unique to the individual LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Note, "Ordering individual's mfrs." ); foreach( CIndividualRecord irMultimedia in m_alIndividualRecords ) { ConvertMultimediaLinks( irMultimedia.m_alMultimediaLinks, ref irMultimedia.m_alUniqueFileRefs ); } // Create a list of MFRs unique to the source LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Note, "Ordering source's mfrs." ); foreach( CSourceRecord srMultimedia in m_alSourceRecords ) { ConvertMultimediaLinks( srMultimedia.m_alMultimediaLinks, ref srMultimedia.m_alUniqueFileRefs ); } // Moved inside try block as any exception it threw would not otherwise be caught: AddChildrenToFamilies(); // Ended normally threaderror.m_nError = 0; } catch( System.Threading.ThreadAbortException e ) { // Abnormal abort threaderror.m_nError = 2; threaderror.m_sMessage = ""; LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Error, String.Format("Caught thread exception : {0}", e.ToString() ) ); } catch( System.Threading.ThreadInterruptedException e ) { // Abnormal abort threaderror.m_nError = 2; threaderror.m_sMessage = ""; LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Error, String.Format( "Caught thread exception : {0}", e.ToString() ) ); } catch( CParsingException e ) { // Abnormal abort threaderror.m_nError = 2; threaderror.m_sMessage = ""; string sLine = sParseLine; if( m_nLineIndex>=0 ) { if( m_nLineIndex >= m_alLines.Count ) { sLine = "EOF"; } else { sLine = ((CGedcomLine)(m_alLines[m_nLineIndex])).ToString(); } } LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Error, String.Format("Caught parsing exception in file {0}, line {1} ({2}) : {3}", Filename, m_nLineIndex, sLine, e.ToString() ) ); // And here, if we can } catch( System.IO.IOException e ) { // Abnormal abort, offer retry, file already open. threaderror.m_nError = 3; threaderror.m_sMessage = ""; LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Error, String.Format("Caught IO exception (line index={0}) : {1}", m_nLineIndex, e.ToString() ) ); } catch( Exception e ) { // Abnormal abort threaderror.m_nError = 2; threaderror.m_sMessage = ""; LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Error, String.Format("Caught generic exception (line index={0}) : {1}", m_nLineIndex, e.ToString() ) ); } finally { LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Note, "Closing file" ); if (streamReader != null) { streamReader.Close(); } if (fileStream != null) { fileStream.Close(); } if( m_progressWindow != null ) { LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Note, "Closing progress window" ); m_progressWindow.End( threaderror ); } // Don't need the memory any more: m_alLines.Clear(); } LogFile.TheLogFile.WriteLine( LogFile.DT_GEDCOM, LogFile.EDebugLevel.Note, "All done." ); }