1 package be
.nikiroo
.fanfix
.supported
;
4 import java
.io
.FileNotFoundException
;
5 import java
.io
.IOException
;
6 import java
.io
.InputStream
;
8 import java
.util
.ArrayList
;
10 import java
.util
.Scanner
;
12 import org
.jsoup
.nodes
.Document
;
14 import be
.nikiroo
.fanfix
.Instance
;
15 import be
.nikiroo
.fanfix
.bundles
.Config
;
16 import be
.nikiroo
.fanfix
.data
.MetaData
;
17 import be
.nikiroo
.utils
.Image
;
18 import be
.nikiroo
.utils
.streams
.MarkableFileInputStream
;
20 // not complete: no "description" tag
21 public class InfoReader
{
22 static protected BasicSupportHelper bsHelper
= new BasicSupportHelper();
23 // static protected BasicSupportImages bsImages = new BasicSupportImages();
24 // static protected BasicSupportPara bsPara = new BasicSupportPara(new
25 // BasicSupportHelper(), new BasicSupportImages());
27 public static MetaData
readMeta(File infoFile
, boolean withCover
)
29 if (infoFile
== null) {
30 throw new IOException("File is null");
33 if (infoFile
.exists()) {
34 InputStream in
= new MarkableFileInputStream(infoFile
);
36 MetaData meta
= createMeta(infoFile
.toURI().toURL(), in
,
39 // Some old .info files don't have those now required fields...
40 // So we check if we can find the info in another way (many
41 // formats have a copy of the original text file)
42 if (!hasIt(meta
.getTitle(), meta
.getAuthor(), meta
.getDate(),
45 // TODO: not nice, would be better to do it properly...
47 String base
= infoFile
.getPath();
48 if (base
.endsWith(".info")) {
49 base
= base
.substring(0,
50 base
.length() - ".info".length());
52 File textFile
= new File(base
);
53 if (!textFile
.exists()) {
54 textFile
= new File(base
+ ".txt");
56 if (!textFile
.exists()) {
57 textFile
= new File(base
+ ".text");
60 if (textFile
.exists()) {
61 final URL source
= textFile
.toURI().toURL();
62 final MetaData
[] superMetaA
= new MetaData
[1];
63 @SuppressWarnings("unused")
64 Text unused
= new Text() {
65 private boolean loaded
= loadDocument();
68 public SupportType
getType() {
69 return SupportType
.TEXT
;
72 protected boolean loadDocument()
75 superMetaA
[0] = getMeta();
80 protected Image
getCover(File sourceFile
) {
85 MetaData superMeta
= superMetaA
[0];
86 if (!hasIt(meta
.getTitle())) {
87 meta
.setTitle(superMeta
.getTitle());
89 if (!hasIt(meta
.getAuthor())) {
90 meta
.setAuthor(superMeta
.getAuthor());
92 if (!hasIt(meta
.getDate())) {
93 meta
.setDate(superMeta
.getDate());
95 if (!hasIt(meta
.getUrl())) {
96 meta
.setUrl(superMeta
.getUrl());
107 throw new FileNotFoundException(
108 "File given as argument does not exists: "
109 + infoFile
.getAbsolutePath());
113 * Check if we have non-empty values for all the given {@link String}s.
116 * the values to check
118 * @return TRUE if none of them was NULL or empty
120 static private boolean hasIt(String
... values
) {
121 for (String value
: values
) {
122 if (value
== null || value
.trim().isEmpty()) {
130 private static MetaData
createMeta(URL sourceInfoFile
, InputStream in
,
131 boolean withCover
) throws IOException
{
132 MetaData meta
= new MetaData();
134 meta
.setTitle(getInfoTag(in
, "TITLE"));
135 meta
.setAuthor(getInfoTag(in
, "AUTHOR"));
136 meta
.setDate(getInfoTag(in
, "DATE"));
137 meta
.setTags(getInfoTagList(in
, "TAGS", ","));
138 meta
.setSource(getInfoTag(in
, "SOURCE"));
139 meta
.setUrl(getInfoTag(in
, "URL"));
140 meta
.setPublisher(getInfoTag(in
, "PUBLISHER"));
141 meta
.setUuid(getInfoTag(in
, "UUID"));
142 meta
.setLuid(getInfoTag(in
, "LUID"));
143 meta
.setLang(getInfoTag(in
, "LANG"));
144 meta
.setSubject(getInfoTag(in
, "SUBJECT"));
145 meta
.setType(getInfoTag(in
, "TYPE"));
146 meta
.setImageDocument(getInfoTagBoolean(in
, "IMAGES_DOCUMENT", false));
148 String infoTag
= getInfoTag(in
, "COVER");
149 if (infoTag
!= null && !infoTag
.trim().isEmpty()) {
150 meta
.setCover(bsHelper
.getImage(null, sourceInfoFile
, infoTag
));
152 if (meta
.getCover() == null) {
153 // Second chance: try to check for a cover next to the info file
154 meta
.setCover(getCoverByName(sourceInfoFile
));
158 meta
.setWords(Long
.parseLong(getInfoTag(in
, "WORDCOUNT")));
159 } catch (NumberFormatException e
) {
162 meta
.setCreationDate(getInfoTag(in
, "CREATION_DATE"));
163 meta
.setFakeCover(Boolean
.parseBoolean(getInfoTag(in
, "FAKE_COVER")));
165 if (withCover
&& meta
.getCover() == null) {
166 meta
.setCover(bsHelper
.getDefaultCover(meta
.getSubject()));
173 * Return the cover image if it is next to the source file.
175 * @param sourceInfoFile
178 * @return the cover if present, NULL if not
180 public static Image
getCoverByName(URL sourceInfoFile
) {
183 File basefile
= new File(sourceInfoFile
.getFile());
185 String ext
= "." + Instance
.getInstance().getConfig()
186 .getString(Config
.FILE_FORMAT_IMAGE_FORMAT_COVER
).toLowerCase();
188 // Without removing ext
189 cover
= bsHelper
.getImage(null, sourceInfoFile
,
190 basefile
.getAbsolutePath() + ext
);
193 String name
= basefile
.getName();
194 int pos
= name
.lastIndexOf(".");
195 if (cover
== null && pos
> 0) {
196 name
= name
.substring(0, pos
);
197 basefile
= new File(basefile
.getParent(), name
);
199 cover
= bsHelper
.getImage(null, sourceInfoFile
,
200 basefile
.getAbsolutePath() + ext
);
206 private static boolean getInfoTagBoolean(InputStream in
, String key
,
207 boolean def
) throws IOException
{
208 Boolean value
= getInfoTagBoolean(in
, key
);
209 return value
== null ? def
: value
;
212 private static Boolean
getInfoTagBoolean(InputStream in
, String key
)
214 String value
= getInfoTag(in
, key
);
215 if (value
!= null && !value
.trim().isEmpty()) {
216 value
= value
.toLowerCase().trim();
217 return value
.equals("1") || value
.equals("on")
218 || value
.equals("true") || value
.equals("yes");
224 private static List
<String
> getInfoTagList(InputStream in
, String key
,
225 String separator
) throws IOException
{
226 List
<String
> list
= new ArrayList
<String
>();
227 String tt
= getInfoTag(in
, key
);
229 for (String tag
: tt
.split(separator
)) {
230 list
.add(tag
.trim());
238 * Return the value of the given tag in the <tt>.info</tt> file if present.
243 * @return the value or NULL
245 * @throws IOException
246 * in case of I/O error
248 private static String
getInfoTag(InputStream in
, String key
)
250 key
= "^" + key
+ "=";
254 String value
= getLine(in
, key
, 0);
255 if (value
!= null && !value
.isEmpty()) {
256 value
= value
.trim().substring(key
.length() - 1).trim();
257 if (value
.startsWith("'") && value
.endsWith("'")
258 || value
.startsWith("\"") && value
.endsWith("\"")) {
259 value
= value
.substring(1, value
.length() - 1).trim();
270 * Return the first line from the given input which correspond to the given
276 * a string that must be found inside the target line (also
277 * supports "^" at start to say "only if it starts with" the
279 * @param relativeLine
280 * the line to return based upon the target line position (-1 =
281 * the line before, 0 = the target line...)
285 static private String
getLine(InputStream in
, String needle
,
287 return getLine(in
, needle
, relativeLine
, true);
291 * Return a line from the given input which correspond to the given
297 * a string that must be found inside the target line (also
298 * supports "^" at start to say "only if it starts with" the
300 * @param relativeLine
301 * the line to return based upon the target line position (-1 =
302 * the line before, 0 = the target line...)
304 * takes the first result (as opposed to the last one, which will
305 * also always spend the input)
309 static private String
getLine(InputStream in
, String needle
,
310 int relativeLine
, boolean first
) {
313 List
<String
> lines
= new ArrayList
<String
>();
314 @SuppressWarnings("resource")
315 Scanner scan
= new Scanner(in
, "UTF-8");
317 scan
.useDelimiter("\\n");
318 while (scan
.hasNext()) {
319 lines
.add(scan
.next());
322 if (needle
.startsWith("^")) {
323 if (lines
.get(lines
.size() - 1)
324 .startsWith(needle
.substring(1))) {
325 index
= lines
.size() - 1;
329 if (lines
.get(lines
.size() - 1).contains(needle
)) {
330 index
= lines
.size() - 1;
335 if (index
>= 0 && index
+ relativeLine
< lines
.size()) {
336 rep
= lines
.get(index
+ relativeLine
);