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
17package com.google.doclava;
18
19import com.google.clearsilver.jsilver.JSilver;
20import com.google.clearsilver.jsilver.data.Data;
21
22import java.io.BufferedWriter;
23import java.io.File;
24import java.io.FileInputStream;
25import java.io.FileOutputStream;
26import java.io.IOException;
27import java.io.OutputStreamWriter;
28import java.io.Writer;
29import java.util.ArrayList;
30import java.util.List;
31import java.util.Arrays;
32
33public class ClearPage {
34  /*
35   * public ClearPage() { String templ = "templates/index.cs"; String filename = "docs/index.html";
36   *
37   * data.setValue("A.B.C", "1"); data.setValue("A.B.D", "2"); }
38   */
39
40  private static ArrayList<String> mTemplateDirs = new ArrayList<String>();
41  private static boolean mTemplateDirSet = false;
42
43  private static ArrayList<String> mBundledTemplateDirs = new ArrayList<String>();
44
45  public static String outputDir = "docs";
46  public static List<String> htmlDirs = new ArrayList<String>();
47  public static String toroot = null;
48
49  public static void addTemplateDir(String dir) {
50    mTemplateDirSet = true;
51    mTemplateDirs.add(dir);
52  }
53
54  public static List<String> getTemplateDirs() {
55    return mTemplateDirs;
56  }
57
58  public static void addBundledTemplateDir(String dir) {
59    mTemplateDirSet = true;
60    mBundledTemplateDirs.add(dir);
61  }
62
63  public static List<String> getBundledTemplateDirs() {
64    return mBundledTemplateDirs;
65  }
66
67  private static int countSlashes(String s) {
68    final int N = s.length();
69    int slashcount = 0;
70    for (int i = 0; i < N; i++) {
71      if (s.charAt(i) == '/') {
72        slashcount++;
73      }
74    }
75    return slashcount;
76  }
77
78  public static void write(Data data, String templ, String filename, JSilver cs) {
79    write(data, templ, filename, false, cs);
80  }
81
82  public static void write(Data data, String templ, String filename) {
83    write(data, templ, filename, false, Doclava.jSilver);
84  }
85
86  public static void write(Data data, String templ, String filename, boolean fullPath) {
87    write(data, templ, filename, false, Doclava.jSilver);
88  }
89
90  public static void write(Data data, String templ, String filename, boolean fullPath, JSilver cs) {
91    if (!htmlDirs.isEmpty()) {
92      data.setValue("hasindex", "true");
93    }
94
95    String toroot;
96    if (ClearPage.toroot != null) {
97      toroot = ClearPage.toroot;
98    } else {
99      int slashcount = countSlashes(filename);
100      if (slashcount > 0) {
101        toroot = "";
102        for (int i = 0; i < slashcount; i++) {
103          toroot += "../";
104        }
105      } else {
106        toroot = "./";
107      }
108    }
109    data.setValue("toroot", toroot);
110
111    data.setValue("filename", filename);
112
113    if (!fullPath) {
114      filename = outputDir + "/" + filename;
115    }
116
117    int i = 0;
118    if (!htmlDirs.isEmpty()) {
119        for (String dir : htmlDirs) {
120          data.setValue("hdf.loadpaths." + i, dir);
121          i++;
122        }
123    }
124    if (mTemplateDirSet) {
125      for (String dir : mTemplateDirs) {
126        data.setValue("hdf.loadpaths." + i, dir);
127        i++;
128      }
129    } else {
130      data.setValue("hdf.loadpaths." + i, "templates");
131    }
132
133    File file = new File(outputFilename(filename));
134
135    ensureDirectory(file);
136    Writer stream = null;
137    try {
138      stream = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"));
139      String rendered = cs.render(templ, data);
140      stream.write(rendered, 0, rendered.length());
141    } catch (IOException e) {
142      System.out.println("error: " + e.getMessage() + "; when writing file: " + filename);
143    } finally {
144      if (stream != null) {
145        try {
146          stream.close();
147        } catch (IOException e) {}
148      }
149    }
150  }
151
152  // recursively create the directories to the output
153  public static void ensureDirectory(File f) {
154    File parent = f.getParentFile();
155    if (parent != null) {
156      parent.mkdirs();
157    }
158  }
159
160  public static void copyFile(boolean allowExcepted, File from, String toPath) {
161    File to = new File(outputDir + "/" + toPath);
162    FileInputStream in;
163    FileOutputStream out;
164    try {
165      if (!from.exists()) {
166        throw new IOException();
167      }
168      in = new FileInputStream(from);
169    } catch (IOException e) {
170      System.err.println(from.getAbsolutePath() + ": Error opening file");
171      return;
172    }
173    ensureDirectory(to);
174    try {
175      out = new FileOutputStream(to);
176    } catch (IOException e) {
177      System.err.println(from.getAbsolutePath() + ": Error opening file");
178      return;
179    }
180    if (!isValidContentType(allowExcepted, toPath, DROIDDOC_VALID_CONTENT_TYPES)) {
181        Errors.error(Errors.INVALID_CONTENT_TYPE, null, "Failed to process " + from
182                + ": Invalid file type. Please move the file to frameworks/base/docs/image_sources/... or docs/downloads/...");
183        return;
184    }
185
186    long sizel = from.length();
187    final int maxsize = 64 * 1024;
188    int size = sizel > maxsize ? maxsize : (int) sizel;
189    byte[] buf = new byte[size];
190    while (true) {
191      try {
192        size = in.read(buf);
193      } catch (IOException e) {
194        System.err.println(from.getAbsolutePath() + ": error reading file");
195        break;
196      }
197      if (size > 0) {
198        try {
199          out.write(buf, 0, size);
200        } catch (IOException e) {
201          System.err.println(from.getAbsolutePath() + ": error writing file");
202        }
203      } else {
204        break;
205      }
206    }
207    try {
208      in.close();
209    } catch (IOException e) {}
210    try {
211      out.close();
212    } catch (IOException e) {}
213  }
214
215  /** Takes a string that ends w/ .html and changes the .html to htmlExtension */
216  public static String outputFilename(String htmlFile) {
217    if (!Doclava.htmlExtension.equals(".html") && htmlFile.endsWith(".html")) {
218      return htmlFile.substring(0, htmlFile.length() - 5) + Doclava.htmlExtension;
219    } else {
220      return htmlFile;
221    }
222  }
223
224  public static ArrayList<String> DROIDDOC_VALID_CONTENT_TYPES = new ArrayList<String>(Arrays.asList(".txt", ".css",
225    ".js", ".html", ".ico", ".png", ".jpg", ".gif", ".svg", ".webm", ".ogv","mp4", ".java", ".xml", ".aidl", ".rs",".zip", ".yaml"));
226  /* Setting excepted types to allow everything. Leaving it this way in in case we want to explicitly
227   * specify file types later. This adds unneeded checking though since it lets everything through
228   */
229  public static ArrayList<String> DROIDDOC_EXCEPTED_CONTENT_TYPES = new ArrayList<String>(Arrays.asList(""));
230
231  public static boolean isValidContentType(boolean allowExcepted, String s, ArrayList<String> list) {
232    if(allowExcepted){
233      list.addAll(DROIDDOC_EXCEPTED_CONTENT_TYPES);
234    }
235    for (String t : list) {
236      if (s.endsWith(t)) {
237        return true;
238      }
239    }
240    return false;
241  }
242}
243