1 package org.unicode.cldr.util;
2 
3 import java.io.BufferedReader;
4 import java.io.File;
5 import java.io.FileReader;
6 import java.io.IOException;
7 import java.io.PrintWriter;
8 import java.io.Writer;
9 import java.util.Random;
10 
11 import org.unicode.cldr.draft.FileUtilities;
12 
13 import com.ibm.icu.util.ICUUncheckedIOException;
14 
15 /**
16  * Simple utility to create a temporary file, write into it, then close it.
17  * If the file differs from the old file (except for date), then it is deleted.
18  * Otherwise it replaces the target file. Moved from UnicodeTools.
19  * @author markdavis
20  */
21 public class TempPrintWriter extends Writer {
22     final PrintWriter tempPrintWriter;
23     final String tempName;
24     final String filename;
25     boolean noReplace = false;
26 
27 
28     public static TempPrintWriter openUTF8Writer(String filename) {
29         return new TempPrintWriter(new File(filename));
30     }
31 
32     public static TempPrintWriter openUTF8Writer(String dir, String filename) {
33         return new TempPrintWriter(new File(dir, filename));
34     }
35 
36     public TempPrintWriter(String dir, String filename) {
37         this(new File(dir, filename));
38     }
39 
40     public TempPrintWriter(File file) {
41         super();
42         final String parentFile = file.getParent();
43         this.filename = file.toString();
44         Random rand = new Random();
45         try {
46             File tempFile;
47             do {
48                 tempFile = new File(parentFile, (0xFFFF & rand.nextInt()) + "-" + file.getName());
49             } while (tempFile.exists());
50             tempName = tempFile.toString();
51             tempPrintWriter = FileUtilities.openUTF8Writer(parentFile, tempFile.getName());
52         } catch (IOException e) {
53             throw new ICUUncheckedIOException(e);
54         }
55     }
56 
57     public void dontReplaceFile() {
58         noReplace = true;
59     }
60 
61     @Override
62     public void close() {
63         tempPrintWriter.close();
64         try {
65             if (noReplace) {
66                 new File(tempName).delete();
67             } else {
68                 replaceDifferentOrDelete(filename, tempName, false);
69             }
70         } catch (IOException e) {
71             throw new ICUUncheckedIOException(e);
72         }
73     }
74 
75     @Override
76     public void write(char[] cbuf, int off, int len) {
77         tempPrintWriter.write(cbuf, off, len);
78     }
79 
80     @Override
81     public void flush() {
82         tempPrintWriter.flush();
83     }
84 
85     public void println(Object line) {
86         tempPrintWriter.println(line);
87     }
88 
89     public void print(Object line) {
90         tempPrintWriter.print(line);
91     }
92 
93     public void println() {
94         tempPrintWriter.println();
95     }
96 
97     /**
98      * If contents(newFile) ≠ contents(oldFile), rename newFile to old. Otherwise delete newfile. Return true if replaced. *
99      */
100     private static boolean replaceDifferentOrDelete(String oldFile, String newFile, boolean skipCopyright) throws IOException {
101         final File oldFile2 = new File(oldFile);
102         if (oldFile2.exists()) {
103             final String lines[] = new String[2];
104             final boolean identical = filesAreIdentical(oldFile, newFile, skipCopyright, lines);
105             if (identical) {
106                 new File(newFile).delete();
107                 return false;
108             }
109             System.out.println("Found difference in : " + oldFile + ", " + newFile);
110             final int diff = compare(lines[0], lines[1]);
111             System.out.println(" File1: '" + lines[0].substring(0,diff) + "', '" + lines[0].substring(diff) + "'");
112             System.out.println(" File2: '" + lines[1].substring(0,diff) + "', '" + lines[1].substring(diff) + "'");
113         }
114         new File(newFile).renameTo(oldFile2);
115         return true;
116     }
117 
118     private static boolean filesAreIdentical(String file1, String file2, boolean skipCopyright, String[] lines) throws IOException {
119         if (file1 == null) {
120             lines[0] = null;
121             lines[1] = null;
122             return false;
123         }
124         final BufferedReader br1 = new BufferedReader(new FileReader(file1), 32*1024);
125         final BufferedReader br2 = new BufferedReader(new FileReader(file2), 32*1024);
126         String line1 = "";
127         String line2 = "";
128         try {
129             for (int lineCount = 0; ; ++lineCount) {
130                 line1 = getLineWithoutFluff(br1, lineCount == 0, skipCopyright);
131                 line2 = getLineWithoutFluff(br2, lineCount == 0, skipCopyright);
132                 if (line1 == null) {
133                     if (line2 == null) {
134                         return true;
135                     }
136                     break;
137                 }
138                 if (!line1.equals(line2)) {
139                     break;
140                 }
141             }
142             lines[0] = line1;
143             lines[1] = line2;
144             if (lines[0] == null) {
145                 lines[0] = "<end of file>";
146             }
147             if (lines[1] == null) {
148                 lines[1] = "<end of file>";
149             }
150             return false;
151         } finally {
152             br1.close();
153             br2.close();
154         }
155     }
156 
157     private static String getLineWithoutFluff(BufferedReader br1, boolean first, boolean skipCopyright) throws IOException {
158         while (true) {
159             String line1 = br1.readLine();
160             if (line1 == null) {
161                 return line1;
162             }
163             line1 = line1.trim();
164             if (line1.length() == 0) {
165                 continue;
166             }
167             if (line1.equals("#")) {
168                 continue;
169             }
170             if (line1.startsWith("# Generated")) {
171                 continue;
172             }
173             if (line1.startsWith("# Date")) {
174                 continue;
175             }
176             if (skipCopyright && line1.startsWith("# Copyright")) {
177                 continue;
178             }
179             if (line1.startsWith("<p><b>Date:</b>")) {
180                 continue;
181             }
182             if (line1.startsWith("<td valign=\"top\">20") && line1.endsWith("GMT</td>")) {
183                 continue;
184             }
185 
186             if (line1.equals("# ================================================")) {
187                 continue;
188             }
189             if (first && line1.startsWith("#")) {
190                 first = false;
191                 continue;
192             }
193             return line1;
194         }
195     }
196 
197     /**
198      * Returns -1 if strings are equal; otherwise the first position they are different at.
199      */
200     public static int compare(String a, String b) {
201         int len = a.length();
202         if (len > b.length()) {
203             len = b.length();
204         }
205         for (int i = 0; i < len; ++i) {
206             if (a.charAt(i) != b.charAt(i)) {
207                 return i;
208             }
209         }
210         if (a.length() != b.length()) {
211             return len;
212         }
213         return -1;
214     }
215 
216 }