| ConfigEntryType.java |
1 /**
2 * Distribution License:
3 * JSword is free software; you can redistribute it and/or modify it under
4 * the terms of the GNU Lesser General Public License, version 2.1 as published by
5 * the Free Software Foundation. This program is distributed in the hope
6 * that it will be useful, but WITHOUT ANY WARRANTY; without even the
7 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8 * See the GNU Lesser General Public License for more details.
9 *
10 * The License is available on the internet at:
11 * http://www.gnu.org/copyleft/lgpl.html
12 * or by writing to:
13 * Free Software Foundation, Inc.
14 * 59 Temple Place - Suite 330
15 * Boston, MA 02111-1307, USA
16 *
17 * Copyright: 2005
18 * The copyright to this program is held by it's authors.
19 *
20 * ID: $Id: ConfigEntryType.java 2223 2012-01-26 21:28:02Z dmsmith $
21 */
22 package org.crosswire.jsword.book.sword;
23
24 import java.util.regex.Pattern;
25
26 import org.crosswire.common.util.Language;
27 import org.crosswire.common.util.Version;
28 import org.crosswire.jsword.book.BookCategory;
29
30 /**
31 * Constants for the keys in a Sword Config file. Taken from
32 * http://sword.sourceforge.net/cgi-bin/twiki/view/Swordapi/ConfFileLayout<br/>
33 * now located at
34 * http://www.crosswire.org/ucgi-bin/twiki/view/Swordapi/ConfFileLayout<br/>
35 * now located at http://www.crosswire.org/wiki/index.php/DevTools:Modules<br/>
36 * now located at http://www.crosswire.org/wiki/DevTools:confFiles<br/>
37 * <p>
38 * Note: This file is organized the same as the latest wiki documentation.
39 *
40 * @see gnu.lgpl.License for license details.<br>
41 * The copyright to this program is held by it's authors.
42 * @author Joe Walker [joe at eireneh dot com]
43 * @author DM Smith [dmsmith555 at yahoo dot com]
44 */
45 public enum ConfigEntryType {
46 /**
47 * The abbreviated name by which this book is known. This is in the [] on
48 * the first non-blank line of the conf. JSword uses this for display and
49 * access purposes.
50 */
51 INITIALS("Initials") {
52 @Override
53 public boolean isSynthetic() {
54 return true;
55 }
56 },
57
58 /**
59 * Relative path to the data files, some issues with this
60 */
61 DATA_PATH("DataPath") {
62 @Override
63 public boolean isAllowed(String value) {
64 return true;
65 }
66 },
67
68 /**
69 * The full name of this book
70 */
71 DESCRIPTION("Description"),
72
73 /**
74 * This indicates how the book was stored.
75 */
76 MOD_DRV("ModDrv", -1,
77 "RawText",
78 "zText",
79 "RawCom",
80 "RawCom4",
81 "zCom",
82 "HREFCom",
83 "RawFiles",
84 "RawLD",
85 "RawLD4",
86 "zLD",
87 "RawGenBook"
88 ),
89
90 /**
91 * The type of compression in use. While LZSS is the default, it is not used.
92 * At least so far.
93 */
94 COMPRESS_TYPE("CompressType", 0,
95 "LZSS",
96 "ZIP"
97 ),
98
99 /**
100 * The level at which compression is applied, BOOK, CHAPTER, or VERSE
101 */
102 BLOCK_TYPE("BlockType", 1,
103 "BOOK",
104 "CHAPTER",
105 "VERSE"
106 ),
107
108 /**
109 * single value integer, unknown use, some indications that we ought to be
110 * using it
111 */
112 BLOCK_COUNT("BlockCount", "200") {
113 @Override
114 public boolean isAllowed(String aValue) {
115 try {
116 Integer.parseInt(aValue);
117 return true;
118 } catch (NumberFormatException e) {
119 return false;
120 }
121 }
122
123 @Override
124 public Object convert(String input) {
125 try {
126 return Integer.valueOf(input);
127 } catch (NumberFormatException e) {
128 return getDefault();
129 }
130 }
131 },
132
133 /**
134 * The kind of key that a Generic Book uses.
135 */
136 KEY_TYPE("KeyType", 0,
137 "TreeKey",
138 "VerseKey"
139 ),
140
141 /**
142 * If this exists in the conf, then the book is encrypted. The value is used
143 * to unlock the book. The encryption algorithm is Sapphire.
144 */
145 CIPHER_KEY("CipherKey"),
146
147 /**
148 * This indicates the versification of the book, with KJV being the default.
149 */
150 VERSIFICATION("Versification", 3,
151 "Catholic",
152 "Catholic2",
153 "German",
154 "KJV",
155 "KJVA",
156 "Leningrad",
157 "Luther",
158 "MT",
159 "NRSV",
160 "NRSVA",
161 "Synodal",
162 "SynodalP",
163 "Vulg"
164 ),
165
166 /**
167 * Global Option Filters are the names of routines in SWORD that can be used
168 * to display the data. These are not used by JSword.
169 */
170 GLOBAL_OPTION_FILTER("GlobalOptionFilter", -1,
171 "GBFStrongs",
172 "GBFFootnotes",
173 "GBFMorph",
174 "GBFHeadings",
175 "GBFRedLetterWords",
176 "GBFScripref", // no longer in wiki
177 "ThMLStrongs",
178 "ThMLFootnotes",
179 "ThMLScripref",
180 "ThMLMorph",
181 "ThMLHeadings",
182 "ThMLVariants",
183 "ThMLLemma",
184 "UTF8Cantillation",
185 "UTF8GreekAccents",
186 "UTF8HebrewPoints",
187 "OSISStrongs",
188 "OSISFootnotes",
189 "OSISScripref",
190 "OSISMorph",
191 "OSISHeadings",
192 "OSISVariants",
193 "OSISRedLetterWords",
194 "OSISLemma",
195 "OSISRuby"
196 )
197 {
198 @Override
199 public boolean mayRepeat() {
200 return true;
201 }
202 },
203
204 /**
205 * The layout direction of the text in the book. Hebrew, Arabic and Farsi
206 * RtoL. Most are 'LtoR'. Some are 'bidi', bi-directional. E.g.
207 * hebrew-english glossary.
208 */
209 DIRECTION("Direction", 0,
210 "LtoR",
211 "RtoL",
212 "bidi"
213 ),
214
215 /**
216 * This indicates the kind of markup used for the book.
217 */
218 SOURCE_TYPE("SourceType", 0,
219 "Plaintext",
220 "GBF",
221 "ThML",
222 "OSIS",
223 "TEI"
224 ),
225
226 /**
227 * The character encoding. Only Latin-1 and UTF-8 are supported.
228 */
229 ENCODING("Encoding", 0,
230 "Latin-1",
231 "UTF-8"
232 ),
233
234 /**
235 * Display level is used by GenBooks to do auto expansion in the tree. A
236 * level of 2 indicates that the first two levels should be shown.
237 */
238 DISPLAY_LEVEL("DisplayLevel", "1") {
239 @Override
240 public boolean isAllowed(String value) {
241 try {
242 Integer.parseInt(value);
243 return true;
244 } catch (NumberFormatException e) {
245 return false;
246 }
247 }
248
249 @Override
250 public Object convert(String input) {
251 try {
252 return Integer.valueOf(input);
253 } catch (NumberFormatException e) {
254 return null;
255 }
256 }
257 },
258
259 /**
260 * A recommended font to use for the book.
261 */
262 FONT("Font"),
263
264 /**
265 * When false do not show quotation marks for OSIS text that has <q>
266 * elements.
267 */
268 OSIS_Q_TO_TICK("OSISqToTick", 0,
269 "true",
270 "false"
271 )
272 {
273 @Override
274 public Object convert(String input) {
275 return Boolean.valueOf(input);
276 }
277 },
278
279 /**
280 * A Feature describes a characteristic of the Book.
281 */
282 FEATURE("Feature", -1,
283 "StrongsNumbers",
284 "GreekDef",
285 "HebrewDef",
286 "GreekParse",
287 "HebrewParse",
288 "DailyDevotion",
289 "Glossary",
290 "Images"
291 )
292 {
293 @Override
294 public boolean mayRepeat() {
295 return true;
296 }
297 },
298
299 /**
300 * Books with a Feature of Glossary are used to map words FROM one language
301 * TO another.
302 */
303 GLOSSARY_FROM("GlossaryFrom") {
304 @Override
305 public Object convert(String input) {
306 return new Language(input);
307 }
308
309 @Override
310 public String unconvert(Object internal) {
311 if (internal instanceof Language) {
312 return ((Language) internal).getCode();
313 }
314 return super.unconvert(internal);
315 }
316 },
317
318 /**
319 * Books with a Feature of Glossary are used to map words FROM one language
320 * TO another.
321 */
322 GLOSSARY_TO("GlossaryTo") {
323 @Override
324 public Object convert(String input) {
325 return new Language(input);
326 }
327
328 @Override
329 public String unconvert(Object internal) {
330 if (internal instanceof Language) {
331 return ((Language) internal).getCode();
332 }
333 return super.unconvert(internal);
334 }
335 },
336
337 /**
338 * The short name of this book.
339 */
340 ABBREVIATION("Abbreviation"),
341
342 /**
343 * Contains rtf that describes the book.
344 */
345 ABOUT("About") {
346 @Override
347 public boolean allowsContinuation() {
348 return true;
349 }
350
351 @Override
352 public boolean allowsRTF() {
353 return true;
354 }
355 },
356
357 /**
358 * An informational string indicating the current version of the book.
359 */
360 VERSION("Version", "1.0") {
361 @Override
362 public boolean isAllowed(String aValue) {
363 try {
364 new Version(aValue);
365 return true;
366 } catch (IllegalArgumentException e) {
367 return false;
368 }
369 }
370 @Override
371 public Object convert(String input) {
372 try {
373 return new Version(input);
374 } catch (IllegalArgumentException e) {
375 return null;
376 }
377 }
378 },
379
380 /**
381 * multiple values starting with History, some sort of change-log. In the
382 * conf these are of the form History_x.y. We strip off the x.y and prefix
383 * the value with it. The x.y corresponds to a current or prior Version
384 * value.
385 */
386 HISTORY("History") {
387 @Override
388 public boolean mayRepeat() {
389 return true;
390 }
391
392 @Override
393 public boolean reportDetails() {
394 return false;
395 }
396 },
397
398 /**
399 * single value version number, lowest sword c++ version that can read this
400 * book JSword does not use this value.
401 */
402 MINIMUM_VERSION("MinimumVersion", "1.5.1a"),
403
404 /**
405 * The Category of the book. Used on the web to classify books into a tree.
406 */
407 CATEGORY("Category", 0,
408 "Other",
409 "Daily Devotional",
410 "Glossaries",
411 "Cults / Unorthodox / Questionable Material",
412 "Essays",
413 "Maps",
414 "Images",
415 "Biblical Texts",
416 "Commentaries",
417 "Lexicons / Dictionaries",
418 "Generic Books"
419 )
420 {
421 @Override
422 public Object convert(String input) {
423 return BookCategory.fromString(input);
424 }
425 },
426
427 /**
428 * Library of Congress Subject Heading. Typically this is of the form
429 * BookCategory Scope Language, where scope is typically O.T., N.T.
430 */
431 LCSH("LCSH"),
432
433 /**
434 * single value string, defaults to en, the language of the book
435 */
436 LANG("Lang", "en") {
437 @Override
438 public Object convert(String input) {
439 return new Language(input);
440 }
441
442 @Override
443 public String unconvert(Object internal) {
444 if (internal instanceof Language) {
445 return ((Language) internal).getCode();
446 }
447 return super.unconvert(internal);
448 }
449 },
450
451 /**
452 * The installed size of the book in bytes. This is not the size of the zip
453 * that is downloaded.
454 */
455 INSTALL_SIZE("InstallSize") {
456 @Override
457 public boolean isAllowed(String value) {
458 try {
459 Integer.parseInt(value);
460 return true;
461 } catch (NumberFormatException e) {
462 return false;
463 }
464 }
465
466 @Override
467 public Object convert(String input) {
468 try {
469 return Integer.valueOf(input);
470 } catch (NumberFormatException e) {
471 return null;
472 }
473 }
474 },
475
476 /**
477 * The date that this version of the book was last updated. Informational
478 * only.
479 */
480 SWORD_VERSION_DATE("SwordVersionDate") {
481 @Override
482 public boolean isAllowed(String value) {
483 return validDatePattern.matcher(value).matches();
484 }
485
486 private Pattern validDatePattern = Pattern.compile("\\d{4}-\\d{2}-\\d{2}");
487 },
488
489 /**
490 * A list of prior "initials" for the current book.
491 * TODO(dms): when a user installs a book with an obsoletes that matches
492 * an installed book, offer the user the opportunity to delete the old book.
493 */
494 OBSOLETES("Obsoletes") {
495 @Override
496 public boolean mayRepeat() {
497 return true;
498 }
499
500 @Override
501 public boolean reportDetails() {
502 return false;
503 }
504 },
505
506 /**
507 * Single value version number, lowest sword c++ version that can read this
508 * book JSword does not use this value.
509 */
510 OSIS_VERSION("OSISVersion"),
511
512 /**
513 * Informational copyright notice.
514 */
515 COPYRIGHT("Copyright") {
516 @Override
517 public boolean allowsContinuation() {
518 return true;
519 }
520 },
521
522 /**
523 * single value string, unknown use
524 */
525 COPYRIGHT_HOLDER("CopyrightHolder"),
526
527 /**
528 * Copyright info. Informational only.
529 * This is a year, a year range or a comma separated list of these.
530 */
531 COPYRIGHT_DATE("CopyrightDate") {
532 @Override
533 public boolean isAllowed(String value) {
534 return validDatePattern.matcher(value).matches();
535 }
536
537 private Pattern validDatePattern = Pattern.compile("\\d{4}(\\s*-\\s*\\d{4})?(\\s*,\\s*\\d{4}(\\s*-\\s*\\d{4})?)*");
538 },
539
540 /**
541 * Copyright info. Informational only.
542 */
543 COPYRIGHT_NOTES("CopyrightNotes") {
544 @Override
545 public boolean allowsContinuation() {
546 return true;
547 }
548
549 @Override
550 public boolean allowsRTF() {
551 return true;
552 }
553 },
554
555 /**
556 * Copyright info. Informational only.
557 */
558 COPYRIGHT_CONTACT_NAME("CopyrightContactName") {
559 @Override
560 public boolean allowsContinuation() {
561 return true;
562 }
563
564 @Override
565 public boolean allowsRTF() {
566 return true;
567 }
568 },
569
570 /**
571 * Copyright info. Informational only.
572 */
573 COPYRIGHT_CONTACT_NOTES("CopyrightContactNotes") {
574
575 @Override
576 public boolean allowsContinuation() {
577 return true;
578 }
579
580 @Override
581 public boolean allowsRTF() {
582 return true;
583 }
584 },
585
586 /**
587 * Copyright info. Informational only.
588 */
589 COPYRIGHT_CONTACT_ADDRESS("CopyrightContactAddress") {
590 @Override
591 public boolean allowsContinuation() {
592 return true;
593 }
594
595 @Override
596 public boolean allowsRTF() {
597 return true;
598 }
599 },
600
601 /**
602 * Copyright info. Informational only.
603 */
604 COPYRIGHT_CONTACT_EMAIL("CopyrightContactEmail"),
605
606 /**
607 * A one line promo statement, required by Lockman for NASB
608 */
609 SHORT_PROMO("ShortPromo"),
610
611 /**
612 * A one line copyright statement, required by Lockman for NASB
613 */
614 SHORT_COPYRIGHT("ShortCopyright"),
615
616 /**
617 * Copyright info. Informational only.
618 */
619 DISTRIBUTION_LICENSE("DistributionLicense", 0,
620 "Public Domain",
621 "Copyrighted",
622 "Copyrighted; Free non-commercial distribution",
623 "Copyrighted; Permission to distribute granted to CrossWire",
624 "Copyrighted; Freely distributable",
625 "Copyrighted; Permission granted to distribute non-commercially in Sword format",
626 "GFDL",
627 "GPL",
628 "Creative Commons: by-nc-nd",
629 "Creative Commons: by-nc-sa",
630 "Creative Commons: by-nc",
631 "Creative Commons: by-nd",
632 "Creative Commons: by-sa",
633 "Creative Commons: by"
634 ),
635
636 /**
637 * Copyright info. Informational only.
638 */
639 DISTRIBUTION_NOTES("DistributionNotes") {
640
641 @Override
642 public boolean allowsContinuation() {
643 return true;
644 }
645 },
646
647 /**
648 * Information on where the book's text was obtained.
649 */
650 TEXT_SOURCE("TextSource") {
651
652 @Override
653 public boolean allowsContinuation() {
654 return true;
655 }
656 },
657
658 /**
659 * Contains the URL (a bare URL, not an HTML <a> link) of a web page for unlocking instructions/payment.
660 */
661 UNLOCK_URL("UnlockURL"),
662
663 /**
664 * Deliberately not in wiki. Similar to DataPath. It gives where on the CrossWire server the book can
665 * be found. Informational only.
666 */
667 DISTRIBUTION_SOURCE("DistributionSource") {
668
669 @Override
670 public boolean allowsContinuation() {
671 return true;
672 }
673 },
674
675 /**
676 * New. Not in wiki. Present in SWORD engine. Present in hesychius.conf w/ PapyriPlain
677 */
678 LOCAL_STRIP_FILTER("LocalStripFilter"),
679
680 /**
681 * New. Not in wiki. Present in SWORD engine. Present in hesychius.conf w/ IncludeKeyInSearch
682 */
683 SEARCH_OPTION("SearchOption"),
684
685 /**
686 * The location of a collection of modules. JSword uses this to install and
687 * delete a module.
688 */
689 LIBRARY_URL("LibraryURL") {
690 @Override
691 public boolean isSynthetic() {
692 return true;
693 }
694 },
695
696 /**
697 * The location of the module. JSword uses this to access a module.
698 */
699 LOCATION_URL("LocationURL") {
700 @Override
701 public boolean isSynthetic() {
702 return true;
703 }
704 };
705
706 /**
707 * Simple ctor
708 */
709 private ConfigEntryType(String name) {
710 this.name = name;
711 this.defaultValue = null;
712 this.picks = null;
713 }
714
715 /**
716 * Simple ctor
717 */
718 private ConfigEntryType(String name, String defaultValue) {
719 this.name = name;
720 this.defaultValue = convert(defaultValue);
721 this.picks = null;
722 }
723
724 /**
725 * Simple ctor
726 */
727 private ConfigEntryType(String name, int defaultPick, String... picks) {
728 this.name = name;
729 if (defaultPick >= 0 && defaultPick < picks.length) {
730 this.defaultValue = convert(picks[defaultPick]);
731 } else {
732 this.defaultValue = null;
733 }
734 this.picks = picks;
735 }
736
737 /**
738 * Returns the normalized name of this ConfigEntry.
739 *
740 * @return the name
741 */
742 public String getName() {
743 return name;
744 }
745
746 /**
747 * Determines whether the string is allowed. For some config entries, the
748 * value is expected to be one of a group, for others the format is defined.
749 *
750 * @param value
751 * the string to be checked
752 * @return true if the string is allowed
753 */
754 public boolean isAllowed(String value) {
755 if (hasChoices()) {
756 for (String pick : picks) {
757 if (pick.equalsIgnoreCase(value)) {
758 return true;
759 }
760 }
761
762 return false;
763 }
764 return value != null;
765 }
766
767 /**
768 * Modify the value if necessary.
769 *
770 * @param value
771 * the input
772 * @return either value or a modified version of it.
773 */
774 public String filter(String value) {
775 // Look through the choice array, if present, for matches.
776 if (hasChoices()) {
777 // Do we have an exact match?
778 for (String pick : picks) {
779 if (pick.equals(value)) {
780 return value;
781 }
782 }
783
784 // Do we have a case insensitive match?
785 for (String pick : picks) {
786 if (pick.equalsIgnoreCase(value)) {
787 return pick;
788 }
789 }
790 }
791
792 return value;
793 }
794
795 /**
796 * RTF is allowed in a few config entries.
797 *
798 * @return true if RTF is allowed
799 */
800 public boolean allowsRTF() {
801 return false;
802 }
803
804 /**
805 * While most fields are single line or single value, some allow
806 * continuation. A continuation mark is a backslash at the end of a line. It
807 * is not to be followed by whitespace.
808 *
809 * @return true if continuation is allowed
810 */
811 public boolean allowsContinuation() {
812 return false;
813 }
814
815 /**
816 * Some keys can repeat. When this happens each is a single value pick from
817 * a list of choices.
818 *
819 * @return true if this ConfigEntryType can occur more than once
820 */
821 public boolean mayRepeat() {
822 return false;
823 }
824
825 /**
826 * Determines the level of detail stored in the histogram.
827 *
828 * @return true if the ConfigEntry should report histogram for repetitions
829 */
830 public boolean reportDetails() {
831 return true;
832 }
833
834 /**
835 * Some keys can repeat. When this happens each is a single value pick from
836 * a list of choices.
837 *
838 * @return true if this ConfigEntryType can occur more than once
839 */
840 protected boolean hasChoices() {
841 return picks != null;
842 }
843
844 /**
845 * Synthetic keys are those that are not in the Sword Book's conf, but are
846 * needed by the program. Typically, these are derived by the program from
847 * the other entries.
848 *
849 * @return true if this is synthetic
850 */
851 public boolean isSynthetic() {
852 return false;
853 }
854
855 /**
856 * Some ConfigEntryTypes have defaults.
857 *
858 * @return the default, if there is one, null otherwise
859 */
860 public Object getDefault() {
861 return defaultValue;
862 }
863
864 /**
865 * Convert the string value from the conf into the representation of this
866 * ConfigEntryType.
867 *
868 * @return the converted object
869 */
870 public Object convert(String input) {
871 return input;
872 }
873
874 /**
875 * Return the original representation of the object.
876 *
877 * @return the converted object
878 */
879 public String unconvert(Object internal) {
880 if (internal == null) {
881 return null;
882 }
883 return internal.toString();
884 }
885
886 /**
887 * Lookup method to convert from a String
888 */
889 public static ConfigEntryType fromString(String name) {
890 if (name != null) {
891 // special case
892 if (name.startsWith(ConfigEntryType.HISTORY.toString())) {
893 return ConfigEntryType.HISTORY;
894 }
895
896 for (ConfigEntryType o : ConfigEntryType.values()) {
897 if (name.equals(o.name)) {
898 return o;
899 }
900 }
901 }
902
903 // should not get here.
904 // But there are typos in the keys in the book conf files
905 // And this allows for the addition of new fields in
906 // advance of changing JSword
907 return null;
908 }
909
910 @Override
911 public String toString() {
912 return name;
913 }
914
915 /**
916 * The name of the ConfigEntryType
917 */
918 private final String name;
919
920 /**
921 * The default for the ConfigEntryType
922 */
923 private final Object defaultValue;
924
925 /**
926 * The array of choices.
927 */
928 private final String[] picks;
929
930 /**
931 * Constants for direction
932 */
933 public static final String DIRECTION_LTOR = "LtoR";
934 public static final String DIRECTION_RTOL = "RtoL";
935 public static final String DIRECTION_BIDI = "bidi";
936
937 }
938