/******************************************************************************* * Copyright (c) 2004, 2005 * Thomas Hallgren, Kenneth Olwing, Mitch Sonies * Pontus Rydin, Nils Unden, Peer Torngren * The code, documentation and other materials contained herein have been * licensed under the Eclipse Public License - v 1.0 by the individual * copyright holders listed above, as Initial Contributors under such license. * The text of such license is available at www.eclipse.org. *******************************************************************************/ package org.eclipse.buckminster.p4.internal; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; import org.eclipse.buckminster.p4.Messages; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.osgi.util.NLS; /** * @author thhal */ public abstract class DepotObject { public class ViewEntry { private final IPath m_depotPath; private final IPath m_localPath; public ViewEntry(IPath depotPath, IPath localPath) { if(!(depotPath.isUNC() && localPath.isUNC())) throw new IllegalArgumentException(Messages.only_UNC_paths_are_accepted); m_depotPath = depotPath; m_localPath = localPath; } ViewEntry(String viewSpecLine) { this(parsePaths(viewSpecLine)); } private ViewEntry(IPath[] paths) { this(paths[0], paths[1]); } /** * @return Returns the depotPath. */ public final IPath getDepotPath() { return m_depotPath; } /** * @return Returns the localPath. */ public final IPath getLocalPath() { return m_localPath; } /** * * @return A string representation. */ @Override public final String toString() { return concatMultiPaths(new String[] { expandEscapedChars(m_depotPath.toString()), expandEscapedChars(m_localPath.toString()) }); } } /** * Concatenates the array of <code>paths</code> into one space separated string. Paths that contains spaces will be * quoted using the " character. * * @param paths * The paths to concatenate. * @return The string of concatenated paths. * @see #splitMultiPaths(String) */ public static String concatMultiPaths(String[] paths) { StringBuilder bld = new StringBuilder(); for(String path : paths) { if(bld.length() > 0) bld.append(' '); if(path.indexOf(' ') >= 0) { bld.append('"'); bld.append(path); bld.append('"'); } else bld.append(path); } return bld.toString(); } /** * Expand the P4 "forbidden" characters into their %<hexadecimal ascii code> corresponance. * * @param path * The path to expand. * @return An expanded path. * @see #parseEscapedChars(String) */ public static String expandEscapedChars(String path) { StringBuilder bld = new StringBuilder(); int top = path.length(); for(int idx = 0; idx < top; ++idx) { char c = path.charAt(idx); switch(c) { case '@': bld.append("%40"); //$NON-NLS-1$ continue; case '#': bld.append("%23"); //$NON-NLS-1$ continue; case '*': bld.append("%2a"); //$NON-NLS-1$ continue; case '%': bld.append("%25"); //$NON-NLS-1$ continue; } bld.append(c); } return bld.toString(); } /** * Parse occurences of %<hexadecimal ascii code> into their corresponding ascii character. * * @param path * The path to parse * @return A path where the parsed characters has been replaced. * @see #expandEscapedChars(String) */ public static String parseEscapedChars(String path) { StringBuilder bld = null; int top = path.length(); for(int idx = 0; idx < top; ++idx) { char c = path.charAt(idx); if(c == '%' && idx + 1 < top) { int percentStart = idx; char c2 = path.charAt(++idx); if(c2 == '%') { // Loose one of the two % // if(bld == null) { bld = new StringBuilder(); if(percentStart > 0) bld.append(path.substring(0, percentStart)); } bld.append(c2); continue; } if(Character.isDigit(c2) && idx + 1 < top && Character.isDigit(path.charAt(++idx))) { // Treat as hex character // if(bld == null) { bld = new StringBuilder(); if(percentStart > 0) bld.append(path.substring(0, percentStart)); } int ascii = Integer.parseInt(path.substring(idx - 1, idx + 1), 16); bld.append((char)ascii); } else { if(bld != null) { bld.append(c); bld.append(c2); } } continue; } if(bld != null) bld.append(c); } if(bld != null) path = bld.toString(); return path; } /** * Split a String containing space separated paths into multiple strings. A path may contain spaces if it is quoted * using " * * @param entry * The entry that contains multiple paths. * @return An array of paths. * @see #concatMultiPaths(String[]) */ public static String[] splitMultiPaths(String entry) { List<String> paths = new ArrayList<String>(); int top = entry.length(); for(int idx = 0; idx < top; ++idx) { String body = null; char c = entry.charAt(idx); while(idx < top && Character.isWhitespace(c)) c = entry.charAt(++idx); if(idx == top) break; if(c == '"') { int start = ++idx; for(; idx < top; ++idx) if(entry.charAt(idx) == '"') body = entry.substring(start, idx++); if(body == null) throw new IllegalArgumentException(NLS.bind(Messages.missing_ending_quote_view_file_entry_0, entry)); } else { int start = idx++; while(idx < top && !Character.isWhitespace(entry.charAt(idx))) ++idx; body = entry.substring(start, idx); } paths.add(body); } return paths.toArray(new String[paths.size()]); } private static IPath[] parsePaths(String viewSpecLine) { String[] paths = splitMultiPaths(viewSpecLine); if(paths.length != 2) throw new IllegalArgumentException(Messages.pair_with_depot_path_and_client_path_expected); return new IPath[] { new Path(parseEscapedChars(paths[0])), new Path(parseEscapedChars(paths[1])) }; } private final Connection m_connection; private final Map<String, String> m_info; protected DepotObject(Connection client, Map<String, String> info) { m_connection = client; m_info = info; } public final Connection getConnection() { return m_connection; } final synchronized String get(String key) { return m_info.get(key); } final Map<String, String> getInfo() { return m_info; } Date getParsedDate(String dateName) throws CoreException { String date = this.get(dateName); if(date == null) return null; return this.getConnection().parseDate(date); } final ViewEntry[] getViewSpec() { List<ViewEntry> entries = new ArrayList<ViewEntry>(); int entryNum = 0; for(;; ++entryNum) { String pair = this.get("View" + Integer.toString(entryNum)); //$NON-NLS-1$ if(pair == null) break; entries.add(new ViewEntry(pair)); } return entries.toArray(new ViewEntry[entries.size()]); } final synchronized String put(String key, String value) { return m_info.put(key, value); } final synchronized String remove(String key) { return m_info.remove(key); } }