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
18package com.google.doclava;
19
20import com.google.clearsilver.jsilver.data.Data;
21
22import java.io.*;
23import java.util.regex.Pattern;
24import java.util.regex.Matcher;
25
26
27public class DocFile {
28  public static final Pattern LINE = Pattern.compile("(.*)[\r]?\n", Pattern.MULTILINE);
29  public static final Pattern PROP = Pattern.compile("([^=]+)=(.*)");
30
31  public static String readFile(String filename) {
32    try {
33      File f = new File(filename);
34      int length = (int) f.length();
35      FileInputStream is = new FileInputStream(f);
36      InputStreamReader reader = new InputStreamReader(is, "UTF-8");
37      char[] buf = new char[length];
38      int index = 0;
39      int amt;
40      while (true) {
41        amt = reader.read(buf, index, length - index);
42
43        if (amt < 1) {
44          break;
45        }
46
47        index += amt;
48      }
49      return new String(buf, 0, index);
50    } catch (IOException e) {
51      return null;
52    }
53  }
54
55  public static String[] DEVSITE_VALID_LANGS = {"en", "es", "id", "in", "ja", "ko",
56      "ru", "vi", "zh-cn", "zh-tw", "pt-br"};
57
58  public static String getPathRoot(String filename) {
59    //look for a valid lang string in the file path. If found,
60    //snip the intl/lang from the path.
61    for (String t : DEVSITE_VALID_LANGS) {
62      int langStart = filename.indexOf("/" + t + "/");
63      if (langStart > -1) {
64        int langEnd = filename.indexOf("/", langStart + 1);
65        filename = filename.substring(langEnd + 1);
66        break;
67      }
68    }
69    return filename;
70  }
71
72  public static Data getPageMetadata (String docfile, Data hdf) {
73    //utility method for extracting metadata without generating file output.
74    if (hdf == null) {
75      hdf = Doclava.makeHDF();
76    }
77    String filedata = readFile(docfile);
78
79    // The document is properties up until the line "@jd:body".
80    // Any blank lines are ignored.
81    int start = -1;
82    int lineno = 1;
83    Matcher lines = LINE.matcher(filedata);
84    String line = null;
85    while (lines.find()) {
86      line = lines.group(1);
87      if (line.length() > 0) {
88        if (line.equals("@jd:body")) {
89          start = lines.end();
90          break;
91        }
92        Matcher prop = PROP.matcher(line);
93        if (prop.matches()) {
94          String key = prop.group(1);
95          String value = prop.group(2);
96          hdf.setValue(key, value);
97        } else {
98          break;
99        }
100      }
101      lineno++;
102    }
103    if (start < 0) {
104      System.err.println(docfile + ":" + lineno + ": error parsing docfile");
105      if (line != null) {
106        System.err.println(docfile + ":" + lineno + ":" + line);
107      }
108      System.exit(1);
109    }
110    return hdf;
111  }
112
113  public static void writePage(String docfile, String relative, String outfile, Data hdf) {
114
115    /*
116     * System.out.println("docfile='" + docfile + "' relative='" + relative + "'" + "' outfile='" +
117     * outfile + "'");
118     */
119    if (hdf == null) {
120      hdf = Doclava.makeHDF();
121    }
122    String filedata = readFile(docfile);
123
124    // The document is properties up until the line "@jd:body".
125    // Any blank lines are ignored.
126    int start = -1;
127    int lineno = 1;
128    Matcher lines = LINE.matcher(filedata);
129    String line = null;
130    while (lines.find()) {
131      line = lines.group(1);
132      if (line.length() > 0) {
133        if (line.equals("@jd:body")) {
134          start = lines.end();
135          break;
136        }
137        Matcher prop = PROP.matcher(line);
138        if (prop.matches()) {
139          String key = prop.group(1);
140          String value = prop.group(2);
141          hdf.setValue(key, value);
142        } else {
143          break;
144        }
145      }
146      lineno++;
147    }
148    if (start < 0) {
149      System.err.println(docfile + ":" + lineno + ": error parsing docfile");
150      if (line != null) {
151        System.err.println(docfile + ":" + lineno + ":" + line);
152      }
153      System.exit(1);
154    }
155
156    // if they asked to only be for a certain template, maybe skip it
157    String fromTemplate = hdf.getValue("template.which", "");
158    String fromPage = hdf.getValue("page.onlyfortemplate", "");
159    if (!"".equals(fromPage) && !fromTemplate.equals(fromPage)) {
160      return;
161    }
162
163    // and the actual text after that
164    String commentText = filedata.substring(start);
165
166    Comment comment = new Comment(commentText, null, new SourcePositionInfo(docfile, lineno, 1));
167    TagInfo[] tags = comment.tags();
168
169    TagInfo.makeHDF(hdf, "root.descr", tags);
170
171    hdf.setValue("commentText", commentText);
172
173    // write the page using the appropriate root template, based on the
174    // whichdoc value supplied by build
175    String fromWhichmodule = hdf.getValue("android.whichmodule", "");
176    if (fromWhichmodule.equals("online-pdk")) {
177      // leaving this in just for temporary compatibility with pdk doc
178      hdf.setValue("online-pdk", "true");
179      // add any conditional login for root template here (such as
180      // for custom left nav based on tab etc.
181      ClearPage.write(hdf, "docpage.cs", outfile);
182    } else {
183      String filename = outfile;
184      // Special case handling of samples files for devsite
185      // locale handling -- strip out the en/ root
186      if (Doclava.USE_DEVSITE_LOCALE_OUTPUT_PATHS) {
187        filename = filename.replaceFirst("^en/", "");
188      }
189      // Strip out the intl and lang id substr and get back just the
190      // guide, design, distribute, etc.
191      filename = getPathRoot(filename);
192
193      // map 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        } else if (filename.indexOf("topic/performance") == 0) {
240          hdf.setValue("perf", "true");
241          hdf.setValue("page.type", "develop");
242          hdf.setValue("page.category", "performance");
243        } else if (filename.indexOf("topic/arc") == 0) {
244          hdf.setValue("arc", "true");
245          hdf.setValue("page.type", "develop");
246          hdf.setValue("page.category", "arc");
247        }
248      } else if (filename.indexOf("distribute") == 0) {
249        hdf.setValue("distribute", "true");
250        hdf.setValue("page.type", "distribute");
251        hdf.setValue("page.category", "distribute");
252        if (filename.indexOf("distribute/googleplay") == 0) {
253          hdf.setValue("page.category", "googleplay");
254          hdf.setValue("page.type", "distribute");
255          hdf.setValue("googleplay", "true");
256        } else if (filename.indexOf("distribute/essentials") == 0) {
257          hdf.setValue("page.category", "essentials");
258          hdf.setValue("essentials", "true");
259        } else if (filename.indexOf("distribute/users") == 0) {
260          hdf.setValue("page.category", "users");
261          hdf.setValue("users", "true");
262        } else if (filename.indexOf("distribute/engage") == 0) {
263          hdf.setValue("page.category", "engage");
264          hdf.setValue("engage", "true");
265        } else if (filename.indexOf("distribute/monetize") == 0) {
266          hdf.setValue("page.category", "monetize");
267          hdf.setValue("monetize", "true");
268        } else if (filename.indexOf("distribute/analyze") == 0) {
269          hdf.setValue("page.category", "analyze");
270          hdf.setValue("analyze", "true");
271        } else if (filename.indexOf("distribute/tools") == 0) {
272          hdf.setValue("page.category", "essentials");
273          hdf.setValue("essentials", "true");
274        } else if (filename.indexOf("distribute/stories") == 0) {
275          hdf.setValue("page.category", "stories");
276          hdf.setValue("stories", "true");
277        }
278      } else if (filename.indexOf("about") == 0) {
279        hdf.setValue("about", "true");
280        hdf.setValue("page.type", "about");
281        hdf.setValue("page.category", "about");
282        if ((filename.indexOf("about/versions") == 0)) {
283          hdf.setValue("versions", "true");
284          hdf.setValue("page.category", "versions");
285        //todo remove this because there's no file at this location
286        } else if ((filename.indexOf("wear") == 0)) {
287          hdf.setValue("wear", "true");
288          hdf.setValue("page.category", "wear");
289        } else if ((filename.indexOf("tv") == 0)) {
290          hdf.setValue("tv", "true");
291          hdf.setValue("page.category", "tv");
292        } else if ((filename.indexOf("auto") == 0)) {
293          hdf.setValue("auto", "true");
294          hdf.setValue("page.category", "auto");
295        }
296      } else if (filename.indexOf("wear/preview") == 0) {
297        hdf.setValue("wearpreview", "true");
298        hdf.setValue("page.type", "about");
299        hdf.setValue("page.category", "wear preview");
300      } else if (filename.indexOf("devices") == 0) {
301        hdf.setValue("devices", "true");
302        hdf.setValue("page.type", "devices");
303      } else if (filename.indexOf("source") == 0) {
304        hdf.setValue("source", "true");
305      } else if (filename.indexOf("security") == 0) {
306        hdf.setValue("security", "true");
307      } else if (filename.indexOf("compatibility") == 0) {
308        hdf.setValue("compatibility", "true");
309      } else if (filename.indexOf("wear") == 0) {
310        hdf.setValue("wear", "true");
311        hdf.setValue("about", "true");
312        hdf.setValue("page.type", "about");
313        hdf.setValue("page.category", "wear");
314      } else if (filename.indexOf("work") == 0) {
315        hdf.setValue("work", "true");
316        hdf.setValue("page.type", "about");
317        hdf.setValue("page.category", "work");
318      } else if (filename.indexOf("preview") == 0) {
319        hdf.setValue("page.type", "develop");
320        hdf.setValue("page.category", "preview");
321        hdf.setValue("preview", "true");
322      } else if (filename.indexOf("auto") == 0) {
323        hdf.setValue("auto", "true");
324        hdf.setValue("about", "true");
325        hdf.setValue("page.type", "about");
326        hdf.setValue("page.category", "auto");
327      } else if (filename.indexOf("tv") == 0) {
328        hdf.setValue("tv", "true");
329        hdf.setValue("about", "true");
330        hdf.setValue("page.type", "about");
331        hdf.setValue("page.category", "tv");
332      } else {
333        hdf.setValue("about", "true");
334        hdf.setValue("page.type", "about");
335        hdf.setValue("page.category", "about");
336      }
337
338      //set metadata for this file in jd_lists_unified
339      PageMetadata.setPageMetadata(docfile, relative, outfile, hdf, Doclava.sTaglist);
340
341      //for devsite builds, remove 'intl/' from output paths for localized files
342      if (Doclava.USE_DEVSITE_LOCALE_OUTPUT_PATHS) {
343        outfile = outfile.replaceFirst("^intl/", "");
344      }
345
346      ClearPage.write(hdf, "docpage.cs", outfile);
347    }
348  } // writePage
349}
350