From 3e0a20f64f2a56ef8983cdcad92bb300547c2e01 Mon Sep 17 00:00:00 2001 From: Mathias Claassen Date: Mon, 20 Nov 2017 12:38:11 +0000 Subject: [PATCH] USFM section heading support --- README.md | 13 +++++++++++++ src/GoBibleCreator.java | 27 ++++++++++++++++++++++++++- src/USFMParse.java | 32 ++++++++++++++++++++++++++++---- 3 files changed, 67 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 50b5ea5..a609ab9 100644 --- a/README.md +++ b/README.md @@ -13,3 +13,16 @@ NB. This repository does **not** include the source code for **GoBibleCore**. Following the rapid growth of _smart phones_, apps like **Go Bible** for _feature phones_ are now well past their peak popularity. **Go Bible** is no longer being actively developed. + +## Introduction + +GoBibleCore will create the core of an app for MIDP 2.0 cmpatible phones. It does not the Bible information per se, which is what you have to add using GoBibleCreator. +GoBibleCreator will take GoBibleCore's output jar file and add the selected Bible books to that file. To do this both of them follow a specific format which is explained at https://github.com/DavidHaslam/GoBibleCore. +The latest update includes section headings whih were not present before. + +## Section headings + +Since November 2017 GoBible apps can also show section headings. This is currently only supported for USFM file formats. + +#### USFM +GBC will parse \s, \s1, \s2 tags and pass them as headings to GoBibleCore. diff --git a/src/GoBibleCreator.java b/src/GoBibleCreator.java index abf35d8..f8081f9 100644 --- a/src/GoBibleCreator.java +++ b/src/GoBibleCreator.java @@ -1640,6 +1640,7 @@ public static void writeMultipleBooks(JarOutputStream jarOutputStream, Collectio int fileNumber = 0; StringBuffer buffer = new StringBuffer(); + StringBuffer headingBuffer = new StringBuffer(); for (int chapterNumber = collectionBook.startChapter; chapterNumber <= collectionBook.endChapter; chapterNumber++) { @@ -1689,6 +1690,9 @@ public static void writeMultipleBooks(JarOutputStream jarOutputStream, Collectio jarOutputStream.putNextEntry(new JarEntry("Bible Data/" + thmlBook.fileName + "/" + thmlBook.fileName + " " + chapterNumber)); jarOutputStream.write(byteArray, 0, byteArray.length); } + + // We add all headings to the buffer. Headings of one book go together in one entry + headingBuffer.append(chapter.allHeadings.toString()); } if (COMBINED_CHAPTERS) @@ -1707,6 +1711,14 @@ public static void writeMultipleBooks(JarOutputStream jarOutputStream, Collectio dataOutputStream.writeInt(verseBytes.length); dataOutputStream.write(verseBytes, 0, verseBytes.length); } + + if (headingBuffer.length() > 0) { + // Write Headings file + jarOutputStream.putNextEntry(new JarEntry("Bible Data/" + thmlBook.fileName + "/Headings")); + byte[] headingBytes = headingBuffer.toString().getBytes("UTF-8"); + dataOutputStream.writeInt(headingBytes.length); + dataOutputStream.write(headingBytes, 0, headingBytes.length); + } } } @@ -1727,12 +1739,23 @@ public static void writeMultipleBookIndex(/*File directory,*/ JarOutputStream ja for (int chapterNumber = collectionBook.startChapter; chapterNumber <= collectionBook.endChapter; chapterNumber++) { Chapter chapter = (Chapter) xmlBook.chapters.elementAt(chapterNumber - xmlBook.startChapter); - + + // Write the number of headings + output.writeShort(chapter.headingInfo.size()/2); // we have 2 entries for each heading + for (Enumeration e = chapter.verses.elements(); e.hasMoreElements(); ) { String verse = (String) e.nextElement(); output.writeShort(verse.length()); } + + // headingInfo contains two entries for each heading. The first says after which verse each heading goes + // and the second says its length in characters + for (Enumeration e = chapter.headingInfo.elements(); e.hasMoreElements(); ) + { + int num = (int) e.nextElement(); + output.writeShort(num); + } } output.close(); @@ -2270,6 +2293,8 @@ class Chapter public Vector verses = new Vector(); public StringBuffer allVerses = new StringBuffer(); public int fileNumber; + public StringBuffer allHeadings = new StringBuffer(); + public Vector headingInfo = new Vector(); // stores after which verse the heading goes and its length (2 ints per heading) } diff --git a/src/USFMParse.java b/src/USFMParse.java index 66bd302..243ac47 100644 --- a/src/USFMParse.java +++ b/src/USFMParse.java @@ -320,11 +320,13 @@ public Chapter parseChapter() { try { // remove chapter headers part: delete everything before the first \v + // we now try to keep the headers and add it to the first verse + String heading = ""; LOOP: while (true) { lex(); switch (current.type) { - case TAG_OPEN: + case TAG_OPEN: if (current.data.equals("v")) { break LOOP; } @@ -333,6 +335,13 @@ else if (current.data.equals("c")) { // empty chapter System.out.println(current.toString()); return c; } + else if (isHeading(current.data)) { + heading = parseVerse2(); + c.headingInfo.add(0); + c.headingInfo.add(heading.length()); + c.allHeadings.append(heading); + break LOOP; + } break; case EOF: return null; @@ -344,6 +353,7 @@ else if (current.data.equals("c")) { // empty chapter if (verseBody.length() == 0 && this.emptyVerseString != null) { verseBody = new String(this.emptyVerseString); } + c.verses.add(verseBody); c.allVerses.append(verseBody); // System.err.printf("ch vs %d %s\n", @@ -351,8 +361,15 @@ else if (current.data.equals("c")) { // empty chapter // ((String)c.verses.get( c.verses.size() - 1 )).trim()); // time to return because it's the next chapter - if (current.type == SymbolType.TAG_OPEN && current.data.equals("c") ) { - break; + if (current.type == SymbolType.TAG_OPEN ) { + if (current.data.equals("c")) { + break; + } else if (isHeading(current.data)) { + heading = parseVerse2(); + c.headingInfo.add(c.verses.size()); + c.headingInfo.add(heading.length()); + c.allHeadings.append(heading); + } } } @@ -432,6 +449,9 @@ else if (isDoubleTextualTag(current.data)) { else if (current.data.equals("c")) { // new chapter return handleWhitespace(body.toString()); } + else if (isHeading(current.data)) { // new chapter + return handleWhitespace(body.toString()); + } if (macroReplacementTable.containsKey(current.data)) { body.append(macroReplacementTable.get(current.data)); } @@ -482,7 +502,7 @@ else if (isDoubleAnnotationTag(current.data)) { else return handleWhitespace(body.toString()); } - + public String handleWhitespace(String s) { String parts[] = configTable.get("SignificantWhitespace"); @@ -506,6 +526,10 @@ private boolean isSingularTag(String comp) { return false; } + + private boolean isHeading(String comp) { + return comp.equals("s") || comp.equals("s1") || comp.equals("s2"); + } private boolean isSingularGreedyTag(String comp) {