package com.openMap1.mapper.util; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; import java.io.FileOutputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.LineNumberReader; import java.io.OutputStream; import java.io.Reader; import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.StringTokenizer; import java.util.Vector; import org.apache.commons.codec.binary.Base64; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Shell; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.FileLocator; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EcorePackage; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.URIConverter; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.emf.ecore.resource.impl.ExtensibleURIConverterImpl; import org.eclipse.emf.ecore.xmi.XMLResource; import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; import com.openMap1.mapper.core.MapperException; import com.openMap1.mapper.structures.XSDStructure; import com.openMap1.mapper.MappedStructure; import com.openMap1.mapper.MapperPackage; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.xsd.XSDSchema; /** * A collection of file handling utilities, all static. * @author robert * */ public class FileUtil { /** * @return the string 'platform:/resource/' */ public static String platformPreface() {return platformPreface;} private static String platformPreface= "platform:/resource/"; /** * Get a file location from the user * @param part IWorkbenchPart - used only to get a shell for the dialogue * @param allowedExts String array of allowed file extensions, of the form {"*.uml","*.xsd"} * @param title the title for the dialogue box * @param saveFile: if true, the dialogue is to save a file; if false, to open an existing file * @return String the file path selected , such as "C:\blah\blah.uml" ; or "" if none was chosen */ public static String getFilePathFromUser(IWorkbenchPart part, String[] allowedExts,String title, boolean saveFile) { String path = ""; FileDialog fd = null; Shell parent = part.getSite().getShell(); if (saveFile) fd = new FileDialog(parent,SWT.SAVE); else fd = new FileDialog(parent,SWT.OPEN); fd.setText(title); fd.setFilterExtensions(allowedExts); fd.open(); if (!fd.getFileName().equals(""))path = fd.getFilterPath() + "\\" + fd.getFileName(); return path; } /** * @return the root of the workspace */ static IWorkspaceRoot getRoot() { return ResourcesPlugin.getWorkspace().getRoot(); } /** * * @param resourceLocation a location in the workspace, starting with "platform:/resource/" * @return the absolute location * @throws MapperException */ public static String absoluteLocation(String resourceLocation) throws MapperException { return absoluteLocation(workspaceRootPath(),resourceLocation); } /** * @param rootPath path to the root of the workspace * @param resourceLocation a location in the workspace, starting with "platform:/resource/" * @return the absolute location * @throws MapperException */ public static String absoluteLocation(String rootPath, String resourceLocation) throws MapperException { String rStart = "platform:/resource/"; if (!(resourceLocation.startsWith(rStart))) throw new MapperException("Resource location '" + resourceLocation + "' does not start with '" + rStart + "'"); String relLoc = resourceLocation.substring(rStart.length()); return (rootPath + "/" + relLoc); } /** * * @param absoluteLocation an absolute file location, which is in the current workspace * @return the relative location in the workspace, starting with "platform:/resource/" * @throws MapperException if the absolute location is not in the workspace */ public static String resourceLocation(String absoluteLocation) throws MapperException { String rStart = "platform:/resource/"; String aStart = removeInitialSlashes(workspaceRootPath()); // message("Adjusted workspace root path: " + aStart); String absPath = removeInitialSlashes(forwardSlashForm(absoluteLocation)); // message("Absolute path to file: " + absPath); if (absPath.startsWith("file:")) absPath = removeInitialSlashes(removeFilePrefix(absPath)); boolean inWorkspace = (absPath.startsWith(aStart)); if (!inWorkspace) throw new MapperException("Absolute location '" + absPath + "' is not in the current workspace"); String relLoc = absPath.substring(aStart.length() + 1); String relPath = (rStart + relLoc); // message("Computed relative path " + relPath); return relPath; } /** * remove any number of initial '/' from a string * @param s */ private static String removeInitialSlashes(String s) { String result = s; while (result.startsWith("/")) result = result.substring(1); return result; } /** * remove the prefix 'file:' from any file path, leaving a string which on PCs will look like '/C:/...'. * (Previously I removed 6 characters to give 'C:/...'. This seems to work as well on PCs, * and the change is made in order to work on Macs) * @param filePath * @return */ public static String removeFilePrefix(String filePath) { return filePath.substring(5); } /** * @return a URIConverter that will normalise 'platform:/resource/' URIs to absolute file paths */ public static URIConverter editURIConverter() { URIConverter uc = new ExtensibleURIConverterImpl(); IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); URI uri1 = URI.createURI("platform:/resource/"); URI uri2 = URI.createURI("file:/" + root.getLocation().toString() + "/"); uc.getURIMap().put(uri1,uri2); return uc; } /** * @param filePath a file path as returned by an SWT FileDialog, such as "C:\blah\blah.uml" * @return if the path is in the workspace, the platform:resource URI * or the file URI if the path is not in the workspace */ public static URI URIFromPath(String filePath) { URI uri = null; if (forwardSlashForm(filePath).startsWith(workspaceRootPath() + "/")) { // remove the root path, but not the first '/' after it String relPath = forwardSlashForm(filePath).substring(workspaceRootPath().length()); uri = URI.createPlatformResourceURI(relPath,true); } else { uri = URI.createFileURI(forwardSlashForm(filePath)); } return uri; } /** * @return absolute file path to the root of the Eclipse workspace */ public static String workspaceRootPath() { IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); return root.getLocation().toString(); } public static String getResourceURIString(String fileURIString) { String uriString = null; String filePrefix = "file:/"; String rawLocation = fileURIString.substring(filePrefix.length()); // the +1 below removes an extra '/' if (rawLocation.startsWith(workspaceRootPath())) uriString = platformPreface() + rawLocation.substring(workspaceRootPath().length()+1); return uriString; } public static void saveResource(Resource resource) { try{ // Save the contents of the resource to the file system. Map<Object, Object> options = new HashMap<Object, Object>(); options.put(XMLResource.OPTION_ENCODING, "UTF-8"); resource.save(options); } catch (Exception ex) {} } /** * * @return true if we are running inside Eclipse; false otherwise. * This relies on throwing an Exception if classes within Eclipse * (org/osgi/framework/BundleActivator) cannot be found; * so it needs that library not to be in the classpath. */ public static boolean isInEclipse() { boolean inEclipse = true; try {workspaceRootPath();} catch (NoClassDefFoundError ex) {inEclipse = false;} catch (IllegalStateException ex) {inEclipse = false;} return inEclipse; } /** * @param filePath an absolute file path, with forward slashes as separators * @return true if the file path is in the Eclipse workspace */ public static boolean isInWorkSpace(String filePath) { return (forwardSlashForm(filePath).startsWith(workspaceRootPath() + "/")); } /** * Convert a file path so the separators are all '/', not '\' * @param path */ public static String forwardSlashForm(String path) { String fsPath = ""; StringTokenizer st = new StringTokenizer(path,"\\"); while (st.hasMoreTokens()) { fsPath = fsPath + st.nextToken(); if (st.hasMoreTokens()) fsPath = fsPath + "/"; } if (path.endsWith("\\")) fsPath = fsPath + "/"; return fsPath; } public static String fSlashForm(String path) { char[] newVersion = new char[path.length()]; for (int i = 0; i < path.length();i++) { char c = path.charAt(i); if (c == '\\') c = '/'; newVersion[i] = c; } String result = new String(newVersion); return result; } /** * this method should return a correct location for the Resource * containing an EObject, both inside and outside Eclipse * @param eo * @return */ public static String fileLocation(EObject eo) { return editURIConverter().normalize(eo.eResource().getURI()).toString(); } /** * Open a file as an EMF model * @param uriString the string form of the URI of the model file * @return the EObject root of the model; or null if failed to open */ public static EObject getEMFModelRoot(String uriString) throws IOException { return getEMFModelRoot(URI.createURI(uriString)); } /** * Open a file as an EMF model * @param uri the URI of the model file * @return the EObject root of the model; or null if failed to open */ public static EObject getEMFModelRoot(URI uri) throws IOException { return (EObject)getEMFResource(uri).getContents().get(0); } public static MappedStructure getMappingSet(URI uri) throws MapperException { EObject root = null; String exMessage = "Could not open mapping set at " + uri.toString() + ": "; try {root = getEMFModelRoot(uri);} catch (IOException ex) {throw new MapperException(exMessage + ex.getMessage());} if (root == null) {throw new MapperException(exMessage + "Null root.");} if (!(root instanceof MappedStructure)) {throw new MapperException(exMessage + "Root is not a MappedStructure.");} return (MappedStructure)root; } /** * Open a file as an EMF model * @param uri the URI of the model file * @return the resource; or null if failed to open */ public static Resource getEMFResource(URI uri) throws IOException { ResourceSet resourceSet = new ResourceSetImpl(); resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap(). put(uri.fileExtension(),new XMIResourceFactoryImpl()); Resource emfResource = resourceSet.createResource(uri); emfResource.load(null); return emfResource; } public static XSDStructure userChooseStructure(IWorkbenchPart targetPart) throws MapperException { XSDStructure xsd = null; // show a dialog for the user to choose a schema, if he wants to order the EReferences correctly String[] exts = {"*.xsd"}; String schemaFilePath = FileUtil.getFilePathFromUser(targetPart,exts,"Select XML schema",false); if (schemaFilePath.equals("")) return xsd; // Open the schema URI uri = FileUtil.URIFromPath(schemaFilePath); XSDSchema theSchema = XSDStructure.getXSDRoot(uri); // find the tree StructureDefinition from the schema if (theSchema != null) xsd = new XSDStructure(theSchema); return xsd; } /** * @param classModelFileLocation full file path to the ecore file * @return the EPackage for the class model * @throws IOException */ public static EPackage getClassModel(String classModelFileLocation) throws MapperException { // register the Ecore package EcorePackage.eINSTANCE.getEFactoryInstance(); ResourceSet resourceSet = new ResourceSetImpl(); // register the factory resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap(). put("ecore", new XMIResourceFactoryImpl()); // create the resource URI uri = URI.createURI("file:/" + classModelFileLocation); Resource resource = resourceSet.createResource(uri); // read the resource and make the class model try { resource.load(null); EPackage classModel = (EPackage)resource.getContents().get(0); return classModel; } catch (IOException ex) {throw new MapperException(ex.getMessage());} } /** * * @param mapperLocation the location of the mapping set * @return the location of the project folder, without a final '/' * @throws MapperException */ public static String projectFolderLocation(String mapperLocation) throws MapperException { String mapLoc = forwardSlashForm(mapperLocation); // URI.toString gives a 'file:/' prefix which we do not want if (mapLoc.startsWith("file:/")) mapLoc = removeFilePrefix(mapLoc); // copy the mapping set location up to and not including the 'MappingSets' folder String folderLoc = ""; StringTokenizer st = new StringTokenizer(mapLoc,"/.",true); boolean foundMappingFolder = false; while ((st.hasMoreTokens())&& !foundMappingFolder) { String tok = st.nextToken(); if (tok.equals("MappingSets")) foundMappingFolder = true; if (!foundMappingFolder) folderLoc = folderLoc + tok; } // throw an exception if no MappingSets folder was found if (!foundMappingFolder) throw new MapperException("Unexpected location for mapping set, not in 'MappingSets' folder: " + mapLoc); int len = folderLoc.length(); return folderLoc.substring(0,len-1); } /** * finds a mapping set referred to from a node in soem mapping set by * @param node * @param platformURL * @return * @throws MapperException */ public static MappedStructure getImportedMappedStructure(EObject node, String platformURL) throws MapperException { if (isInEclipse()) { return getMappingSet(URI.createURI(platformURL)); } else try { String importingLocation = node.eResource().getURI().toString(); return getMappedStructure(getImportedLocation(platformURL,importingLocation)); } catch (IOException ex) {throw new MapperException(ex.getMessage());} } /** * * @param platformURL a URL of a mapping set, * expressed as 'platform:/resource/<project>/MappingSets/<folders>/imported.mapper' * @param importingLocation the file location of the importing mapping set, expressed as * 'file:/<drive letter>:/<outer folders>/MappingSets/<more folders>/importing.mapper' * @return the correct path to imported.mapper, in the form * '<drive letter>:/<outer folders>/MappingSets/<folders>/imported.mapper'; * * i.e it replaces 'platform:/resource/<project>/' at the front by 'C:/<folders>/' * The initial trail <outer folders> should not include a 'MappingSets' folder * */ public static String getImportedLocation(String platformURL, String importingLocation) { // tidy up the importing location, just in case String impLoc = forwardSlashForm(importingLocation); if (impLoc.startsWith("file:/")) impLoc = removeFilePrefix(impLoc); // remove the back end from the importing file location int startLength = impLoc.length() - afterFolder("MappingSets",impLoc).length(); String start = impLoc.substring(0,startLength); // add the back end of the imported file location String importedLocation = start + afterFolder("MappingSets",platformURL); return importedLocation; } /** * From * @param folderName the name of a folder in a path * @param path a String 'blah/blah/<folderName>/more/fileName' * @return '/more/fileName' */ private static String afterFolder(String folderName, String path) { boolean foundFolder = false; String newPath = ""; // pass through the slashes StringTokenizer st = new StringTokenizer(path,"/",true); while (st.hasMoreTokens()) { String step = st.nextToken(); if (foundFolder) newPath = newPath + step; if (step.equals(folderName)) foundFolder = true; } return newPath; } /** * * @param mapperFileLocation full file path to the mapper file * @return the MappedStructure (mapping set) at that location * @throws MapperException * @throws IOException */ public static MappedStructure getMappedStructure(String mapperFileLocation) throws IOException { // register the mapper package MapperPackage.eINSTANCE.getEFactoryInstance(); ResourceSet resourceSet = new ResourceSetImpl(); // register the factory resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap(). put("mapper", new XMIResourceFactoryImpl()); // create the resource String uriString = "file:/" + mapperFileLocation; URI uri = URI.createURI(uriString); Resource resource = resourceSet.createResource(uri); if (resource == null) System.out.println("Null resource at " + uriString); // read the resource and make the mapped Structure resource.load(null); MappedStructure ms = (MappedStructure)resource.getContents().get(0); return ms; } public static String getXSLLocation(String xslFileName, MappedStructure referenceMS) { URI mapperFileURI = referenceMS.eResource().getURI(); String mapperLoc = FileUtil.editURIConverter().normalize(mapperFileURI).toString(); if (mapperLoc.startsWith("file:/")) mapperLoc = removeFilePrefix(mapperLoc); String xslLoc = ""; StringTokenizer st = new StringTokenizer(mapperLoc,"/\\",true); while (st.hasMoreTokens()) { String token = st.nextToken(); if (st.hasMoreTokens()) xslLoc = xslLoc + token; else xslLoc = xslLoc + xslFileName; } return xslLoc; } /** * @param URIString a URI in the workspace, * which may or may not begin with 'platform:/resource/' * @return the IProject of IPRoject handle containing that URI */ public static IProject getProject(String URIString) { String pathString = URIString; if (pathString.startsWith(platformPreface)) pathString = pathString.substring(platformPreface.length()); StringTokenizer st = new StringTokenizer(pathString,"/\\"); return getRoot().getProject(st.nextToken()); } /** * Get an image from an icon folder in the com.openMap1.mapper.edit plugin * @param ImageFileName * @return */ public static Image getImage(String ImageFileName) { Image im = null; try { String pluginURLString = "platform:/plugin/com.openMap1.mapper.edit/icons/full/obj16/" + ImageFileName + ".gif"; URL u1 = new URL(pluginURLString); URL u2= FileLocator.toFileURL(u1); // strip off the first 5 characters 'file:' from the URL String imageFileLocation = removeFilePrefix(u2.toString()); // System.out.println("Image file at '" + imageFileLocation + "'"); im = new Image(null,imageFileLocation); } catch (IOException ex) {System.out.println("IO Exception getting image " + ImageFileName + ": " + ex.getMessage());} return im; } // strip off anything before slashes in a path name, to leave the file name /** * @param path full path name to a file * @return the file name */ public static String getFileName(String path) { String res = ""; StringTokenizer st = new StringTokenizer(path, "/\\"); while (st.hasMoreTokens()) {res = st.nextToken();} return res; } /** * @param path full path name to a file * @return the path to the folder, including the final '/' or '\' */ public static String getFolder(String path) { String fileName = getFileName(path); return path.substring(0,path.length() - fileName.length()); } /** * @param path the full path to a file * @param fileName the name of a sibling file, in the same folder * @return path to the sibling file */ public static String siblingFilePath(String path,String fileName) { int pathLength = path.length() - getFileName(path).length(); return path.substring(0,pathLength) + fileName; } //-------------------------------------------------------------------------------------------------- // methods for placing and finding .wproc files //-------------------------------------------------------------------------------------------------- /** * derive the location of a wproc file from the corresponding mapper file location * (got by URI.toString(), which gives '/' separators). * The path is the same except that: * (1) the 'MappingSets' folder is replaced by the 'Translators' folder (subfolders are the same) * (2) The file extension '.mapper' is replaced by '.wproc' */ public static String wProcLocation(String mapperLocation) { String mapLoc = FileUtil.forwardSlashForm(mapperLocation); // URI.toString gives a 'file:/' prefix which we do not want if (mapperLocation.startsWith("file:/")) mapLoc = removeFilePrefix(mapperLocation); String wProcLoc = ""; // treat the delimiters '/'. '.' as tokens (pass them through) StringTokenizer st = new StringTokenizer(mapLoc,"/.",true); while (st.hasMoreTokens()) { String tok = st.nextToken(); if (tok.equals("MappingSets")) tok = "Translators"; if (tok.equals("mapper") && (!st.hasMoreTokens())) tok = "wproc"; wProcLoc = wProcLoc + tok; } return wProcLoc; } /** * derive the location of a Ecore file from the corresponding mapper file location * (got by URI.toString(), which gives '/' separators), * and from the EMFModelURI string in the mapping set. * This is for use outside Eclipse, assuming the Mapper project folder * structure has been copied */ public static String ecoreFileLocation(String mapperLocation, String umlModelURI) throws MapperException { String ecoreFileLoc = projectFolderLocation(mapperLocation) + "/"; // copy the Ecore model location after and including the 'ClassModel' folder // treat the delimiters '/'. '.' as tokens (pass them through) StringTokenizer st = new StringTokenizer(umlModelURI,"/.",true); boolean foundClassModelFolder = false; while (st.hasMoreTokens()) { String tok = st.nextToken(); if (tok.equals("ClassModel")) foundClassModelFolder = true; if (foundClassModelFolder) ecoreFileLoc = ecoreFileLoc + tok; } return ecoreFileLoc; } //-------------------------------------------------------------------------------------------------- // reading text files //-------------------------------------------------------------------------------------------------- /** * read a text file at an absolute file location */ public static FileInputStream getTextFile(String location) throws MapperException { FileInputStream fi = null; try { fi = new FileInputStream(location); } catch (Exception ex) {throw new MapperException("Cannot read text file at '" + location + "': " + ex.getMessage());} return fi; } /** * * @param location an absolute file location * @return the lines of a text file at the location * @throws MapperException */ public static Vector<String> textLines(String location) throws MapperException { Vector<String> lines = new Vector<String>(); FileInputStream fiz = getTextFile(location); InputStreamReader isr = new InputStreamReader(fiz); LineNumberReader lnr = new LineNumberReader(isr); try { String line = lnr.readLine(); while (line != null) { lines.add(line); line = lnr.readLine(); } lnr.close(); } catch (Exception ex) {throw new MapperException("Failure reading read text file at '" + location + "': " + ex.getMessage());} return lines; } /** * * @param fileLocation * @return the parsed rows of a csv file, including the header row * @throws MapperException */ public static Vector<String[]> getCSVRows(String fileLocation) throws MapperException { Vector<String> lines = textLines(fileLocation); if (lines.size() < 1) throw new MapperException("No lines in csv file"); StringTokenizer cols = new StringTokenizer(lines.get(0),","); Vector<String[]> csvRows = new Vector<String[]>(); for (int i = 0; i < lines.size(); i++) csvRows.add(parseCSVLine(cols.countTokens(),lines.get(i))); return csvRows; } /** * @param bufferedReader reader of a text file * @return each line of the file as a String * @throws MapperException */ public static Vector<String> getLines(InputStream inputFile) throws MapperException { Reader reader = new InputStreamReader(inputFile); BufferedReader bufferedReader = new BufferedReader(reader); Vector<String> lines = new Vector<String>(); String line = ""; while (line != null) try { line = bufferedReader.readLine(); if (line != null) lines.add(line); } catch (IOException ex) {throw new MapperException(ex.getMessage());} return lines; } /** * treats the contents of cells as follows: * remove any new lines, which will screw up a csv file * if there are no ',' or '"', no other change * any '"' is doubled up * if there are any ',', the whole cell contents are enclosed in two '"' * This means ',' which occur after an odd number of '"' are there in the text; * whereas ',' which occur after an even number of '"' are cell separators * @param cells * @return */ public static String makeCSVLine(String[] cells) { String line = ""; for (int i = 0; i < cells.length; i++) { String cell = ""; // double up any existing '"', and remove any new lines StringTokenizer st = new StringTokenizer(removeNewLines(cells[i]),"\"",true); while (st.hasMoreTokens()) { String token = st.nextToken(); cell = cell + token; if (token.equals("\"")) cell = cell + token; } // if the cell has any ',', enclose it all in two outer '"' int commas = new StringTokenizer(cell,",",true).countTokens() - 1; if (commas > 0) cell = "\"" + cell + "\""; // add the cell and a separator comma to the line line = line + cell; if (i < cells.length - 1) line = line + ","; } return line; } /** * remove any new lines from a text String, replacing them by spaces * @param text * @return */ public static String removeNewLines(String text) { byte[] newLineChars = {13,10}; byte[] rawBytes = text.getBytes(); byte[] newBytes = new byte[rawBytes.length]; for (int b = 0; b < rawBytes.length; b++) { byte raw = rawBytes[b]; for (int i = 0; i < 2; i++) if (raw == newLineChars[i]) raw = ' '; newBytes[b] = raw; } return new String(newBytes); } /** * read a line of a csv file, expected to have not more than columns separated fields, * and return a string array of the fields, including "" for any initial ',' * or for final fields not supplied. * Deals with commas and quotes in cells as handled by makeCSVLine * @param columns max number of columns allowed * @param line * @return String array of field values * @throws MapperException */ public static String[] parseCSVLine(int columns, String line) throws MapperException { String[] field = new String[columns]; // break on either comma or quote, and retain them both as tokens StringTokenizer st = new StringTokenizer(line,",\"",true); int col = 0; field[0] = ""; boolean evenQuotes = true; while (st.hasMoreTokens()) { String val = st.nextToken(); if (val.equals("\"")) { evenQuotes = !evenQuotes; /* always consume a quote on its own without adding it to the cell contents */ if (st.hasMoreTokens()) { val = st.nextToken(); // may be '"' ',' or something else if (val.equals("\"")) evenQuotes = !evenQuotes; } else val = ""; // quote at the end of the line } // a comma after an even number of quotes marks a new cell if ((val.equals(",")) && evenQuotes) // no 'else' because the first condition may have fired and changed val { col++; if (col > columns -1) throw new MapperException("Too many columns in csv line '" + line + "'"); field[col]=""; } // at this point val can be '"' ',' or something else; whatever it is, add it to the cell else field[col] = field[col] + val; } // trailing fields not even given ',' if (col < columns - 1) for (int c = col + 1; c < columns; c++) field[c] = ""; return field; } /** * read a line of a csv file, expected to have not more than columns separated fields, * and return a string array of the fields, including "" for and initial ',' or two successive ',', * or for final fields not supplied. * FIXME: does not deal with commas within the csv fields. * @param columns max number of columns allowed * @param line * @return String array of field values * @throws MapperException */ public static String[] oldParseCSVLine(int columns, String line) throws MapperException { String[] field = new String[columns]; StringTokenizer st = new StringTokenizer(line,",",true); int col = 0; boolean emptyField = true; while (st.hasMoreTokens()) { if (col > columns -1) throw new MapperException("Too many columns in csv line '" + line + "'"); String val = st.nextToken(); if (val.equals(",")) { if (emptyField) // initial ',', or two successive ',' { field[col]=""; col++; } emptyField = true; } else // non-empty field { field[col] = val; col++; emptyField = false; } } // trailing fields not even given ',' if (col < columns) for (int c = col; c < columns; c++) field[c] = ""; return field; } //-------------------------------------------------------------------------------------------------- // writing csv files //-------------------------------------------------------------------------------------------------- public static void writeCSVFile(String location, Vector<String[]> csvRows) throws MapperException { try { FileOutputStream fo = new FileOutputStream(location); for (int i = 0; i < csvRows.size(); i++) { String[] row = csvRows.get(i); String rowText = makeCSVLine(row); nl(rowText, fo); } fo.close(); } catch (Exception ex) {ex.printStackTrace();throw new MapperException(ex.getMessage());} } //-------------------------------------------------------------------------------------------------- // writing text files //-------------------------------------------------------------------------------------------------- private static byte[] newLine = {13,10}; // write out a String followed by a new line public static void nl(String s, OutputStream fo) { try{ fo.write(s.getBytes()); fo.write(newLine); } catch (IOException e) {message("Exception writing line '" + s + "': " + e.getMessage());} } // write out a String followed by no new line public static void nnl(String s, OutputStream fo) { try{ fo.write(s.getBytes()); } catch (IOException e) {message("Exception writing line '" + s + "': " + e.getMessage());} } public static void quoted(String s, FileOutputStream fo) { byte[] quote = {'"'}; try{ fo.write(quote); fo.write(s.getBytes()); fo.write(quote); } catch (IOException e) {message("Exception writing quoted string '" + s + "': " + e.getMessage());} } //-------------------------------------------------------------------------------------------------- // Base64 Encoding (for PDF files) //-------------------------------------------------------------------------------------------------- /** * encode a binary input as a base64 String * @param input * @return */ public static String base64Encode(byte[] input) { byte[] encoded = new Base64().encode(input); String result = new String(encoded); return result; } //-------------------------------------------------------------------------------------------------- // Trivia //-------------------------------------------------------------------------------------------------- public static void message(String s) {System.out.println(s);} }