/// ------------------------------------------------------------------------------------ /// <summary> /// Add a mapping to the mapping list. /// </summary> /// <param name="mapping">mapping info to add to the list</param> /// ------------------------------------------------------------------------------------ public void Add(ImportMappingInfo mapping) { if (mapping == null) { throw new ArgumentNullException(); } if (string.IsNullOrEmpty(mapping.BeginMarker)) { throw new ArgumentException("Begin marker must be set before adding mapping to the list."); } if (mapping.BeginMarker == MarkerChapter) { // REVIEW: Do we also need to do this for the Annotations domain. What does the importer expect? mapping.StyleName = ScrStyleNames.ChapterNumber; } else if (mapping.BeginMarker == MarkerVerse) { // REVIEW: Do we also need to do this for the Annotations domain. What does the importer expect? mapping.StyleName = ScrStyleNames.VerseNumber; } else if (mapping.BeginMarker == MarkerBook) { // \id markers do not have a style or domain mapping.Domain = MarkerDomain.Default; mapping.StyleName = null; } else { switch (m_mappingSet) { case MappingSet.Main: // If this is a BT marker but it's already in the list in the Default domain, clear the // BT flag and make sure it isn't being redefined. if ((mapping.Domain & MarkerDomain.BackTrans) != 0 && m_list.ContainsKey(mapping.BeginMarker)) { ImportMappingInfo existingMapping = this[mapping.BeginMarker]; if ((existingMapping.Domain & MarkerDomain.BackTrans) == 0) { mapping.Domain = existingMapping.Domain; } } break; case MappingSet.Notes: // If the mapping is for the annotations domain and it is marked as Note, then // set it to Default. if (mapping.Domain == MarkerDomain.Note) { mapping.Domain = MarkerDomain.Default; } if (mapping.Domain != MarkerDomain.Default) { throw new ArgumentException("Invalid mapping domain"); } break; } } m_list[mapping.BeginMarker] = mapping; mapping.HasChanged = true; }
/// ------------------------------------------------------------------------------------ /// <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> /// Add a default mapping for the given Standard Format marker if it does not exist yet. /// </summary> /// <param name="marker">The SF marker</param> /// <param name="endMarker">The end marker (or null)</param> /// <param name="importDomain">The import domain from which this marker originates</param> /// <param name="fAutoMapBtMarkers">Indicates whether markers beginning with "bt" should /// be treated as back-translation markers if possible.</param> /// <param name="isInUse">Indicates whether this marker is actually in use in one or more /// of the import files (for P6, this is currently always false since we're getting the /// markers from the STY file -- we come back in a second pass and set it to true if we /// find it in a file).</param> /// <returns>The newly added mapping info, or the existing one if already in the list /// </returns> /// ------------------------------------------------------------------------------------ public ImportMappingInfo AddDefaultMappingIfNeeded(string marker, string endMarker, ImportDomain importDomain, bool fAutoMapBtMarkers, bool isInUse) { // Look for the marker - if it is found and it maps to a Style, then we are done if (this[marker] != null && !string.IsNullOrEmpty(this[marker].StyleName)) { return(this[marker]); } // Read the TEStyles XML file to generate a table of mappings if (!m_defaultMappingsLoaded && !string.IsNullOrEmpty(TeStylesPath)) { ReadDefaultMappings(); } string styleName; bool excluded; MappingTargetType target; MarkerDomain markerDomain = (importDomain != ImportDomain.BackTrans) ? MarkerDomain.Default : MarkerDomain.BackTrans; if (importDomain == ImportDomain.Annotations) { // TODO (TE-5004): Map \rem (and possibly other markers?) automatically in annotations // domain. Probably need to have a separate import mapping set in TeStyles.xml that has // default mappings for the Annotations domain. styleName = null; excluded = m_defaultExclusions.ContainsKey(marker); //Make sure to check exclusions (TE-5703) target = MappingTargetType.TEStyle; } else if (!GetDefaultMapping(marker, out styleName, out excluded, out target, ref markerDomain)) { if (fAutoMapBtMarkers && importDomain == ImportDomain.Main && marker.StartsWith(@"\bt") && marker != @"\btc") { // pick out the corresponding vernacular marker. "\btblah" -> "\blah" string correspondingVernMarker = marker.Remove(1, 2); // if domain is DeprecatedScripture and the corresponding vernacular marker is defined... ImportMappingInfo correspondingVernMarkerInfo = this[correspondingVernMarker]; if (correspondingVernMarkerInfo != null && (correspondingVernMarkerInfo.Domain & MarkerDomain.DeprecatedScripture) != 0) { // clear the DeprecatedScripture bit. correspondingVernMarkerInfo.Domain ^= MarkerDomain.DeprecatedScripture; } if (correspondingVernMarkerInfo != null) { // If the corresponding vernacular marker is already defined... if (correspondingVernMarkerInfo.Domain != MarkerDomain.Note && (correspondingVernMarkerInfo.Domain & MarkerDomain.BackTrans) == 0 && (correspondingVernMarkerInfo.MappingTarget != MappingTargetType.TEStyle || correspondingVernMarkerInfo.StyleName != null)) { styleName = correspondingVernMarkerInfo.StyleName; target = correspondingVernMarkerInfo.MappingTarget; markerDomain = correspondingVernMarkerInfo.Domain; // We only want to map to the BackTrans domain when mapping to a paragraph // style because character styles automatically assume the domain of their // containing paragraphs. if (StyleSheet == null || styleName == null || StyleSheet.GetType(styleName) == (int)StyleType.kstParagraph) { markerDomain |= MarkerDomain.BackTrans; } } } else if (GetDefaultMapping(correspondingVernMarker, out styleName, out excluded, out target, ref markerDomain)) { // The corresponding vernacular marker has default mapping info so make this marker // a back translation of it - unless it is an annotation or BT. if (markerDomain == MarkerDomain.Note || markerDomain == MarkerDomain.BackTrans) { styleName = null; excluded = false; target = MappingTargetType.TEStyle; markerDomain = MarkerDomain.Default; } else { markerDomain |= MarkerDomain.BackTrans; } } } } // Create a mapping for the marker using the default mapping ImportMappingInfo newMapping = new ImportMappingInfo(marker, endMarker, excluded, target, markerDomain, styleName, null, null, isInUse, importDomain); Add(newMapping); return(newMapping); }