1 /*
2  * Copyright (C) 2010 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.doclava;
18 
19 import com.google.clearsilver.jsilver.data.Data;
20 
21 import java.io.*;
22 import java.util.regex.Pattern;
23 import java.util.regex.Matcher;
24 
25 
26 public class DocFile {
27   public static final Pattern LINE = Pattern.compile("(.*)[\r]?\n", Pattern.MULTILINE);
28   public static final Pattern PROP = Pattern.compile("([^=]+)=(.*)");
29 
readFile(String filename)30   public static String readFile(String filename) {
31     try {
32       File f = new File(filename);
33       int length = (int) f.length();
34       FileInputStream is = new FileInputStream(f);
35       InputStreamReader reader = new InputStreamReader(is, "UTF-8");
36       char[] buf = new char[length];
37       int index = 0;
38       int amt;
39       while (true) {
40         amt = reader.read(buf, index, length - index);
41 
42         if (amt < 1) {
43           break;
44         }
45 
46         index += amt;
47       }
48       return new String(buf, 0, index);
49     } catch (IOException e) {
50       return null;
51     }
52   }
53 
54   public static String[] DEVSITE_VALID_LANGS = {"en", "es", "in", "ja", "ko",
55       "ru", "vi", "zh-cn", "zh-tw", "pt-br"};
56 
getPathRoot(String filename)57   public static String getPathRoot(String filename) {
58     //look for a valid lang string in the file path. If found,
59     //snip the intl/lang from the path.
60     for (String t : DEVSITE_VALID_LANGS) {
61       int langStart = filename.indexOf("/" + t + "/");
62       if (langStart > -1) {
63         int langEnd = filename.indexOf("/", langStart + 1);
64         filename = filename.substring(langEnd + 1);
65         break;
66       }
67     }
68     return filename;
69   }
70 
getPageMetadata(String docfile, Data hdf)71   public static Data getPageMetadata (String docfile, Data hdf) {
72     //utility method for extracting metadata without generating file output.
73     if (hdf == null) {
74       hdf = Doclava.makeHDF();
75     }
76     String filedata = readFile(docfile);
77 
78     // The document is properties up until the line "@jd:body".
79     // Any blank lines are ignored.
80     int start = -1;
81     int lineno = 1;
82     Matcher lines = LINE.matcher(filedata);
83     String line = null;
84     while (lines.find()) {
85       line = lines.group(1);
86       if (line.length() > 0) {
87         if (line.equals("@jd:body")) {
88           start = lines.end();
89           break;
90         }
91         Matcher prop = PROP.matcher(line);
92         if (prop.matches()) {
93           String key = prop.group(1);
94           String value = prop.group(2);
95           hdf.setValue(key, value);
96         } else {
97           break;
98         }
99       }
100       lineno++;
101     }
102     if (start < 0) {
103       System.err.println(docfile + ":" + lineno + ": error parsing docfile");
104       if (line != null) {
105         System.err.println(docfile + ":" + lineno + ":" + line);
106       }
107       System.exit(1);
108     }
109     return hdf;
110   }
111 
writePage(String docfile, String relative, String outfile, Data hdf)112   public static void writePage(String docfile, String relative, String outfile, Data hdf) {
113 
114     /*
115      * System.out.println("docfile='" + docfile + "' relative='" + relative + "'" + "' outfile='" +
116      * outfile + "'");
117      */
118     if (hdf == null) {
119       hdf = Doclava.makeHDF();
120     }
121     String filedata = readFile(docfile);
122 
123     // The document is properties up until the line "@jd:body".
124     // Any blank lines are ignored.
125     int start = -1;
126     int lineno = 1;
127     Matcher lines = LINE.matcher(filedata);
128     String line = null;
129     while (lines.find()) {
130       line = lines.group(1);
131       if (line.length() > 0) {
132         if (line.equals("@jd:body")) {
133           start = lines.end();
134           break;
135         }
136         Matcher prop = PROP.matcher(line);
137         if (prop.matches()) {
138           String key = prop.group(1);
139           String value = prop.group(2);
140           hdf.setValue(key, value);
141         } else {
142           break;
143         }
144       }
145       lineno++;
146     }
147     if (start < 0) {
148       System.err.println(docfile + ":" + lineno + ": error parsing docfile");
149       if (line != null) {
150         System.err.println(docfile + ":" + lineno + ":" + line);
151       }
152       System.exit(1);
153     }
154 
155     // if they asked to only be for a certain template, maybe skip it
156     String fromTemplate = hdf.getValue("template.which", "");
157     String fromPage = hdf.getValue("page.onlyfortemplate", "");
158     if (!"".equals(fromPage) && !fromTemplate.equals(fromPage)) {
159       return;
160     }
161 
162     // and the actual text after that
163     String commentText = filedata.substring(start);
164 
165     Comment comment = new Comment(commentText, null, new SourcePositionInfo(docfile, lineno, 1));
166     TagInfo[] tags = comment.tags();
167 
168     TagInfo.makeHDF(hdf, "root.descr", tags);
169 
170     hdf.setValue("commentText", commentText);
171 
172     // write the page using the appropriate root template, based on the
173     // whichdoc value supplied by build
174     String fromWhichmodule = hdf.getValue("android.whichmodule", "");
175     if (fromWhichmodule.equals("online-pdk")) {
176       // leaving this in just for temporary compatibility with pdk doc
177       hdf.setValue("online-pdk", "true");
178       // add any conditional login for root template here (such as
179       // for custom left nav based on tab etc.
180       ClearPage.write(hdf, "docpage.cs", outfile);
181     } else {
182       String filename = outfile;
183       // Special case handling of samples files for devsite
184       // locale handling -- strip out the en/ root
185       if (Doclava.USE_DEVSITE_LOCALE_OUTPUT_PATHS) {
186         filename = filename.replaceFirst("^en/", "");
187       }
188       // Strip out the intl and lang id substr and get back just the
189       // guide, design, distribute, etc.
190       filename = getPathRoot(filename);
191 
192       if (Doclava.USE_UPDATED_TEMPLATES) {
193         //remap types to design, dev, distribute etc.
194         if (filename.indexOf("design") == 0) {
195           hdf.setValue("design", "true");
196           hdf.setValue("page.type", "design");
197           hdf.setValue("page.category", "design");
198         } else if (filename.indexOf("develop") == 0) {
199           hdf.setValue("develop", "true");
200           hdf.setValue("page.type", "develop");
201           hdf.setValue("page.category", "develop");
202         } else if (filename.indexOf("guide") == 0) {
203           hdf.setValue("guide", "true");
204           hdf.setValue("page.type", "develop");
205           if (filename.indexOf("guide/topics/manif") == 0) {
206             hdf.setValue("page.category", "app manifest");
207           } else {
208             hdf.setValue("page.category", "guide");
209           }
210         } else if (filename.indexOf("training") == 0) {
211           hdf.setValue("training", "true");
212           hdf.setValue("page.type", "develop");
213           hdf.setValue("page.category", "training");
214         } else if (filename.indexOf("more") == 0) {
215           hdf.setValue("more", "true");
216         } else if (filename.indexOf("google") == 0) {
217           hdf.setValue("google", "true");
218           hdf.setValue("page.type", "develop");
219           hdf.setValue("page.category", "google");
220         } else if (filename.indexOf("samples") == 0) {
221           hdf.setValue("samples", "true");
222           hdf.setValue("samplesDocPage", "true");
223           hdf.setValue("page.type", "develop");
224           hdf.setValue("page.category", "samples");
225           if (Doclava.samplesNavTree != null) {
226             hdf.setValue("samples_toc_tree", Doclava.samplesNavTree.getValue("samples_toc_tree", ""));
227           }
228         } else if (filename.indexOf("topic/") == 0) {
229           hdf.setValue("topic", "true");
230           hdf.setValue("page.type", "develop");
231           if (filename.indexOf("topic/libraries") == 0) {
232             hdf.setValue("page.category", "libraries");
233             hdf.setValue("page.type", "develop");
234             hdf.setValue("libraries", "true");
235           } else if (filename.indexOf("topic/instant-apps") == 0) {
236             hdf.setValue("instantapps", "true");
237             hdf.setValue("page.type", "develop");
238             hdf.setValue("page.category", "instant apps");
239           }
240         } else if (filename.indexOf("distribute") == 0) {
241           hdf.setValue("distribute", "true");
242           hdf.setValue("page.type", "distribute");
243           hdf.setValue("page.category", "distribute");
244           if (filename.indexOf("distribute/googleplay") == 0) {
245             hdf.setValue("page.category", "googleplay");
246             hdf.setValue("page.type", "distribute");
247             hdf.setValue("googleplay", "true");
248           } else if (filename.indexOf("distribute/essentials") == 0) {
249             hdf.setValue("page.category", "essentials");
250             hdf.setValue("essentials", "true");
251           } else if (filename.indexOf("distribute/users") == 0) {
252             hdf.setValue("page.category", "users");
253             hdf.setValue("users", "true");
254           } else if (filename.indexOf("distribute/engage") == 0) {
255             hdf.setValue("page.category", "engage");
256             hdf.setValue("engage", "true");
257           } else if (filename.indexOf("distribute/monetize") == 0) {
258             hdf.setValue("page.category", "monetize");
259             hdf.setValue("monetize", "true");
260           } else if (filename.indexOf("distribute/analyze") == 0) {
261             hdf.setValue("page.category", "analyze");
262             hdf.setValue("analyze", "true");
263           } else if (filename.indexOf("distribute/tools") == 0) {
264             hdf.setValue("page.category", "essentials");
265             hdf.setValue("essentials", "true");
266           } else if (filename.indexOf("distribute/stories") == 0) {
267             hdf.setValue("page.category", "stories");
268             hdf.setValue("stories", "true");
269           }
270         } else if (filename.indexOf("about") == 0) {
271           hdf.setValue("about", "true");
272           hdf.setValue("page.type", "about");
273           hdf.setValue("page.category", "about");
274           if ((filename.indexOf("about/versions") == 0)) {
275             hdf.setValue("versions", "true");
276             hdf.setValue("page.category", "versions");
277           //todo remove this because there's no file at this location
278           } else if ((filename.indexOf("wear") == 0)) {
279             hdf.setValue("wear", "true");
280             hdf.setValue("page.category", "wear");
281           } else if ((filename.indexOf("tv") == 0)) {
282             hdf.setValue("tv", "true");
283             hdf.setValue("page.category", "tv");
284           } else if ((filename.indexOf("auto") == 0)) {
285             hdf.setValue("auto", "true");
286             hdf.setValue("page.category", "auto");
287           }
288         } else if (filename.indexOf("wear/preview") == 0) {
289           hdf.setValue("wearpreview", "true");
290           hdf.setValue("page.type", "about");
291           hdf.setValue("page.category", "wear preview");
292         } else if ((filename.indexOf("tools") == 0) || (filename.indexOf("sdk") == 0)) {
293           hdf.setValue("tools", "true");
294           hdf.setValue("page.type", "develop");
295           hdf.setValue("page.category", "tools");
296           fromTemplate = hdf.getValue("page.template", "");
297         } else if (filename.indexOf("devices") == 0) {
298           hdf.setValue("devices", "true");
299           hdf.setValue("page.type", "devices");
300         } else if (filename.indexOf("source") == 0) {
301           hdf.setValue("source", "true");
302         } else if (filename.indexOf("accessories") == 0) {
303           hdf.setValue("accessories", "true");
304         } else if (filename.indexOf("compatibility") == 0) {
305           hdf.setValue("compatibility", "true");
306         } else if (filename.indexOf("wear") == 0) {
307           hdf.setValue("wear", "true");
308           hdf.setValue("about", "true");
309           hdf.setValue("page.type", "about");
310           hdf.setValue("page.category", "wear");
311         } else if (filename.indexOf("work") == 0) {
312           hdf.setValue("work", "true");
313           hdf.setValue("page.type", "about");
314           hdf.setValue("page.category", "work");
315         } else if (filename.indexOf("preview") == 0) {
316           hdf.setValue("page.type", "develop");
317           hdf.setValue("page.category", "preview");
318           hdf.setValue("preview", "true");
319         } else if (filename.indexOf("auto") == 0) {
320           hdf.setValue("auto", "true");
321           hdf.setValue("about", "true");
322           hdf.setValue("page.type", "about");
323           hdf.setValue("page.category", "auto");
324         } else if (filename.indexOf("tv") == 0) {
325           hdf.setValue("tv", "true");
326           hdf.setValue("about", "true");
327           hdf.setValue("page.type", "about");
328           hdf.setValue("page.category", "tv");
329         } else if (filename.indexOf("ndk") == 0) {
330           hdf.setValue("ndk", "true");
331           hdf.setValue("page.type", "ndk");
332           hdf.setValue("page.category", "ndk");
333           if (filename.indexOf("ndk/guides") == 0) {
334             hdf.setValue("guide", "true");
335             hdf.setValue("page.type", "ndk");
336             hdf.setValue("page.category", "guide");
337           } else if (filename.indexOf("ndk/reference") == 0) {
338             hdf.setValue("reference", "true");
339             hdf.setValue("page.type", "ndk");
340             hdf.setValue("page.category", "reference");
341           } else if (filename.indexOf("ndk/samples") == 0) {
342             hdf.setValue("samples", "true");
343             hdf.setValue("page.type", "ndk");
344             hdf.setValue("page.category", "samples");
345             hdf.setValue("samplesDocPage", "true");
346           } else if (filename.indexOf("ndk/downloads") == 0) {
347             hdf.setValue("downloads", "true");
348             hdf.setValue("page.type", "ndk");
349             hdf.setValue("page.category", "downloads");
350             fromTemplate = hdf.getValue("page.template", "");
351           }
352         }
353       } else {
354         //support the old mappings
355         if (filename.indexOf("design") == 0) {
356           hdf.setValue("design", "true");
357           hdf.setValue("page.type", "design");
358         } else if (filename.indexOf("develop") == 0) {
359           hdf.setValue("develop", "true");
360           hdf.setValue("page.type", "develop");
361         } else if (filename.indexOf("guide") == 0) {
362           hdf.setValue("guide", "true");
363           hdf.setValue("page.type", "guide");
364         } else if (filename.indexOf("training") == 0) {
365           hdf.setValue("training", "true");
366           hdf.setValue("page.type", "training");
367         } else if (filename.indexOf("more") == 0) {
368           hdf.setValue("more", "true");
369         } else if (filename.indexOf("google") == 0) {
370           hdf.setValue("google", "true");
371           hdf.setValue("page.type", "google");
372         } else if (filename.indexOf("samples") == 0) {
373           hdf.setValue("samples", "true");
374           hdf.setValue("samplesDocPage", "true");
375           hdf.setValue("page.type", "samples");
376           if (Doclava.samplesNavTree != null) {
377             hdf.setValue("samples_toc_tree", Doclava.samplesNavTree.getValue("samples_toc_tree", ""));
378           }
379         } else if (filename.indexOf("distribute") == 0) {
380           hdf.setValue("distribute", "true");
381           hdf.setValue("page.type", "distribute");
382           if (filename.indexOf("distribute/googleplay") == 0) {
383             hdf.setValue("googleplay", "true");
384           } else if (filename.indexOf("distribute/essentials") == 0) {
385             hdf.setValue("essentials", "true");
386           } else if (filename.indexOf("distribute/users") == 0) {
387             hdf.setValue("users", "true");
388           } else if (filename.indexOf("distribute/engage") == 0) {
389             hdf.setValue("engage", "true");
390           } else if (filename.indexOf("distribute/monetize") == 0) {
391             hdf.setValue("monetize", "true");
392           } else if (filename.indexOf("distribute/analyze") == 0) {
393             hdf.setValue("analyze", "true");
394           } else if (filename.indexOf("distribute/tools") == 0) {
395             hdf.setValue("essentials", "true");
396           } else if (filename.indexOf("distribute/stories") == 0) {
397             hdf.setValue("stories", "true");
398           }
399         } else if (filename.indexOf("about") == 0) {
400           hdf.setValue("about", "true");
401           hdf.setValue("page.type", "about");
402         } else if ((filename.indexOf("tools") == 0) || (filename.indexOf("sdk") == 0)) {
403           hdf.setValue("tools", "true");
404           hdf.setValue("page.type", "tools");
405           fromTemplate = hdf.getValue("page.template", "");
406         } else if (filename.indexOf("devices") == 0) {
407           hdf.setValue("devices", "true");
408           hdf.setValue("page.type", "devices");
409         } else if (filename.indexOf("source") == 0) {
410           hdf.setValue("source", "true");
411         } else if (filename.indexOf("accessories") == 0) {
412           hdf.setValue("accessories", "true");
413         } else if (filename.indexOf("compatibility") == 0) {
414           hdf.setValue("compatibility", "true");
415         } else if (filename.indexOf("topic/") == 0) {
416           hdf.setValue("topic", "true");
417           hdf.setValue("page.type", "develop");
418           if (filename.indexOf("topic/libraries") == 0) {
419             hdf.setValue("page.category", "libraries");
420             hdf.setValue("page.type", "develop");
421             hdf.setValue("libraries", "true");
422           } else if (filename.indexOf("topic/instant-apps") == 0) {
423             hdf.setValue("instantapps", "true");
424             hdf.setValue("page.type", "develop");
425             hdf.setValue("page.category", "instant apps");
426           }
427         } else if (filename.indexOf("wear/preview") == 0) {
428           hdf.setValue("wearpreview", "true");
429           hdf.setValue("page.type", "about");
430           hdf.setValue("page.category", "wear preview");
431         } else if (filename.indexOf("wear") == 0) {
432           hdf.setValue("wear", "true");
433         } else if (filename.indexOf("work") == 0) {
434           hdf.setValue("work", "true");
435           hdf.setValue("page.type", "about");
436           hdf.setValue("page.category", "work");
437         } else if (filename.indexOf("preview") == 0) {
438           hdf.setValue("page.type", "preview");
439           hdf.setValue("page.category", "preview");
440           hdf.setValue("preview", "true");
441         } else if (filename.indexOf("auto") == 0) {
442           hdf.setValue("auto", "true");
443         } else if (filename.indexOf("tv") == 0) {
444           hdf.setValue("tv", "true");
445         } else if (filename.indexOf("ndk") == 0) {
446           hdf.setValue("ndk", "true");
447           hdf.setValue("page.type", "ndk");
448           if (filename.indexOf("ndk/guides") == 0) {
449             hdf.setValue("guide", "true");
450           } else if (filename.indexOf("ndk/reference") == 0) {
451             hdf.setValue("reference", "true");
452           } else if (filename.indexOf("ndk/samples") == 0) {
453             hdf.setValue("samples", "true");
454             hdf.setValue("samplesDocPage", "true");
455           } else if (filename.indexOf("ndk/downloads") == 0) {
456             hdf.setValue("downloads", "true");
457             fromTemplate = hdf.getValue("page.template", "");
458           }
459         }
460       }
461       //set metadata for this file in jd_lists_unified
462       PageMetadata.setPageMetadata(docfile, relative, outfile, hdf, Doclava.sTaglist);
463 
464       //for devsite builds, remove 'intl/' from output paths for localized files
465       if (Doclava.USE_DEVSITE_LOCALE_OUTPUT_PATHS) {
466         outfile = outfile.replaceFirst("^intl/", "");
467       }
468 
469       if (fromTemplate.equals("sdk")) {
470         ClearPage.write(hdf, "sdkpage.cs", outfile);
471       } else {
472         ClearPage.write(hdf, "docpage.cs", outfile);
473       }
474     }
475   } // writePage
476 }
477