001/*
002 * (C) Copyright 2006-2014 Nuxeo SA <http://nuxeo.com> and others
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     Jean-Marc Orliaguet, Chalmers
011 *
012 */
013
014package org.nuxeo.theme.presets;
015
016import java.io.DataInputStream;
017import java.io.FileNotFoundException;
018import java.io.IOException;
019import java.io.InputStream;
020import java.io.StringReader;
021import java.io.StringWriter;
022import java.net.URL;
023import java.util.HashMap;
024import java.util.Map;
025
026import org.apache.commons.csv.CSVFormat;
027import org.apache.commons.csv.CSVParser;
028import org.apache.commons.csv.CSVPrinter;
029import org.apache.commons.csv.CSVRecord;
030import org.apache.commons.logging.Log;
031import org.apache.commons.logging.LogFactory;
032
033public class PaletteParser {
034
035    private static final Log log = LogFactory.getLog(PaletteParser.class);
036
037    public static Map<String, String> parse(URL url) {
038        Map<String, String> entries = new HashMap<>();
039        InputStream in = null;
040        try {
041            in = url.openStream();
042            entries = parse(in, url.getFile());
043        } catch (FileNotFoundException e) {
044            log.error("File not found: " + url);
045        } catch (IOException e) {
046            log.error("Could not open file: " + url);
047        } catch (PaletteIdentifyException e) {
048            log.error("Could not identify palette type: " + url);
049        } catch (PaletteParseException e) {
050            log.error("Could not parse palette: " + url);
051        } finally {
052            if (in != null) {
053                try {
054                    in.close();
055                } catch (IOException e) {
056                    log.error(e, e);
057                } finally {
058                    in = null;
059                }
060            }
061        }
062        return entries;
063    }
064
065    public static boolean checkSanity(byte[] bytes) {
066        return false;
067    }
068
069    public static String rgbToHex(int r, int g, int b) {
070        final StringBuffer hexcolor = new StringBuffer("#");
071        final int[] rgb = { r, g, b };
072        for (final int val : rgb) {
073            if (val < 16) {
074                hexcolor.append("0");
075            }
076            hexcolor.append(Integer.toHexString(val));
077        }
078        // optimize #aabbcc to #abc
079        if (hexcolor.charAt(1) == hexcolor.charAt(2) && hexcolor.charAt(3) == hexcolor.charAt(4)
080                && hexcolor.charAt(5) == hexcolor.charAt(6)) {
081            return String.format("#%s%s%s", hexcolor.charAt(1), hexcolor.charAt(4), hexcolor.charAt(6));
082        }
083        return hexcolor.toString();
084    }
085
086    public static PaletteFamily identifyPaletteType(byte[] bytes, String filename) throws PaletteIdentifyException {
087        if (filename.endsWith(".aco") && PhotoshopPaletteParser.checkSanity(bytes)) {
088            return PaletteFamily.PHOTOSHOP;
089        } else if (filename.endsWith(".gpl") && GimpPaletteParser.checkSanity(bytes)) {
090            return PaletteFamily.GIMP;
091        } else if (filename.endsWith(".properties") && PropertiesPaletteParser.checkSanity(bytes)) {
092            return PaletteFamily.PROPERTIES;
093        }
094        throw new PaletteIdentifyException();
095    }
096
097    public static Map<String, String> parse(InputStream in, String filename) throws IOException,
098            PaletteIdentifyException, PaletteParseException {
099        DataInputStream dis = new DataInputStream(in);
100        byte[] bytes = new byte[dis.available()];
101        dis.read(bytes);
102        return parse(bytes, filename);
103    }
104
105    public static Map<String, String> parse(byte[] bytes, String filename) throws PaletteIdentifyException,
106            PaletteParseException {
107        PaletteFamily paletteFamily = identifyPaletteType(bytes, filename);
108        if (paletteFamily == PaletteFamily.PHOTOSHOP) {
109            return PhotoshopPaletteParser.parse(bytes);
110        } else if (paletteFamily == PaletteFamily.GIMP) {
111            return GimpPaletteParser.parse(bytes);
112        } else if (paletteFamily == PaletteFamily.PROPERTIES) {
113            return PropertiesPaletteParser.parse(bytes);
114        }
115        if (paletteFamily == null) {
116            throw new PaletteParseException();
117        }
118        return null;
119    }
120
121    public static String renderPaletteAsCsv(byte[] bytes, String fileName) {
122        StringWriter sw = new StringWriter();
123        try (CSVPrinter writer = new CSVPrinter(sw, CSVFormat.DEFAULT.withDelimiter('\t'))) {
124            for (Map.Entry<String, String> entry : parse(bytes, fileName).entrySet()) {
125                writer.printRecord(entry.getKey(), entry.getValue());
126            }
127        } catch (PaletteIdentifyException e) {
128            log.warn("Could not identify palette type: " + fileName);
129        } catch (PaletteParseException e) {
130            log.warn("Could not parse palette: " + fileName);
131        } catch (IOException e) {
132            log.error(e.getMessage(), e);
133        }
134        return sw.toString();
135    }
136
137    public static Map<String, String> parseCsv(String text) {
138        Map<String, String> properties = new HashMap<>();
139        if (text == null) {
140            return properties;
141        }
142        try (StringReader sr = new StringReader(text);
143                CSVParser reader = new CSVParser(sr, CSVFormat.DEFAULT.withDelimiter('\t'))) {
144            for (CSVRecord record : reader) {
145                properties.put(record.get(0), record.get(1));
146            }
147        } catch (IOException e) {
148            log.error(e, e);
149        }
150        return properties;
151    }
152
153}