/// ------------------------------------------------------------------------------------ /// <summary> /// Given a Scripture section, this method returns the index of the paragraph containing /// the requested verse and the position of the character immediately following the /// verse number in that paragraph. If an exact match isn't found, the closest /// approximate place is found. /// </summary> /// <param name="section">The section whose paragraphs will be searched</param> /// <param name="targetRef">The reference being sought</param> /// <param name="iPara">The index of the paragraph where the verse was found</param> /// <param name="ichPosition">The index of the character immediately following the /// verse number in that paragraph</param> /// ------------------------------------------------------------------------------------ protected void FindVerseNumber(IScrSection section, ScrReference targetRef, out int iPara, out int ichPosition) { iPara = 0; ichPosition = 0; bool fChapterFound = (BCVRef.GetChapterFromBcv(section.VerseRefMin) == targetRef.Chapter); foreach (IStTxtPara para in section.ContentOA.ParagraphsOS) { if (para.Contents.Text == null) { continue; } TsRunInfo tsi; ITsTextProps ttpRun; int ich = 0; while (ich < para.Contents.Length) { // Get props of current run. ttpRun = para.Contents.FetchRunInfoAt(ich, out tsi); // See if it is our verse number style. if (fChapterFound) { if (ttpRun.Style() == ScrStyleNames.VerseNumber) { // The whole run is the verse number. Extract it. string sVerseNum = para.Contents.Text.Substring(tsi.ichMin, tsi.ichLim - tsi.ichMin); int startVerse, endVerse; ScrReference.VerseToInt(sVerseNum, out startVerse, out endVerse); if ((targetRef.Verse >= startVerse && targetRef.Verse <= endVerse) || targetRef.Verse < startVerse) { ichPosition = tsi.ichLim; return; } } } // See if it is our chapter number style. else if (ttpRun.Style() == ScrStyleNames.ChapterNumber) { try { // Assume the whole run is the chapter number. Extract it. string sChapterNum = para.Contents.Text.Substring(tsi.ichMin, tsi.ichLim - tsi.ichMin); fChapterFound = (ScrReference.ChapterToInt(sChapterNum) == targetRef.Chapter); } catch (ArgumentException) { // ignore runs with invalid Chapter numbers } } ich = tsi.ichLim; } iPara++; } iPara = 0; // Couldn't find it. }
/// ------------------------------------------------------------------------------------ /// <summary> /// Given a Scripture section, this method returns the index of the paragraph containing /// the requested verse and the position of the character immediately following the /// verse number in that paragraph. If an exact match isn't found, the closest /// approximate place is found. /// </summary> /// <param name="section">The section whose paragraphs will be searched</param> /// <param name="targetRef">The reference being sought</param> /// <param name="ihvoPara"></param> /// <param name="ichPosition"></param> /// <remarks>Currently, this does NOT attempt to find a close match, but some day it /// should</remarks> /// ------------------------------------------------------------------------------------ protected void FindVerseNumber(ScrSection section, ScrReference targetRef, out int ihvoPara, out int ichPosition) { ihvoPara = 0; ichPosition = 0; bool fChapterFound = ((ScrReference)section.VerseRefStart).Chapter == targetRef.Chapter; foreach (StTxtPara para in section.ContentOA.ParagraphsOS) { TsStringAccessor contents = para.Contents; TsRunInfo tsi; ITsTextProps ttpRun; int ich = 0; while (ich < contents.Text.Length) { // Get props of current run. ttpRun = contents.UnderlyingTsString.FetchRunInfoAt(ich, out tsi); // See if it is our verse number style. if (fChapterFound) { if (StStyle.IsStyle(ttpRun, ScrStyleNames.VerseNumber)) { // The whole run is the verse number. Extract it. string sVerseNum = contents.Text.Substring(tsi.ichMin, tsi.ichLim - tsi.ichMin); int startVerse, endVerse; ScrReference.VerseToInt(sVerseNum, out startVerse, out endVerse); if (targetRef.Verse >= startVerse && targetRef.Verse <= endVerse) { ihvoPara = para.OwnOrd - 1; ichPosition = tsi.ichLim; return; } // TODO: Currently, this does NOT attempt to detect when we have // a close match } } // See if it is our chapter number style. else if (StStyle.IsStyle(ttpRun, ScrStyleNames.ChapterNumber)) { // Assume the whole run is the chapter number. Extract it. string sChapterNum = contents.Text.Substring(tsi.ichMin, tsi.ichLim - tsi.ichMin); int nChapter = ScrReference.ChapterToInt(sChapterNum); fChapterFound = (nChapter == targetRef.Chapter); } ich = tsi.ichLim; } } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Gets the start and end references for the line of text with the given marker. (Sets /// m_currentStartRef and m_currentEndRef.) /// </summary> /// <param name="marker"></param> /// <param name="lineContents"></param> /// <param name="literalVerse"></param> /// <returns></returns> /// ------------------------------------------------------------------------------------ private void GetReferenceForLine(string marker, ref string lineContents, ref string literalVerse) { // If this is a marker that will change the reference, then update // the reference if (marker == ScrImportSet.s_markerBook) { int book = BCVRef.BookToNumber(lineContents.ToUpper()); if (book > 0) { m_currentStartRef.Book = book; m_currentStartRef.Chapter = 1; m_currentStartRef.Verse = 0; } m_currentEndRef = new BCVRef(m_currentStartRef); m_seenIdInFile = true; } else if (marker == ScrImportSet.s_markerChapter) { string chapterText = lineContents; try { m_currentStartRef.Chapter = ScrReference.ChapterToInt(chapterText, out lineContents); m_currentStartRef.Verse = 1; m_currentEndRef = new BCVRef(m_currentStartRef); } catch (ArgumentException) { throw new ScriptureUtilsException(SUE_ErrorCode.InvalidChapterNumber, m_currentFile.FileName, m_lineNumber, lineContents, BCVRef.NumberToBookCode(m_currentStartRef.Book), chapterText, null); } } else if (marker == ScrImportSet.s_markerVerse) { BCVRef.VerseToScrRef(lineContents.TrimStart(), out literalVerse, out lineContents, ref m_currentStartRef, ref m_currentEndRef); } else { if (lineContents == " ") { lineContents = string.Empty; } } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Test converting the digits to a specific digit set /// </summary> /// <param name="zeroChar">zero character in the desired language</param> /// <param name="nineChar">nine character in the desired language</param> /// <param name="dlg">scripture properties dialog</param> /// ------------------------------------------------------------------------------------ private void ScriptDigitConversionTest(char zeroChar, char nineChar, ScriptureProperties dlg) { m_scr.ScriptDigitZero = zeroChar; m_scr.UseScriptDigits = (zeroChar != '0'); ReflectionHelper.CallMethod(dlg, "ConvertChapterVerseNumbers", null); int[] expectedNumbers = new int[] { 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int expectedIndex = 0; ITsString tss = ((IStTxtPara)((IScrSection)m_exodus.SectionsOS[0]).ContentOA.ParagraphsOS[0]).Contents.UnderlyingTsString; for (int i = 0; i < tss.RunCount; i++) { TsRunInfo tri; ITsTextProps ttp = tss.FetchRunInfo(i, out tri); IStStyle style = m_scr.FindStyle(ttp); if (style != null && (style.Function == FunctionValues.Verse || style.Function == FunctionValues.Chapter)) { int expectedNumber = expectedNumbers[expectedIndex++]; string runChars = tss.GetChars(tri.ichMin, tri.ichLim); // make sure the expected digits were found Assert.AreEqual(expectedNumber, ScrReference.ChapterToInt(runChars)); // make sure that all of the digits are in the desired language foreach (char c in runChars) { if (Char.IsDigit(c)) { Assert.IsTrue(c >= zeroChar && c <= nineChar, "Found incorrect digit"); } } } } // Make sure we saw all the expected numbers in the data Assert.AreEqual(expectedNumbers.Length, expectedIndex); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Advances the enumerator to the next verse in the paragraph. /// </summary> /// <returns>True if we successfully moved to the next ScrVerse; False if we reached /// the end of the paragraph.</returns> /// ------------------------------------------------------------------------------------ public bool MoveNext() { InitializeParaContents(); if (m_ich > m_paraLength) { return(false); } m_ichVerseStart = m_ichTextStart = m_ich; TsRunInfo tsi; ITsTextProps ttpRun; string sPara = m_tssParaContents.Text; int nChapter = -1; // This is used to see if we found a chapter later. m_inVerseNum = false; m_inChapterNum = false; while (m_ich < m_paraLength) { ttpRun = m_tssParaContents.FetchRunInfoAt(m_ich, out tsi); // If this run is our verse number style if (ttpRun.Style() == ScrStyleNames.VerseNumber) { // If there is already a verse in process, a new verse number run will terminate it. if (m_ichVerseStart != m_ich) { break; } // Assume the whole run is the verse number string sVerseNum = sPara.Substring(m_ich, tsi.ichLim - tsi.ichMin); int nVerseStart, nVerseEnd; ScrReference.VerseToInt(sVerseNum, out nVerseStart, out nVerseEnd); m_startRef.Verse = nVerseStart; m_endRef.Verse = nVerseEnd; m_ichVerseStart = m_ich; //set VerseStart at beg of verse number m_ich += sVerseNum.Length; m_ichTextStart = m_ich; m_inVerseNum = true; } // If this run is our chapter number style else if (ttpRun.Style() == ScrStyleNames.ChapterNumber) { // If there is already a verse being processed, then the chapter number // run will end it if (m_ichVerseStart != m_ich) { break; } try { // Assume the whole run is the chapter number string sChapterNum = sPara.Substring(m_ich, tsi.ichLim - tsi.ichMin); nChapter = ScrReference.ChapterToInt(sChapterNum); m_startRef.Chapter = m_endRef.Chapter = nChapter; // Set the verse number to 1, since the first verse number after a // chapter is optional. If we happen to get a verse number in the // next run, this '1' will be overridden (though it will probably // still be a 1). m_startRef.Verse = m_endRef.Verse = 1; m_ichVerseStart = m_ich; //set VerseStart at beg of chapter number m_ich += sChapterNum.Length; m_ichTextStart = m_ich; m_inChapterNum = true; } catch (ArgumentException) { // ignore runs with invalid Chapter numbers m_ich += tsi.ichLim - tsi.ichMin; } } else // Process a text run. { // If it comes after a chapter number, then just return the // chapter number without adding the text. if (nChapter > 0) { break; } // skip to the next run m_ich += tsi.ichLim - tsi.ichMin; } } // determine if this verse is a complete paragraph, an empty para and/or a stanza break. m_isCompletePara = (m_ichVerseStart == 0 && m_ich == m_paraLength); if (string.IsNullOrEmpty(sPara)) { //m_isEmptyPara = true; m_isStanzaBreak = string.Equals(ScrStyleNames.StanzaBreak, m_para.StyleName); } try { return((m_ich > m_ichVerseStart) || FirstTimeAtStanzaBreak); } finally { // Update the previous paragraph for the next time (but we do the update // in a 'finally' so that we can compare the current to the previous for // the return value). m_prevPara = m_para; } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Find the start and end reference, by searching backwards in the given ITsString /// from the given position. /// </summary> /// <param name="tss">the given ITsString</param> /// <param name="ichPos">Index of character in paragraph whose reference we want</param> /// <param name="fAssocPrev">Consider this position to be associated with any preceding /// text in the paragraph (in the case where ichPos is at a chapter boundary).</param> /// <param name="refStart">[out] Start reference for the paragraph.</param> /// <param name="refEnd">[out] End reference for the paragraph.</param> /// <returns>A value of <see cref="ChapterVerseFound"/> that tells if a chapter and/or /// verse number was found in this paragraph.</returns> /// <remarks>If ichPos LT zero, we will not search this para, and simply return. /// Be careful not to use this method to search the contents of paragraph using /// character offsets from the BT! /// </remarks> /// ------------------------------------------------------------------------------------ static public ChapterVerseFound GetBCVRefAtPosWithinTss(ITsString tss, int ichPos, bool fAssocPrev, out BCVRef refStart, out BCVRef refEnd) { refStart = new BCVRef(); refEnd = new BCVRef(); ChapterVerseFound retVal = ChapterVerseFound.None; if (tss.Length <= 0) { return(retVal); } TsRunInfo tsi; ITsTextProps ttpRun; bool fGotVerse = false; int ich = ichPos; if (ich > tss.Length) { ich = tss.Length; } while (ich >= 0) { // Get props of current run. ttpRun = tss.FetchRunInfoAt(ich, out tsi); // If we're at (the front edge of) a C/V number boundary and the // caller said to associate the position with the previous material, then // ignore this run unless we're at the beginning of the para. // The run is actually the *following* run, which we don't care about. if (!fAssocPrev || ichPos <= 0 || ichPos != tsi.ichMin) { // See if it is our verse number style. if (!fGotVerse && StStyle.IsStyle(ttpRun, ScrStyleNames.VerseNumber)) { // The whole run is the verse number. Extract it. string sVerseNum = tss.get_RunText(tsi.irun); // string sVerseNum = tss.Text.Substring(tsi.ichMin, // tsi.ichLim - tsi.ichMin); int startVerse, endVerse; ScrReference.VerseToInt(sVerseNum, out startVerse, out endVerse); refStart.Verse = startVerse; refEnd.Verse = endVerse; fGotVerse = true; retVal = ChapterVerseFound.Verse; } // See if it is our chapter number style. else if (StStyle.IsStyle(ttpRun, ScrStyleNames.ChapterNumber)) { try { // Assume the whole run is the chapter number. Extract it. string sChapterNum = tss.get_RunText(tsi.irun); int nChapter = ScrReference.ChapterToInt(sChapterNum); refStart.Chapter = refEnd.Chapter = nChapter; if (fGotVerse) { // Found a chapter number to go with the verse number we // already found, so build the full reference using this // chapter with the previously found verse (already set). retVal |= ChapterVerseFound.Chapter; } else { // Found a chapter number but no verse number, so assume the // edited text is in verse 1 of the chapter. refStart.Verse = refEnd.Verse = 1; fGotVerse = true; retVal = ChapterVerseFound.Chapter | ChapterVerseFound.Verse; } break; } catch (ArgumentException) { // ignore runs with invalid Chapter numbers } } } // move index (going backwards) to the character just before the Min of the run // we just looked at ich = tsi.ichMin - 1; } return(retVal); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Read the file to build mappings of the markers found /// </summary> /// ------------------------------------------------------------------------------------ protected void GetMappingsFromStream(TextReader reader) { string lineIn; int chapter = -1; int book = -1; int lineCount = 0; // book and chapter strings for reporting info in exceptions string sBookId = null; string sChapter = null; string sVerse = null; // Keep track of the first reference in the file int firstBook = -1; int firstChapter = -1; int firstVerse = -1; ReferenceRange currentRange = null; string marker; string lineText; string nextLineText = null; // used for read-ahead for \fig line when doing strict scanning while ((lineIn = reader.ReadLine()) != null) { lineCount++; while (GetNextMarkerFromData(lineIn, out marker, out lineText)) { // Make sure the marker is valid if (!IsValidMarker(marker)) { throw new ScriptureUtilsException(SUE_ErrorCode.InvalidCharacterInMarker, FileName, lineCount, lineIn, sBookId, sChapter, sVerse); } ImportMappingInfo markerMapping = GetOrCreateMarkerMapping(ref marker); if (marker == ScrMappingList.MarkerBook) { sBookId = lineText.TrimStart().ToUpperInvariant(); // save the book number in the list for this file book = ScrReference.BookToNumber(sBookId); if (book <= 0) { throw new ScriptureUtilsException(SUE_ErrorCode.InvalidBookID, FileName, lineCount, lineIn, sBookId, null, null); } sBookId = ScrReference.NumberToBookCode(book); // Make a new reference range with the book id and // start it out with chapter range of 0-0. AddRangeToList(currentRange); currentRange = new ReferenceRange(book, 0, 0); // If this is the first book, remember it if (firstBook == -1) { firstBook = book; } m_booksInFile.Add(book); chapter = -1; } else { // make sure that a book has been started before seeing any non-excluded markers // This error is a "strict" error because files can be added by a user before there // is a chance to exclude markers in the mappings. When the file is added from the settings // for import, then strict checking will be on. if (book == -1 && m_doStrictFileChecking) { // if the marker is not excluded then throw an error if (markerMapping != null && !markerMapping.IsExcluded) { throw new ScriptureUtilsException(SUE_ErrorCode.UnexcludedDataBeforeIdLine, FileName, lineCount, lineIn, null, null, null); } } if (marker == ScrMappingList.MarkerChapter) { // If there is no book, then throw an error since chapter numbers // are not valid without a book if (book == -1) { throw new ScriptureUtilsException(SUE_ErrorCode.ChapterWithNoBook, FileName, lineCount, lineIn, null, null, null); } try { sChapter = lineText; chapter = ScrReference.ChapterToInt(sChapter); // save the chapter number as the last chapter and possibly the first // chapter number in the range. if (currentRange.StartChapter == 0) { currentRange.StartChapter = chapter; } currentRange.EndChapter = chapter; } catch (ArgumentException) { throw new ScriptureUtilsException(SUE_ErrorCode.InvalidChapterNumber, FileName, lineCount, lineIn, sBookId, sChapter, null); } // If this is the first chapter, remember it if (firstChapter == -1) { firstChapter = chapter; } } else if (marker == ScrMappingList.MarkerVerse) { // If a verse is seen without a book, throw an exception if (book == -1) { throw new ScriptureUtilsException(SUE_ErrorCode.VerseWithNoBook, FileName, lineCount, lineIn, sBookId, null, lineText); } BCVRef firstRef = new BCVRef(book, chapter, 0); BCVRef lastRef = new BCVRef(book, chapter, 0); // check for an invalid verse number if (!BCVRef.VerseToScrRef(lineText, ref firstRef, ref lastRef) || firstRef.Verse == 0 || firstRef.Verse > lastRef.Verse) { throw new ScriptureUtilsException(SUE_ErrorCode.InvalidVerseNumber, FileName, lineCount, lineIn, sBookId, sChapter, lineText); } // If a chapter number has not been seen yet, then throw an exception sVerse = firstRef.Verse.ToString(); if (chapter == -1 && !SingleChapterBook(book)) { throw new ScriptureUtilsException(SUE_ErrorCode.MissingChapterNumber, FileName, lineCount, lineIn, sBookId, null, sVerse); } // If this is the first verse, remember it if (firstVerse == -1) { firstVerse = firstRef.Verse; } } else if (!markerMapping.IsExcluded && m_doStrictFileChecking && markerMapping.MappingTarget == MappingTargetType.Figure) { // First, we need to consider whether any following lines also need // to be read in, since the Figure parameters could be split across // lines. (TE-7669) Debug.Assert(nextLineText == null); int cExtraLinesRead = 0; string sTempMarker, sTempLineText; if (!GetNextMarkerFromData(lineText, out sTempMarker, out sTempLineText)) { while ((nextLineText = reader.ReadLine()) != null) { cExtraLinesRead++; if (GetNextMarkerFromData(nextLineText, out sTempMarker, out sTempLineText)) { // Normally, we want to break the line right before the first marker. int ichMarkerPos = nextLineText.IndexOf(sTempMarker); // But if it's a \fig*, break after the marker. if (sTempMarker == markerMapping.EndMarker) { ichMarkerPos += sTempMarker.Length; } lineText += " " + nextLineText.Substring(0, ichMarkerPos); nextLineText = nextLineText.Substring(ichMarkerPos); break; } else { lineText += " " + nextLineText; } } } string figureParams = lineText; int endMarkerLength = 0; // Validate the tokens for a mapping target (only in strict checking) if (!String.IsNullOrEmpty(markerMapping.EndMarker)) { endMarkerLength = markerMapping.EndMarker.Length; int ichEnd = figureParams.IndexOf(markerMapping.EndMarker); if (ichEnd >= 0) { figureParams = figureParams.Substring(0, ichEnd); } else { endMarkerLength = 0; // end marker is optional and not present } } string[] tokens = figureParams.Split('|'); if (tokens.Length < 6) { throw new ScriptureUtilsException(SUE_ErrorCode.BadFigure, FileName, lineCount, lineIn, sBookId, sChapter, sVerse); } lineText = lineText.Substring(figureParams.Length + endMarkerLength); lineCount += cExtraLinesRead; } } // Mark this mapping as "in-use" because it was found in the scanned file markerMapping.SetIsInUse(m_domain, m_wsId, m_noteType, true); if (m_scanInlineBackslashMarkers) { lineIn = lineText; } else { lineIn = nextLineText; nextLineText = null; if (lineIn == null) { break; } } if (string.IsNullOrEmpty(lineIn) && !string.IsNullOrEmpty(nextLineText)) { lineIn = nextLineText; nextLineText = null; } } } // Add the last range to the list AddRangeToList(currentRange); // If no books were found in the file then throw an exception if (book == -1) { throw new ScriptureUtilsException(SUE_ErrorCode.MissingBook, FileName, lineCount, null, null, null, null); } // If no chapters were found then throw an exception if (chapter == -1 && !SingleChapterBook(book)) { throw new ScriptureUtilsException(SUE_ErrorCode.NoChapterNumber, FileName, lineCount, null, sBookId, null, null); } // Store the first reference for the file m_startRef.Book = firstBook; m_startRef.Chapter = firstChapter == -1 ? 1 : firstChapter; m_startRef.Verse = firstVerse == -1 ? 1 : firstVerse; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Advances the enumerator to the next element of the collection. /// </summary> /// <returns> /// true if the enumerator was successfully advanced to the next element; false if the /// enumerator has passed the end of the collection. /// </returns> /// <exception cref="T:System.InvalidOperationException">The collection was modified /// after the enumerator was created. </exception> /// ------------------------------------------------------------------------------------ public bool MoveNext() { if (m_currentScrText == null) { return(false); } while (++m_currentScrText.m_iRun < m_currentScrText.m_paraTss.RunCount) { m_internalToken.m_fParagraphStart = (m_currentScrText.m_iRun == 0); ITsTextProps runProps = m_currentScrText.m_paraTss.get_Properties(m_currentScrText.m_iRun); string charStyleName = runProps.GetStrPropValue((int)FwTextPropType.ktptNamedStyle); m_internalToken.m_sText = m_currentScrText.m_paraTss.get_RunText(m_currentScrText.m_iRun); m_internalToken.m_paraOffset = m_currentScrText.m_paraTss.get_MinOfRun(m_currentScrText.m_iRun); int var; int ws = runProps.GetIntPropValues((int)FwTextPropType.ktptWs, out var); m_internalToken.m_icuLocale = GetLocale(ws); m_internalToken.Ws = ws; switch (runProps.GetStrPropValue((int)FwTextPropType.ktptNamedStyle)) { case ScrStyleNames.VerseNumber: if (!m_foundStart || string.IsNullOrEmpty(m_internalToken.m_sText)) { continue; } m_internalToken.m_textType = TextType.VerseNumber; int verse = ScrReference.VerseToIntStart(m_internalToken.m_sText); if (verse != 0) { m_internalToken.m_startRef.Verse = verse; } verse = ScrReference.VerseToIntEnd(m_internalToken.m_sText); if (verse != 0) { m_internalToken.m_endRef.Verse = verse; } break; case ScrStyleNames.ChapterNumber: if (string.IsNullOrEmpty(m_internalToken.m_sText)) { continue; } int chapter = 0; try { chapter = ScrReference.ChapterToInt(m_internalToken.m_sText); } catch { // Ignore exceptions. We'll flag them later as errors. } if (!m_foundStart) { if (m_chapterNum != chapter) { continue; } m_foundStart = true; } else if (m_chapterNum > 0 && m_chapterNum != chapter) { // Stop if we're only getting tokens for a single chapter (unless // this is an (erroneous) second occurrence of the same chapter) return(false); } m_internalToken.m_textType = TextType.ChapterNumber; m_internalToken.m_startRef.Chapter = m_internalToken.m_endRef.Chapter = chapter; m_internalToken.m_startRef.Verse = m_internalToken.m_endRef.Verse = 1; break; default: { if (!m_foundStart) { continue; } // Deal with footnotes and picture captions Guid guidObj = StringUtils.GetGuidFromRun(m_currentScrText.m_paraTss, m_currentScrText.m_iRun, runProps); if (guidObj == Guid.Empty) { m_internalToken.m_textType = m_currentScrText.DefaultTextType; } else if (m_outerText != null) { // It was possible through copy/paste to put ORCs into footnotes or pictures, but that is no // longer allowed. This tokenizing code won't handle the nesting correctly, so just ignore // the nested ORC. See TE-8609. continue; } else { m_fOrcWasStartOfPara = m_internalToken.m_fParagraphStart; int hvo = m_book.Cache.GetIdFromGuid(guidObj); if (hvo > 0) { switch (m_book.Cache.GetClassOfObject(hvo)) { case StFootnote.kclsidStFootnote: m_outerText = m_currentScrText; // footnotes are StTexts m_currentScrText = new TokenizableText(new StText(m_book.Cache, hvo), TextType.Note); return(MoveNext()); case CmPicture.kclsidCmPicture: { m_outerText = m_currentScrText; CmPicture pict = new CmPicture(m_book.Cache, hvo); m_currentScrText = new TokenizableText( pict.Caption.VernacularDefaultWritingSystem.UnderlyingTsString, ScrStyleNames.Figure, TextType.PictureCaption, pict, (int)CmPicture.CmPictureTags.kflidCaption); return(MoveNext()); } } } } } break; } m_internalToken.m_fNoteStart = (m_internalToken.m_textType == TextType.Note && m_internalToken.m_fParagraphStart && m_currentScrText.m_iPara == 0); m_internalToken.m_paraStyleName = m_currentScrText.ParaStyleName; m_internalToken.m_charStyleName = charStyleName != null ? charStyleName : string.Empty; m_internalToken.m_object = m_currentScrText.m_obj; m_internalToken.m_flid = m_currentScrText.m_flid; // We need the current token to be a copy of our internal token so we don't change the // internal variables of whatever was returned from the enumerator. m_currentToken = m_internalToken.Copy(); return(true); } // Finished that paragraph and didn't find any more runs; try next para in this text, // if any. if (!m_currentScrText.NextParagraph()) { if (!m_foundStart) { Debug.Fail("We should have found the desired chapter wtihin the section we were searching."); return(false); } // Finished that text and didn't find any more paragraphs. // If we have been processing an inner text (footnote or picture caption), pop back // out to the "outer" one. if (m_outerText != null) { m_currentScrText = m_outerText; m_outerText = null; bool result = MoveNext(); if (result) { m_currentToken.m_fParagraphStart |= m_fOrcWasStartOfPara; m_fOrcWasStartOfPara = false; } return(result); } // Otherwise, try next text, if any. if (m_currentScrText.m_text.OwningFlid == (int)ScrBook.ScrBookTags.kflidTitle) { // Get first section head text. CurrentSectionIndex = 0; } else if (m_currentScrText.m_text.OwningFlid == (int)ScrSection.ScrSectionTags.kflidHeading) { m_currentScrText = new TokenizableText(m_currentSection.ContentOA, m_currentSection.IsIntro ? TextType.Other : TextType.Verse); } else { Debug.Assert(m_currentScrText.m_text.OwningFlid == (int)ScrSection.ScrSectionTags.kflidContent); if (m_iCurrentSection + 1 >= m_book.SectionsOS.Count) { return(false); } CurrentSectionIndex++; if (m_chapterNum > 0 && ScrReference.GetChapterFromBcv(m_currentSection.VerseRefStart) != m_chapterNum) { return(false); } } } return(MoveNext()); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Finds all ORCs in the given text and notes any orphaned footnotes or pictures. /// </summary> /// <param name="text">The text.</param> /// <param name="textLocationInfo">Additional information about the location of the /// text that can help the user find it.</param> /// <param name="startRef">Caller should pass in the initial reference to use as the /// basis for any references found in the course of parsing the text. Returned value /// will be the final reference found, which can be used as the basis for the subsequent /// text</param> /// <param name="endRef">Same as startRef, except in the case of verse bridges or /// section headings</param> /// <param name="footnotes">List of footnotes owned by the book that owns the /// given text. As footnotes are found, their locations will be set.</param> /// <param name="parasWithOrcs">List of paragraphs and ORC positions (excluding known /// picture ORCs).</param> /// <returns></returns> /// ------------------------------------------------------------------------------------ private static bool FindOrcsWithoutPropsInText(IStText text, string textLocationInfo, ref BCVRef startRef, ref BCVRef endRef, List <FootnoteOrcLocation> footnotes, List <OrcLocation> parasWithOrcs) { bool foundOrphan = false; foreach (IStTxtPara para in text.ParagraphsOS) { ITsString tssContents = para.Contents; string sContents = tssContents.Text; if (sContents == null) { continue; } int nRun = tssContents.RunCount; for (int i = 0; i < nRun; i++) { TsRunInfo runInfo; ITsTextProps tprops = tssContents.FetchRunInfo(i, out runInfo); string styleName = tprops.GetStrPropValue( (int)FwTextPropType.ktptNamedStyle); // When a verse number is encountered, save the number into // the reference. if (styleName == ScrStyleNames.VerseNumber) { string sVerseNum = sContents.Substring(runInfo.ichMin, runInfo.ichLim - runInfo.ichMin); int nVerseStart, nVerseEnd; ScrReference.VerseToInt(sVerseNum, out nVerseStart, out nVerseEnd); startRef.Verse = nVerseStart; endRef.Verse = nVerseEnd; } // If a chapter number is encountered then save the number into // the reference and start the verse number back at 1. else if (styleName == ScrStyleNames.ChapterNumber) { try { string sChapterNum = sContents.Substring(runInfo.ichMin, runInfo.ichLim - runInfo.ichMin); startRef.Chapter = endRef.Chapter = ScrReference.ChapterToInt(sChapterNum); startRef.Verse = endRef.Verse = 1; } catch (ArgumentException) { // ignore runs with invalid Chapter numbers } } else { // search contents for ORCs for (int ich = runInfo.ichMin; ich < runInfo.ichLim; ich++) { if (sContents[ich] != StringUtils.kChObject) { continue; } OrcLocation orcLocation = new OrcLocation(para, ich, startRef, endRef, textLocationInfo); ITsTextProps props = tssContents.get_PropertiesAt(ich); string objData = props.GetStrPropValue((int)FwTextPropType.ktptObjData); if (objData == null) { foundOrphan = true; } else { // first char. of strData is type code - GUID will follow it. Guid objGuid = MiscUtils.GetGuidFromObjData(objData.Substring(1)); ICmObject obj; if (!text.Cache.ServiceLocator.ObjectRepository.TryGetObject(objGuid, out obj)) { foundOrphan = true; } else if (obj.ClassID == ScrFootnoteTags.kClassId) { foreach (FootnoteOrcLocation footnote in footnotes) { if (footnote.footnote.Guid == objGuid) { orcLocation.Footnote = footnote.footnote; footnote.location = orcLocation; break; } } } else { Debug.Assert(obj.ClassID == CmPictureTags.kClassId, "Unknown class id in embedded object: " + obj.ClassID); continue; } } parasWithOrcs.Add(orcLocation); } } } } return(foundOrphan); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Gets the reference for this footnote. /// </summary> /// <param name="owningBook">The owning book.</param> /// <param name="para">The para to search for a Scripture reference (verse or chapter). /// </param> /// <param name="startRef">The starting reference for this footnote (updated in this /// method).</param> /// <param name="endRef">The ending reference for this footnote (updated in this /// method).</param> /// <returns></returns> /// ------------------------------------------------------------------------------------ private RefResult GetReference(IScrBook owningBook, IScrTxtPara para, BCVRef startRef, BCVRef endRef) { bool foundSelf = (para != ParaContainingOrcRA); IStFootnoteRepository footnoteRepo = Cache.ServiceLocator.GetInstance <IStFootnoteRepository>(); ITsString tssContents = para.Contents; for (int i = tssContents.RunCount - 1; i >= 0; i--) { string styleName = tssContents.get_StringProperty(i, (int)FwTextPropType.ktptNamedStyle); if (foundSelf && styleName == ScrStyleNames.VerseNumber && startRef.Verse == 0) { int nVerseStart, nVerseEnd; ScrReference.VerseToInt(tssContents.get_RunText(i), out nVerseStart, out nVerseEnd); startRef.Verse = nVerseStart; endRef.Verse = nVerseEnd; } else if (foundSelf && styleName == ScrStyleNames.ChapterNumber && startRef.Chapter == 0) { try { startRef.Chapter = endRef.Chapter = ScrReference.ChapterToInt(tssContents.get_RunText(i)); } catch (ArgumentException) { // ignore runs with invalid Chapter numbers } if (startRef.Verse == 0) { startRef.Verse = endRef.Verse = 1; } } else if (styleName == null) { IScrFootnote footnote = (IScrFootnote)footnoteRepo.GetFootnoteFromObjData(tssContents.get_StringProperty(i, (int)FwTextPropType.ktptObjData)); if (footnote != null) { if (footnote == this) { foundSelf = true; continue; } RefRange otherFootnoteLocation = ((ScrFootnote)footnote).FootnoteRefInfo_Internal; if (foundSelf && otherFootnoteLocation != RefRange.EMPTY) { // Found another footnote with a reference we can use if (startRef.Verse == 0) { startRef.Verse = otherFootnoteLocation.StartRef.Verse; endRef.Verse = otherFootnoteLocation.EndRef.Verse; } if (startRef.Chapter == 0) { startRef.Chapter = otherFootnoteLocation.StartRef.Chapter; endRef.Chapter = otherFootnoteLocation.EndRef.Chapter; } } else if (foundSelf) { // Previous footnote does not have a reference yet. We presume, for performance // reasons, that none of the previous footnotes have valid references yet, so // we set all the footnotes for the book. ((ScrBook)owningBook).RefreshFootnoteRefs(); return(RefResult.ScannedAllFootnotes); } } } if (startRef.Verse != 0 && endRef.Verse != 0 && startRef.Chapter != 0 && endRef.Chapter != 0) { return(RefResult.Found); } } return(RefResult.NotFound); }