/* * Copyright 2007 Zhang, Zheng <oldbig@gmail.com> * * This file is part of ZOJ. * * ZOJ is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either revision 3 of the License, or (at your option) any later revision. * * ZOJ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with ZOJ. if not, see * <http://www.gnu.org/licenses/>. */ package cn.edu.zju.acm.onlinejudge.util; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import org.apache.commons.io.CopyUtils; import org.apache.struts.action.ActionMessage; import org.apache.struts.action.ActionMessages; import cn.edu.zju.acm.onlinejudge.bean.Limit; import cn.edu.zju.acm.onlinejudge.bean.Problem; public class ProblemManager { public static final String PROBLEM_CSV_FILE = "problems.csv"; public static final String INPUT_FILE = "input"; public static final String OUTPUT_FILE = "output"; public static final String PROBLEM_TEXT_FILE = "text"; public static final String CHECKER_FILE = "checker"; public static final String CHECKER_SOURCE_FILE = "checker"; public static final String JUDGE_SOLUTION_FILE = "solution"; public static final String IMAGES_DIR = "images"; public static ProblemPackage importProblem(InputStream in, ActionMessages messages) { Map<String, byte[]> files = new HashMap<String, byte[]>(); ZipInputStream zis = null; try { zis = new ZipInputStream(new BufferedInputStream(in)); // zis = new ZipInputStream(new BufferedInputStream(new FileInputStream("d:/100.zip"))); ZipEntry entry = zis.getNextEntry(); while (entry != null) { if (!entry.isDirectory()) { // TODO the file may be too big. > 100M /* * byte data[] = new byte[(int) entry.getSize()]; int l = 0; while (l < data.length) { int ll = * zis.read(data, l, data.length - l); if (ll < 0) { break; } l += ll; } */ ByteArrayOutputStream buf = new ByteArrayOutputStream(); CopyUtils.copy(zis, buf); files.put(entry.getName(), buf.toByteArray()); } entry = zis.getNextEntry(); } } catch (IOException ioe) { messages.add("error", new ActionMessage("onlinejudge.importProblem.invalidzip")); return null; } finally { try { if (zis != null) { zis.close(); } } catch (IOException e) { // ignore } } /* * files.clear(); files.put("problems.csv", "3,a\n2,b,true,1,2,3,4,a,b,c\n1,c".getBytes()); * files.put("1\\checker", "checker".getBytes()); files.put("1\\input", "input".getBytes()); * files.put("1\\output", "output".getBytes()); files.put("3\\checker", "checker3".getBytes()); * files.put("3\\input", "input3".getBytes()); files.put("3\\output", "output3".getBytes()); * files.put("images\\1.jpg", "1".getBytes()); files.put("images\\2\\2.jpg", "2".getBytes()); */ if (!files.containsKey(ProblemManager.PROBLEM_CSV_FILE)) { messages.add("error", new ActionMessage("onlinejudge.importProblem.missingproblemscsv")); return null; } ProblemPackage problemPackage = ProblemManager.parse(files, messages); if (messages.size() > 0) { return null; } return problemPackage; } private static ProblemPackage parse(Map<String, byte[]> files, ActionMessages messages) { Map<String, ProblemEntry> entryMap = new TreeMap<String, ProblemEntry>(); byte[] csv = files.get(ProblemManager.PROBLEM_CSV_FILE); BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(csv))); int index = 0; try { for (;;) { index++; String messageKey = "Line " + index; String line = reader.readLine(); if (line == null) { break; } if (line.trim().length() == 0) { continue; } // CSV format code,title,checker,tl,ml,ol,sl,author,source,contest String[] values = ProblemManager.split(line); Problem problem = new Problem(); if (values.length < 2) { messages.add(messageKey, new ActionMessage("onlinejudge.importProblem.invalidline")); continue; } if (values[0].length() > 8 || values[0].length() == 0) { messages.add(messageKey, new ActionMessage("onlinejudge.importProblem.invalidcode")); } problem.setCode(values[0]); if (values[1].length() > 128 || values[1].length() == 0) { messages.add(messageKey, new ActionMessage("onlinejudge.importProblem.invalidtitle")); } problem.setTitle(values[1]); if (values.length > 2 && Boolean.valueOf(values[2]).booleanValue()) { problem.setChecker(true); } Limit limit = new Limit(); Integer tl = ProblemManager.retrieveInt(values, 3); if (tl != null) { if (tl.intValue() < 0) { messages.add(messageKey, new ActionMessage("onlinejudge.importProblem.invalidtl")); } else { limit.setTimeLimit(tl.intValue()); } } Integer ml = ProblemManager.retrieveInt(values, 4); if (ml != null) { if (ml.intValue() < 0) { messages.add(messageKey, new ActionMessage("onlinejudge.importProblem.invalidml")); } else { limit.setMemoryLimit(ml.intValue()); } } Integer ol = ProblemManager.retrieveInt(values, 5); if (ol != null) { if (ol.intValue() < 0) { messages.add(messageKey, new ActionMessage("onlinejudge.importProblem.invalidol")); } else { limit.setOutputLimit(ol.intValue()); } } Integer sl = ProblemManager.retrieveInt(values, 6); if (sl != null) { if (sl.intValue() < 0) { messages.add(messageKey, new ActionMessage("onlinejudge.importProblem.invalidsl")); } else { limit.setSubmissionLimit(sl.intValue()); } } if (tl != null || ml != null || ol != null || sl != null) { if (tl != null && ml != null && ol != null && sl != null) { problem.setLimit(limit); } else { messages.add(messageKey, new ActionMessage("onlinejudge.importProblem.missinglimit")); } } if (values.length > 7 && values[7].length() > 0) { if (values[7].length() > 32) { messages.add(messageKey, new ActionMessage("onlinejudge.importProblem.invalidauthor")); } else { problem.setAuthor(values[7]); } } if (values.length > 8 && values[8].length() > 0) { if (values[8].length() > 128) { messages.add(messageKey, new ActionMessage("onlinejudge.importProblem.invalidsource")); } else { problem.setSource(values[8]); } } if (values.length > 9 && values[9].length() > 0) { if (values[9].length() > 128) { messages.add(messageKey, new ActionMessage("onlinejudge.importProblem.invalidcontest")); } else { problem.setContest(values[9]); } } ProblemEntry entry = new ProblemEntry(); entry.setProblem(problem); if (entryMap.containsKey(problem.getCode())) { messages.add(messageKey, new ActionMessage("onlinejudge.importProblem.reduplicatecode")); } entryMap.put(problem.getCode(), entry); } } catch (IOException e) { messages.add("error", new ActionMessage("onlinejudge.importProblem.invalidproblemscsv")); } if (messages.size() > 0) { return null; } if (entryMap.size() == 0) { messages.add("error", new ActionMessage("onlinejudge.importProblem.emptyproblemscsv")); } ProblemPackage problemPackage = new ProblemPackage(); problemPackage.setProblemEntries(new ProblemEntry[entryMap.size()]); // retrieve checker, input, output index = 0; for (String string : entryMap.keySet()) { ProblemEntry entry = entryMap.get(string); String code = entry.getProblem().getCode(); byte[] checker = files.get(code + "/" + ProblemManager.CHECKER_FILE); byte[] input = files.get(code + "/" + ProblemManager.INPUT_FILE); byte[] output = files.get(code + "/" + ProblemManager.OUTPUT_FILE); byte[] text = files.get(code + "/" + ProblemManager.PROBLEM_TEXT_FILE); byte[] solution = null; byte[] checkerSource = null; String checkerSourceType = ProblemManager.getFileType(code, ProblemManager.CHECKER_SOURCE_FILE, files); if (checkerSourceType != null) { checkerSource = files.get(code + "/" + ProblemManager.CHECKER_SOURCE_FILE + "." + checkerSourceType); } String solutionType = ProblemManager.getFileType(code, ProblemManager.JUDGE_SOLUTION_FILE, files); if (solutionType != null) { solution = files.get(code + "/" + ProblemManager.JUDGE_SOLUTION_FILE + "." + solutionType); } if ("cpp".equals(checkerSourceType)) { checkerSourceType = "cc"; } if ("cpp".equals(solutionType)) { solutionType = "cc"; } entry.setChecker(checker); entry.setInput(input); entry.setOutput(output); entry.setText(text); entry.setSolution(solution); entry.setSolutionType(solutionType); entry.setCheckerSource(checkerSource); entry.setCheckerSourceType(checkerSourceType); problemPackage.getProblemEntries()[index] = entry; index++; } // retrieve images Map<String, byte[]> imageMap = new HashMap<String, byte[]>(); Map<String, String> usedImages = new HashMap<String, String>(); Map<String, String> duplicateImages = new HashMap<String, String>(); for (String string : files.keySet()) { String path = string; if (ProblemManager.isImageFile(path)) { String imageName = new File(path).getName(); if (imageMap.containsKey(imageName)) { String s = duplicateImages.get(imageName); s = (s == null ? "" : s) + " " + path; duplicateImages.put(imageName, s); } if (ProblemManager.isUsed(imageName)) { String s = usedImages.get(imageName); s = (s == null ? "" : s) + " " + path; usedImages.put(imageName, s); } imageMap.put(imageName, files.get(path)); } } problemPackage.setImages(imageMap); problemPackage.setUsedImages(usedImages); problemPackage.setDuplicateImages(duplicateImages); return problemPackage; } private static boolean isImageFile(String path) { String name = path.toLowerCase(); return name.endsWith(".bmp") || path.endsWith(".gif") || path.endsWith(".tif") || path.endsWith(".png") || path.endsWith(".jpg") || path.endsWith(".jpeg"); } private static boolean isUsed(String image) { File f = new File(ConfigManager.getImagePath(), image); return f.exists(); } private static String getFileType(String code, String name, Map<String, byte[]> files) { if (files.containsKey(code + "/" + name + ".cc")) { return "cc"; } else if (files.containsKey(code + "/" + name + ".cpp")) { return "cpp"; } else if (files.containsKey(code + "/" + name + ".c")) { return "c"; } else if (files.containsKey(code + "/" + name + ".pas")) { return "pas"; } else if (files.containsKey(code + "/" + name + ".fpc")) { return "fpc"; } else if (files.containsKey(code + "/" + name + ".java")) { return "java"; } else { return null; } } private static Integer retrieveInt(String[] values, int index) { if (values.length > index && values[index].length() > 0) { try { return Integer.valueOf(values[index]); } catch (Exception e) { return new Integer(-1); } } return null; } private static String[] split(String line) { int quote = 0; StringBuffer sb = new StringBuffer(); List<String> values = new ArrayList<String>(); for (int i = 0; i < line.length(); ++i) { char ch = line.charAt(i); if (ch == '"') { if (quote == 0 && sb.length() == 0) { quote = 1; continue; } if (quote == 0) { sb.append(ch); continue; } if (quote == 2) { sb.append(ch); quote--; } else { quote++; } } else if (quote == 1) { sb.append(ch); } else if (ch == ',') { values.add(sb.toString().trim()); sb = new StringBuffer(); quote = 0; } else { sb.append(ch); } } values.add(sb.toString().trim()); return values.toArray(new String[0]); } }