using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Perforce.P4 { /// <summary> /// Describes fields and comments in a Perforce specification. /// </summary> public class FormBase :Dictionary<string, object> { public Dictionary<string, bool> IsFieldMultiLine { get; internal set; } public String Comments { get; set; } public FormBase() { IsFieldMultiLine = new Dictionary<string,bool>(); } #region Tagged Form Data /// <summary> /// Set the Values Dictionary from tagged output of a Perforce command. /// </summary> /// <remarks> /// Needed when the object's data dictionary is set after the object /// is created using the default constructer. /// </remarks> /// <param name="data">Object data</param> internal void SetValues(TaggedObject data) { //if (data.ContainsKey("specdef")) //{ // specDescription = new SpecificationMetaData(data["specdef"]); //} // map of base key names to max index (so far) Dictionary<string, int> baseKeys = new Dictionary<string,int>(); foreach (String key in data.Keys) { try { if (char.IsNumber(key, key.Length - 1)) { // value is part of a list string baseKey = key.TrimEnd('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); string idxStr = key.Substring(baseKey.Length); int idx = -1; int.TryParse(idxStr, out idx); IsFieldMultiLine[baseKey] = false; if (ContainsKey(baseKey) == false) { this[baseKey] = new List<string>(idx + 1); } List<string> strList = this[baseKey] as List<string>; while (strList.Count <= idx) { strList.Add(null); } strList[idx] = data[key]; } else { if (data[key].Contains("\r") || data[key].Contains("\n")) { IsFieldMultiLine[key] = true; } this[key] = data[key]; } } catch { }; //Extra tag included with TaggedInfoItem data can be ignored } } #endregion #region From string data (a spec form) /// <summary> /// Parse a string specification in the server format into an object. /// </summary> /// <remarks> /// The base implementation parses the generic specification tag::value /// format into the underlying dictionary /// </remarks> /// <param name="spec">String specification</param> /// <returns>Success/Failure</returns> virtual public bool Parse(String spec) { String currentTag = String.Empty; IList<string> currentValueList = null; String[] lines = spec.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); for (int idx = 0; idx < lines.Length; idx++) { if (lines[idx][0] == '#') // # comment { if (Comments == null) { Comments = lines[idx]; } else { Comments += "\r\n"; Comments += lines[idx]; } continue; } else if (lines[idx][0] == '\t') // tab char so this is part of a value field { currentValueList.Add(lines[idx].TrimStart('\t')); } else { //new tag line String line = lines[idx].Trim(); int colonPos = line.IndexOf(':'); if (colonPos <= 0) //bad line continue; // start of a tag currentValueList = null; currentTag = line.Substring(0, colonPos); if (colonPos < line.Length - 1) { // right of colon is the value this[currentTag] = line.Substring(colonPos + 1).Trim(); IsFieldMultiLine[currentTag] = false; } else { IsFieldMultiLine[currentTag] = true; currentValueList = new List<string>(); this[currentTag] = currentValueList; } } } return true; } #endregion /// <summary> /// Create a form specification from the fields that make up a form /// </summary> /// <returns></returns> public override string ToString() { StringBuilder buff = new StringBuilder(2048); if (Comments != null) { buff.AppendLine(Comments); } foreach (string key in Keys) { // ignore values that do not go into the spec form if (key == "specdef" || key == "specFormatted" || key == "func") { continue; } if ((IsFieldMultiLine.ContainsKey(key)) && (IsFieldMultiLine[key])) { buff.AppendFormat("{0}:\n", key); if (this[key] is string) { string multilineString = this[key] as string; multilineString= multilineString.TrimEnd('\n', '\r'); if (multilineString.Contains("\n")) { multilineString = multilineString.Replace("\r", ""); multilineString = multilineString.Replace("\n", "\n\t"); } else if (multilineString.Contains("\r")) { multilineString = multilineString.Replace("\r", "\n\t"); } buff.AppendFormat("\t{0}\n", (multilineString)); } else { IList<string> lines = this[key] as IList<string>; for (int idx = 0; idx < lines.Count; idx++) { buff.AppendFormat("\t{0}\n", lines[idx]); } } } else { buff.AppendFormat("{0}:\t{1}\n", key, this[key] as string); } } return buff.ToString(); } /// <summary> /// Utility function to format a DateTime in the format expected in a spec /// </summary> /// <param name="dt"></param> /// <returns></returns> public static String FormatDateTime(DateTime dt) { if ((dt != null) && (DateTime.MinValue != dt)) return dt.ToString("yyyy|MM|dd HH:mm:ss").Replace('|','/'); return string.Empty; } /// <summary> /// Utility to convert a Unix time (Seconds past midnight 1/1/1970) to a DateTime /// </summary> /// <param name="unixTime"></param> /// <returns></returns> public static DateTime ConvertUnixTime(long unixTime) { return new DateTime(1970, 1, 1, 0, 0, 0, 0).AddSeconds(unixTime); } /// <summary> /// Utility to convert a Unix time (Seconds past midnight 1/1/1970) to a DateTime /// </summary> /// <param name="unixTimeStr">Unix time as a string</param> /// <returns></returns> public static DateTime ConvertUnixTime(string unixTimeStr) { long unixTime = 0; if (long.TryParse(unixTimeStr, out unixTime)) { return new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(unixTime); } return new DateTime(1970, 1, 1, 0, 0, 0, 0); } public static bool DSTMismatch(ServerMetaData smd) { try { DateTime serverDate = smd.Date; bool UTC_dst = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time").IsDaylightSavingTime(serverDate); bool server_dst = serverDate.IsDaylightSavingTime(); if (server_dst && !UTC_dst) { return true; } } catch { } return false; } public static DateTime ConvertFromUTC(DateTime dt, string offset, bool DST_mistmatch) { int idx = offset.IndexOf(" "); if (idx >= 0) { offset = offset.Remove(offset.IndexOf(" ")); } offset = offset.TrimEnd('0'); int timeDiff; bool num = int.TryParse(offset, out timeDiff); dt = dt.AddHours(timeDiff); bool timestampDST = dt.IsDaylightSavingTime(); if (!timestampDST&&DST_mistmatch) { dt = dt.AddHours(-1); } return dt; } /// <summary> /// Utility to properly format multi-line fields in forms /// </summary> /// <param name="multiLine">Multi-line field</param> /// <returns></returns> public static string FormatMultilineField(string multiline) { String tmpMultilineStr = String.Empty; if (!String.IsNullOrEmpty(multiline)) { tmpMultilineStr = multiline.Replace("\r", "").Trim('\r', '\n'); tmpMultilineStr = tmpMultilineStr.Replace("\n", "\n\t").Trim(); } return tmpMultilineStr; } } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 19640 | Liz Lam | "Forking branch Main of perforce-software-p4connect to liz_lam-p4connect." | ||
//guest/perforce_software/p4connect/main/src/P4Bridge/p4api.net/FormBase.cs | |||||
#1 | 16209 | Norman Morse | Move entire source tree into "main" branch so workshop code will act correctly. | ||
//guest/perforce_software/p4connect/src/P4Bridge/p4api.net/FormBase.cs | |||||
#2 | 12135 | Norman Morse |
Integrate dev branch changes into main. This code is the basiis of the 2.7 BETA release which provides Unity 5 compatibility |
||
#1 | 10940 | Norman Morse |
Inital Workshop release of P4Connect. Released under BSD-2 license |