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 be
.nikiroo
.fanfix
.Instance
;
13 import be
.nikiroo
.fanfix
.bundles
.Config
;
14 import be
.nikiroo
.fanfix
.data
.MetaData
;
15 import be
.nikiroo
.utils
.Image
;
16 import be
.nikiroo
.utils
.streams
.MarkableFileInputStream
;
18 // not complete: no "description" tag
19 public class InfoReader
{
20 static protected BasicSupportHelper bsHelper
= new BasicSupportHelper();
21 // static protected BasicSupportImages bsImages = new BasicSupportImages();
22 // static protected BasicSupportPara bsPara = new BasicSupportPara(new
23 // BasicSupportHelper(), new BasicSupportImages());
25 public static MetaData
readMeta(File infoFile
, boolean withCover
)
27 if (infoFile
== null) {
28 throw new IOException("File is null");
31 if (infoFile
.exists()) {
32 InputStream in
= new MarkableFileInputStream(infoFile
);
34 MetaData meta
= createMeta(infoFile
.toURI().toURL(), in
,
37 // Some old .info files were using UUID for URL...
38 if (!hasIt(meta
.getUrl()) && meta
.getUuid() != null
39 && (meta
.getUuid().startsWith("http://")
40 || meta
.getUuid().startsWith("https://"))) {
41 meta
.setUrl(meta
.getUuid());
44 // Some old .info files don't have those now required fields...
45 // So we check if we can find the info in another way (many
46 // formats have a copy of the original text file)
47 if (!hasIt(meta
.getTitle(), meta
.getAuthor(), meta
.getDate(),
50 // TODO: not nice, would be better to do it properly...
52 String base
= infoFile
.getPath();
53 if (base
.endsWith(".info")) {
54 base
= base
.substring(0,
55 base
.length() - ".info".length());
57 File textFile
= new File(base
);
58 if (!textFile
.exists()) {
59 textFile
= new File(base
+ ".txt");
61 if (!textFile
.exists()) {
62 textFile
= new File(base
+ ".text");
65 if (textFile
.exists()) {
66 final URL source
= textFile
.toURI().toURL();
67 final MetaData
[] superMetaA
= new MetaData
[1];
68 @SuppressWarnings("unused")
69 Text unused
= new Text() {
70 private boolean loaded
= loadDocument();
73 public SupportType
getType() {
74 return SupportType
.TEXT
;
77 protected boolean loadDocument()
80 superMetaA
[0] = getMeta();
85 protected Image
getCover(File sourceFile
) {
90 MetaData superMeta
= superMetaA
[0];
91 if (!hasIt(meta
.getTitle())) {
92 meta
.setTitle(superMeta
.getTitle());
94 if (!hasIt(meta
.getAuthor())) {
95 meta
.setAuthor(superMeta
.getAuthor());
97 if (!hasIt(meta
.getDate())) {
98 meta
.setDate(superMeta
.getDate());
100 if (!hasIt(meta
.getUrl())) {
101 meta
.setUrl(superMeta
.getUrl());
112 throw new FileNotFoundException(
113 "File given as argument does not exists: "
114 + infoFile
.getAbsolutePath());
118 * Check if we have non-empty values for all the given {@link String}s.
121 * the values to check
123 * @return TRUE if none of them was NULL or empty
125 static private boolean hasIt(String
... values
) {
126 for (String value
: values
) {
127 if (value
== null || value
.trim().isEmpty()) {
135 private static MetaData
createMeta(URL sourceInfoFile
, InputStream in
,
136 boolean withCover
) throws IOException
{
137 MetaData meta
= new MetaData();
139 meta
.setTitle(getInfoTag(in
, "TITLE"));
140 meta
.setAuthor(getInfoTag(in
, "AUTHOR"));
141 meta
.setDate(getInfoTag(in
, "DATE"));
142 meta
.setTags(getInfoTagList(in
, "TAGS", ","));
143 meta
.setSource(getInfoTag(in
, "SOURCE"));
144 meta
.setUrl(getInfoTag(in
, "URL"));
145 meta
.setPublisher(getInfoTag(in
, "PUBLISHER"));
146 meta
.setUuid(getInfoTag(in
, "UUID"));
147 meta
.setLuid(getInfoTag(in
, "LUID"));
148 meta
.setLang(getInfoTag(in
, "LANG"));
149 meta
.setSubject(getInfoTag(in
, "SUBJECT"));
150 meta
.setType(getInfoTag(in
, "TYPE"));
151 meta
.setImageDocument(getInfoTagBoolean(in
, "IMAGES_DOCUMENT", false));
153 String infoTag
= getInfoTag(in
, "COVER");
154 if (infoTag
!= null && !infoTag
.trim().isEmpty()) {
155 meta
.setCover(bsHelper
.getImage(null, sourceInfoFile
, infoTag
));
157 if (meta
.getCover() == null) {
158 // Second chance: try to check for a cover next to the info file
159 meta
.setCover(getCoverByName(sourceInfoFile
));
163 meta
.setWords(Long
.parseLong(getInfoTag(in
, "WORDCOUNT")));
164 } catch (NumberFormatException e
) {
167 meta
.setCreationDate(getInfoTag(in
, "CREATION_DATE"));
168 meta
.setFakeCover(Boolean
.parseBoolean(getInfoTag(in
, "FAKE_COVER")));
170 if (withCover
&& meta
.getCover() == null) {
171 meta
.setCover(bsHelper
.getDefaultCover(meta
.getSubject()));
178 * Return the cover image if it is next to the source file.
180 * @param sourceInfoFile
183 * @return the cover if present, NULL if not
185 public static Image
getCoverByName(URL sourceInfoFile
) {
188 File basefile
= new File(sourceInfoFile
.getFile());
190 String ext
= "." + Instance
.getInstance().getConfig()
191 .getString(Config
.FILE_FORMAT_IMAGE_FORMAT_COVER
).toLowerCase();
193 // Without removing ext
194 cover
= bsHelper
.getImage(null, sourceInfoFile
,
195 basefile
.getAbsolutePath() + ext
);
198 String name
= basefile
.getName();
199 int pos
= name
.lastIndexOf(".");
200 if (cover
== null && pos
> 0) {
201 name
= name
.substring(0, pos
);
202 basefile
= new File(basefile
.getParent(), name
);
204 cover
= bsHelper
.getImage(null, sourceInfoFile
,
205 basefile
.getAbsolutePath() + ext
);
211 private static boolean getInfoTagBoolean(InputStream in
, String key
,
212 boolean def
) throws IOException
{
213 Boolean value
= getInfoTagBoolean(in
, key
);
214 return value
== null ? def
: value
;
217 private static Boolean
getInfoTagBoolean(InputStream in
, String key
)
219 String value
= getInfoTag(in
, key
);
220 if (value
!= null && !value
.trim().isEmpty()) {
221 value
= value
.toLowerCase().trim();
222 return value
.equals("1") || value
.equals("on")
223 || value
.equals("true") || value
.equals("yes");
229 private static List
<String
> getInfoTagList(InputStream in
, String key
,
230 String separator
) throws IOException
{
231 List
<String
> list
= new ArrayList
<String
>();
232 String tt
= getInfoTag(in
, key
);
234 for (String tag
: tt
.split(separator
)) {
235 list
.add(tag
.trim());
243 * Return the value of the given tag in the <tt>.info</tt> file if present.
248 * @return the value or NULL
250 * @throws IOException
251 * in case of I/O error
253 private static String
getInfoTag(InputStream in
, String key
)
255 key
= "^" + key
+ "=";
259 String value
= getLine(in
, key
, 0);
260 if (value
!= null && !value
.isEmpty()) {
261 value
= value
.trim().substring(key
.length() - 1).trim();
262 if (value
.length() > 1 && //
263 (value
.startsWith("'") && value
.endsWith("'")
264 || value
.startsWith("\"")
265 && value
.endsWith("\""))) {
266 value
= value
.substring(1, value
.length() - 1).trim();
269 // Some old files ended up with TITLE="'xxxxx'"
270 if ("^TITLE=".equals(key
)) {
271 if (value
.startsWith("'") && value
.endsWith("'")
272 && value
.length() > 1) {
273 value
= value
.substring(1, value
.length() - 1).trim();
285 * Return the first line from the given input which correspond to the given
291 * a string that must be found inside the target line (also
292 * supports "^" at start to say "only if it starts with" the
294 * @param relativeLine
295 * the line to return based upon the target line position (-1 =
296 * the line before, 0 = the target line...)
300 static private String
getLine(InputStream in
, String needle
,
302 return getLine(in
, needle
, relativeLine
, true);
306 * Return a line from the given input which correspond to the given
312 * a string that must be found inside the target line (also
313 * supports "^" at start to say "only if it starts with" the
315 * @param relativeLine
316 * the line to return based upon the target line position (-1 =
317 * the line before, 0 = the target line...)
319 * takes the first result (as opposed to the last one, which will
320 * also always spend the input)
324 static private String
getLine(InputStream in
, String needle
,
325 int relativeLine
, boolean first
) {
328 List
<String
> lines
= new ArrayList
<String
>();
329 @SuppressWarnings("resource")
330 Scanner scan
= new Scanner(in
, "UTF-8");
332 scan
.useDelimiter("\\n");
333 while (scan
.hasNext()) {
334 lines
.add(scan
.next());
337 if (needle
.startsWith("^")) {
338 if (lines
.get(lines
.size() - 1)
339 .startsWith(needle
.substring(1))) {
340 index
= lines
.size() - 1;
344 if (lines
.get(lines
.size() - 1).contains(needle
)) {
345 index
= lines
.size() - 1;
350 if (index
>= 0 && index
+ relativeLine
< lines
.size()) {
351 rep
= lines
.get(index
+ relativeLine
);