Rob van der Woude's Scripting Pages
Powered by GeSHi

Source code for capturedate.cs

(view source code of capturedate.cs as plain text)

  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Text.RegularExpressions;
  5.  
  6.  
  7. namespace RobvanderWoude
  8. {
  9. 	class CaptureDate
  10. 	{
  11. 		static string progver = "1.02";
  12.  
  13.  
  14. 		static int Main( string[] args )
  15. 		{
  16. 			#region Initialize Variables
  17.  
  18. 			string filename = String.Empty;
  19. 			bool confirmsettimestamp = true;
  20. 			bool readabletimestamp = true;
  21. 			bool settimestamp = false;
  22. 			double timediffthreshold = 3600;
  23.  
  24. 			#endregion Initialize Variables
  25.  
  26.  
  27. 			#region Parse Command Line
  28.  
  29. 			if ( args.Length == 0 )
  30. 			{
  31. 				return ShowHelp( );
  32. 			}
  33.  
  34. 			foreach ( string arg in args )
  35. 			{
  36. 				if ( arg == "/?" || arg.Length < 2 )
  37. 				{
  38. 					return ShowHelp( );
  39. 				}
  40. 				if ( arg[0] == '/' )
  41. 				{
  42. 					switch ( arg.Substring( 0, 2 ).ToUpper( ) )
  43. 					{
  44. 						case "/D":
  45. 							if ( arg.Length > 3 && arg[2] == ':' )
  46. 							{
  47. 								if ( timediffthreshold != 3600 )
  48. 								{
  49. 									return ShowHelp( "Duplicate switch: /D" );
  50. 								}
  51. 								try
  52. 								{
  53. 									timediffthreshold = Convert.ToDouble( arg.Substring( 3 ) );
  54. 								}
  55. 								catch
  56. 								{
  57. 									return ShowHelp( "Invalid value: \"{0}\"", arg );
  58. 								}
  59. 							}
  60. 							else
  61. 							{
  62. 								return ShowHelp( "Invalid value: \"{0}\"", arg );
  63. 							}
  64. 							break;
  65. 						case "/S":
  66. 							if ( settimestamp )
  67. 							{
  68. 								return ShowHelp( "Duplicate switch: /S" );
  69. 							}
  70. 							settimestamp = true;
  71. 							break;
  72. 						case "/T":
  73. 							if ( !readabletimestamp )
  74. 							{
  75. 								return ShowHelp( "Duplicate switch: /T" );
  76. 							}
  77. 							readabletimestamp = false;
  78. 							break;
  79. 						case "/Y":
  80. 							if ( !confirmsettimestamp )
  81. 							{
  82. 								return ShowHelp( "Duplicate switch: /Y" );
  83. 							}
  84. 							confirmsettimestamp = false;
  85. 							break;
  86. 						default:
  87. 							return ShowHelp( "Invalid switch: \"{0}\"", arg );
  88. 					}
  89. 				}
  90. 				else
  91. 				{
  92. 					if ( !String.IsNullOrEmpty( filename ) )
  93. 					{
  94. 						return ShowHelp( "Invalid or duplicate argument(s)" );
  95. 					}
  96. 					filename = arg;
  97. 					if ( !String.IsNullOrEmpty( Path.GetDirectoryName( filename ) ) && !Directory.Exists( Path.GetDirectoryName( filename ) ) )
  98. 					{
  99. 						return ShowHelp( "Folder not found: \"{0}\"", Path.GetDirectoryName( filename ) );
  100. 					}
  101. 					if ( !File.Exists( filename ) )
  102. 					{
  103. 						return ShowHelp( "File not found: \"{0}\"", filename );
  104. 					}
  105. 				}
  106. 			}
  107. 			if ( string.IsNullOrEmpty( filename ) )
  108. 			{
  109. 				return ShowHelp( "No file specified" );
  110. 			}
  111. 			if ( !confirmsettimestamp && !settimestamp )
  112. 			{
  113. 				return ShowHelp( "/Y switch is valid only when combined with /S switch." );
  114. 			}
  115. 			if ( timediffthreshold != 3600 && !settimestamp )
  116. 			{
  117. 				return ShowHelp( "/D switch is valid only when combined with /S switch." );
  118. 			}
  119.  
  120. 			#endregion Parse Command Line
  121.  
  122.  
  123. 			try
  124. 			{
  125. 				#region Read First MB of File
  126.  
  127. 				long filesize = new FileInfo( filename ).Length;
  128. 				int buffersize = Convert.ToInt32( Math.Min( filesize, 1048576 ) ); // Buffer size is 1 MB or file size, whichever is the smallest
  129. 				StreamReader file = new StreamReader( filename );
  130. 				char[] buffer = new Char[buffersize];
  131. 				int result = file.Read( buffer, 0, buffersize - 1 ); // Read only the first 1 MB of the file (or the entire file if smaller than 1 MB)
  132. 				file.Close( );
  133. 				string header = new String( buffer );
  134.  
  135. 				if ( String.IsNullOrEmpty( header ) )
  136. 				{
  137. 					return ShowHelp( "Could not open file \"{0}\"", filename );
  138. 				}
  139.  
  140. 				#endregion Read First MB of File
  141.  
  142.  
  143. 				#region Find Earliest Date String
  144.  
  145. 				string pattern = "\\b[12]\\d{3}:[01]\\d:[0-3]\\d [0-2]\\d:[0-5]\\d:[0-5]\\d\\b";
  146. 				Regex regexp = new Regex( pattern, RegexOptions.None );
  147. 				MatchCollection matches = regexp.Matches( header );
  148. 				if ( matches.Count == 0 )
  149. 				{
  150. 					return ShowHelp( "No capture date found in file header" );
  151. 				}
  152. 				string photodatedelimited = String.Empty;
  153. 				foreach ( Match match in matches )
  154. 				{
  155. 					if ( String.IsNullOrEmpty( photodatedelimited ) || String.Compare( photodatedelimited, match.Value, StringComparison.Ordinal ) > 0 )
  156. 					{
  157. 						photodatedelimited = match.Value;
  158. 					}
  159. 				}
  160. 				photodatedelimited = photodatedelimited.Substring( 0, 10 ).Replace( ":", "-" ) + photodatedelimited.Substring( 10 );
  161. 				string photodatenodelims = photodatedelimited.Replace( ":", "" ).Replace( "-", "" ).Replace( " ", "T" );
  162.  
  163. 				#endregion Find Earliest Date String
  164.  
  165.  
  166. 				if ( settimestamp )
  167. 				{
  168. 					string timeformat;
  169. 					if ( readabletimestamp )
  170. 					{
  171. 						timeformat = "{0:yyyy}-{0:MM}-{0:dd} {0:HH}:{0:mm}:{0:ss}";
  172. 					}
  173. 					else
  174. 					{
  175. 						timeformat = "{0:yyyy}{0:MM}{0:dd}T{0:HH}{0:mm}{0:ss}";
  176. 					}
  177. 					DateTime currenttimestamp = File.GetLastWriteTime( filename );
  178. 					DateTime newtimestamp = DateTime.Parse( "01-01-0001 00:00:00" ); // Initial value for new timestamp
  179. 					if ( DateTime.TryParse( photodatedelimited, out newtimestamp ) ) // Try parsing the new file timestamp using the capture timestamp string
  180. 					{
  181. 						if ( DateTime.Compare( currenttimestamp, newtimestamp ) == 0 ) // File and capture timestamps are equal
  182. 						{
  183. 							if ( readabletimestamp )
  184. 							{
  185. 								Console.WriteLine( photodatedelimited );
  186. 							}
  187. 							else
  188. 							{
  189. 								Console.WriteLine( photodatenodelims );
  190. 							}
  191. 						}
  192. 						else
  193. 						{
  194. 							double timediff = Math.Abs( ( currenttimestamp - newtimestamp ).TotalSeconds ); // Calculate absolute value of timestamps' difference in seconds
  195. 							if ( timediff > timediffthreshold ) // Ignore time differences up to threshold (default 1 hour, or value set with /D switch)
  196. 							{
  197. 								string blanks = "\n" + new String( ' ', 70 ) + new String( '\b', 70 ); // String to erase the first 70 characters on the next line
  198. 								Console.WriteLine( "Image file name        : {0}", filename );
  199. 								Console.WriteLine( "Current file timestamp : " + timeformat, currenttimestamp );
  200. 								Console.WriteLine( "Capture timestamp      : " + timeformat, newtimestamp );
  201. 								if ( confirmsettimestamp )
  202. 								{
  203. 									Console.Write( "Do you want to change the file's timestamp to the capture time? [yN] " );
  204. 									string answer = Console.ReadKey( ).KeyChar.ToString( ).ToUpper( );
  205. 									if ( answer == "Y" )
  206. 									{
  207. 										File.SetLastWriteTime( filename, newtimestamp );
  208. 										Console.CursorTop = Console.CursorTop - 1; // Move the cursor 1 line up
  209. 										Console.WriteLine( blanks + "New file timestamp     : " + timeformat, File.GetLastWriteTime( filename ) ); // Overwrite prompt with new timestamp
  210. 									}
  211. 									else
  212. 									{
  213. 										Console.WriteLine( "\naborting . . ." );
  214. 									}
  215. 								}
  216. 								else
  217. 								{
  218. 									File.SetLastWriteTime( filename, newtimestamp );
  219. 									Console.CursorTop = Console.CursorTop - 1; // Move the cursor 1 line up
  220. 									Console.WriteLine( blanks + "New file timestamp     : " + timeformat, File.GetLastWriteTime( filename ) ); // Overwrite prompt with new timestamp
  221. 								}
  222.  
  223. 							}
  224. 							else
  225. 							{
  226. 								Console.WriteLine( photodatedelimited ); // Timespans' difference is not above threshold (default 1 hour, or value set with /D switch)
  227. 							}
  228. 						}
  229. 					}
  230. 					else
  231. 					{
  232. 						return ShowHelp( "Could not determine timestamp of \"{0}\"", filename );
  233. 					}
  234. 				}
  235. 				else
  236. 				{
  237. 					Console.WriteLine( photodatedelimited );
  238. 				}
  239.  
  240. 				return 0;
  241. 			}
  242. 			catch ( Exception e )
  243. 			{
  244. 				return ShowHelp( e.Message );
  245. 			}
  246. 		}
  247.  
  248.  
  249. 		static string Today( bool usedelims = true )
  250. 		{
  251. 			string dateformat;
  252. 			if ( usedelims )
  253. 			{
  254. 				dateformat = "{0:yyyy}-{0:MM}-{0:dd} {0:HH}:{0:mm}:{0:ss}";
  255. 			}
  256. 			else
  257. 			{
  258. 				dateformat = "{0:yyyy}{0:MM}{0:dd}T{0:HH}{0:mm}{0:ss}";
  259. 			}
  260. 			return String.Format( dateformat, DateTime.Now );
  261. 		}
  262.  
  263.  
  264. 		#region Error handling
  265.  
  266. 		public static int ShowHelp( params string[] errmsg )
  267. 		{
  268. 			#region Error Message
  269.  
  270. 			if ( errmsg.Length > 0 )
  271. 			{
  272. 				List<string> errargs = new List<string>( errmsg );
  273. 				errargs.RemoveAt( 0 );
  274. 				Console.Error.WriteLine( );
  275. 				Console.ForegroundColor = ConsoleColor.Red;
  276. 				Console.Error.Write( "ERROR:\t" );
  277. 				Console.ForegroundColor = ConsoleColor.White;
  278. 				Console.Error.WriteLine( errmsg[0], errargs.ToArray( ) );
  279. 				Console.ResetColor( );
  280. 			}
  281.  
  282. 			#endregion Error Message
  283.  
  284.  
  285. 			#region Help Text
  286.  
  287. 			/*
  288. 			CaptureDate,  Version 1.02
  289. 			Return the capture date and time for the specified image file
  290.  
  291. 			Usage:   CAPTUREDATE  image  [ options ]
  292.  
  293. 			Where:   image        specifies the image file
  294.  
  295. 			Options: /D:seconds   minimum Difference in seconds between current file
  296. 			                      timestamp and capture date/time; if the difference
  297. 			                      exceeds the specified number of seconds, the file
  298. 			                      timestamp will be set to the capture date/time
  299. 			                      (default: 3600 seconds = 1 hour; requires /S switch)
  300. 			         /S           Set the image file timestamp to the capture date/time
  301. 			         /T           return the timestamp without "-" and ":" delimiters,
  302. 			                      e.g. 20171114T135628 instead of 2017-11-14 13:56:28
  303. 			         /Y           do not ask for confirmation before changing the image
  304. 			                      file's timestamp (requires /S switch)
  305.  
  306. 			Notes:   Result will be displayed on screen, e.g. 2017-11-14 13:56:28.
  307. 			         The date/time is extracted by searching for the earliest date/time
  308. 			         string in the first 1048576 bytes (1 MB) of the image file.
  309. 			         With /S switch used, the timestamp is changed only if the difference
  310. 			         between the current timestamp and the capture time exceeds 1 hour or
  311. 			         the threshold set with the /D switch.
  312. 			         The program will ask for confirmation before changing the file's
  313. 			         timestamp, unless the /Y switch is used.
  314. 			         Return code ("errorlevel") is -1 in case of errors or if no valid
  315. 			         date was found, or 0 otherwise.
  316.  
  317. 			Written by Rob van der Woude
  318. 			http://www.robvanderwoude.com
  319. 			*/
  320.  
  321. 			string timestampDelimited = Today( true );
  322. 			string timestampNodelims = Today( false );
  323. 			Console.Error.WriteLine( );
  324.  
  325. 			Console.Error.WriteLine( "CaptureDate,  Version {0}", progver );
  326.  
  327. 			Console.Error.WriteLine( "Return the capture date and time for the specified image file" );
  328.  
  329. 			Console.Error.WriteLine( );
  330.  
  331. 			Console.Error.Write( "Usage:   " );
  332. 			Console.ForegroundColor = ConsoleColor.White;
  333. 			Console.Error.WriteLine( "CAPTUREDATE  image  [ options ]" );
  334. 			Console.ResetColor( );
  335.  
  336. 			Console.Error.WriteLine( );
  337.  
  338. 			Console.Error.Write( "Where:   " );
  339. 			Console.ForegroundColor = ConsoleColor.White;
  340. 			Console.Error.Write( "image" );
  341. 			Console.ResetColor( );
  342. 			Console.Error.WriteLine( "        specifies the image file" );
  343.  
  344. 			Console.Error.WriteLine( );
  345.  
  346. 			Console.Error.Write( "Options: " );
  347. 			Console.ForegroundColor = ConsoleColor.White;
  348. 			Console.Error.Write( "/D:seconds" );
  349. 			Console.ResetColor( );
  350. 			Console.Error.Write( "   minimum " );
  351. 			Console.ForegroundColor = ConsoleColor.White;
  352. 			Console.Error.Write( "D" );
  353. 			Console.ResetColor( );
  354. 			Console.Error.Write( "ifference in " );
  355. 			Console.ForegroundColor = ConsoleColor.White;
  356. 			Console.Error.Write( "seconds" );
  357. 			Console.ResetColor( );
  358. 			Console.Error.WriteLine( " between current file" );
  359.  
  360. 			Console.Error.WriteLine( "                      timestamp and capture date/time; if the difference" );
  361.  
  362. 			Console.Error.WriteLine( "                      exceeds the specified number of seconds, the file" );
  363.  
  364. 			Console.Error.WriteLine( "                      timestamp will be set to the capture date/time" );
  365.  
  366. 			Console.Error.Write( "                      (default: 3600 seconds = 1 hour; requires " );
  367. 			Console.ForegroundColor = ConsoleColor.White;
  368. 			Console.Error.Write( "/S" );
  369. 			Console.ResetColor( );
  370. 			Console.Error.WriteLine( " switch)" );
  371.  
  372. 			Console.ForegroundColor = ConsoleColor.White;
  373. 			Console.Error.Write( "         /S           S" );
  374. 			Console.ResetColor( );
  375. 			Console.Error.WriteLine( "et the image file's timestamp to the capture date/time" );
  376.  
  377. 			Console.ForegroundColor = ConsoleColor.White;
  378. 			Console.Error.Write( "         /T" );
  379. 			Console.ResetColor( );
  380. 			Console.Error.WriteLine( "           return the timestamp without \"-\" and \":\" delimiters," );
  381.  
  382. 			Console.Error.Write( "                      e.g. " );
  383. 			Console.ForegroundColor = ConsoleColor.White;
  384. 			Console.Error.Write( timestampNodelims );
  385. 			Console.ResetColor( );
  386. 			Console.Error.Write( " instead of " );
  387. 			Console.ForegroundColor = ConsoleColor.White;
  388. 			Console.Error.Write( timestampDelimited );
  389. 			Console.ResetColor( );
  390. 			Console.Error.WriteLine( "." );
  391.  
  392. 			Console.ForegroundColor = ConsoleColor.White;
  393. 			Console.Error.Write( "         /Y" );
  394. 			Console.ResetColor( );
  395. 			Console.Error.WriteLine( "           do not ask for confirmation before changing the image" );
  396.  
  397. 			Console.Error.Write( "                      file's timestamp (requires " );
  398. 			Console.ForegroundColor = ConsoleColor.White;
  399. 			Console.Error.Write( "/S" );
  400. 			Console.ResetColor( );
  401. 			Console.Error.WriteLine( " switch)" );
  402.  
  403. 			Console.Error.WriteLine( );
  404.  
  405. 			Console.Error.Write( "Notes:   Result will be displayed on screen, e.g. " );
  406. 			Console.ForegroundColor = ConsoleColor.White;
  407. 			Console.Error.Write( timestampDelimited );
  408. 			Console.ResetColor( );
  409. 			Console.Error.WriteLine( "." );
  410.  
  411. 			Console.Error.WriteLine( "         The date/time is extracted by searching for the earliest date/time" );
  412.  
  413. 			Console.Error.WriteLine( "         in the first 1048576 bytes (1 MB) of the image file." );
  414.  
  415. 			Console.Error.Write( "         With " );
  416. 			Console.ForegroundColor = ConsoleColor.White;
  417. 			Console.Error.Write( "/S" );
  418. 			Console.ResetColor( );
  419. 			Console.Error.WriteLine( " switch used, the timestamp is changed only if the difference" );
  420.  
  421. 			Console.Error.WriteLine( "         between the current timestamp and the capture time exceeds 1 hour or" );
  422.  
  423. 			Console.Error.Write( "         the threshold set with the " );
  424. 			Console.ForegroundColor = ConsoleColor.White;
  425. 			Console.Error.Write( "/D" );
  426. 			Console.ResetColor( );
  427. 			Console.Error.WriteLine( " switch." );
  428.  
  429. 			Console.Error.WriteLine( "         The program will ask for confirmation before changing the file's" );
  430.  
  431. 			Console.Error.Write( "         timestamp, unless the " );
  432. 			Console.ForegroundColor = ConsoleColor.White;
  433. 			Console.Error.Write( "/Y" );
  434. 			Console.ResetColor( );
  435. 			Console.Error.WriteLine( " switch is used." );
  436.  
  437. 			Console.Error.WriteLine( "         Return code (\"errorlevel\") is -1 in case of errors or if no valid" );
  438.  
  439. 			Console.Error.WriteLine( "         date was found, or 0 otherwise." );
  440.  
  441. 			Console.Error.WriteLine( );
  442.  
  443. 			Console.Error.WriteLine( "Written by Rob van der Woude" );
  444.  
  445. 			Console.Error.WriteLine( "http://www.robvanderwoude.com" );
  446.  
  447. 			#endregion Help Text
  448.  
  449.  
  450. 			return -1;
  451. 		}
  452.  
  453. 		#endregion Error handling
  454.  
  455. 	}
  456. }
  457.  

page last uploaded: 2018-12-04, 10:47