using Nikse.SubtitleEdit.Core.TransportStream; using Nikse.SubtitleEdit.Core.VobSub; using System; using System.IO; using System.Text; namespace Nikse.SubtitleEdit.Core { /// /// File related utilities. /// public static class FileUtil { /// /// Opens a binary file in read/write shared mode, reads the contents of the file into a /// byte array, and then closes the file. /// /// The file to open for reading. /// A byte array containing the contents of the file. public static byte[] ReadAllBytesShared(string path) { using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { var index = 0; var fileLength = fs.Length; if (fileLength > int.MaxValue) throw new IOException("File too long"); var count = (int)fileLength; var bytes = new byte[count]; while (count > 0) { var n = fs.Read(bytes, index, count); if (n == 0) throw new InvalidOperationException("End of file reached before expected"); index += n; count -= n; } return bytes; } } public static bool IsZip(string fileName) { using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { var buffer = new byte[4]; var count = fs.Read(buffer, 0, buffer.Length); if (count != buffer.Length) return false; return buffer[0] == 0x50 // P && buffer[1] == 0x4B // K && buffer[2] == 0x03 // (ETX) && buffer[3] == 0x04; // (EOT) } } public static bool IsRar(string fileName) { using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { var buffer = new byte[4]; var count = fs.Read(buffer, 0, buffer.Length); if (count != buffer.Length) return false; return buffer[0] == 0x52 // R && buffer[1] == 0x61 // a && buffer[2] == 0x72 // r && buffer[3] == 0x21; // ! } } public static bool IsPng(string fileName) { using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { var buffer = new byte[8]; var count = fs.Read(buffer, 0, buffer.Length); if (count != buffer.Length) return false; return buffer[0] == 137 && buffer[1] == 80 && buffer[2] == 78 && buffer[3] == 71 && buffer[4] == 13 && buffer[5] == 10 && buffer[6] == 26 && buffer[7] == 10; } } public static bool IsSrr(string fileName) { using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { var buffer = new byte[3]; var count = fs.Read(buffer, 0, buffer.Length); if (count != buffer.Length) return false; return buffer[0] == 0x69 && buffer[1] == 0x69 && buffer[2] == 0x69; } } public static bool IsJpg(string fileName) { // jpeg header - always starts with FFD8 (Start Of Image marker) + FF + a uknown byte (most often E0 or E1 though) using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { var buffer = new byte[3]; var count = fs.Read(buffer, 0, buffer.Length); if (count != buffer.Length) return false; return buffer[0] == 0xFF && buffer[1] == 0xD8 && buffer[2] == 0xFF; } } public static bool IsTorrentFile(string fileName) { using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { var buffer = new byte[11]; fs.Read(buffer, 0, buffer.Length); return Encoding.ASCII.GetString(buffer, 0, buffer.Length) == "d8:announce"; } } public static bool IsBluRaySup(string fileName) { using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { var buffer = new byte[2]; fs.Read(buffer, 0, buffer.Length); return buffer[0] == 0x50 // P && buffer[1] == 0x47; // G } } public static bool IsTransportStream(string fileName) { using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { var buffer = new byte[3761]; var count = fs.Read(buffer, 0, buffer.Length); if (count != buffer.Length) return false; // allow for some random bytes in the beginning for (int i = 0; i < 255; i++) { if (buffer[i] == Packet.SynchronizationByte && buffer[i + 188] == Packet.SynchronizationByte && buffer[i + 188 * 2] == Packet.SynchronizationByte) { return true; } } return buffer[0] == 0x54 && buffer[1] == 0x46 && buffer[2] == 0x72 && buffer[3760] == Packet.SynchronizationByte; // Topfield REC TS file } } public static bool IsM2TransportStream(string fileName) { using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { var tsp = new TransportStreamParser(); tsp.DetectFormat(fs); return tsp.IsM2TransportStream; } } public static bool IsMpeg2PrivateStream2(string fileName) { using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { var buffer = new byte[4]; fs.Read(buffer, 0, buffer.Length); return VobSubParser.IsPrivateStream2(buffer, 0); } } public static bool IsVobSub(string fileName) { using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { var buffer = new byte[4]; fs.Read(buffer, 0, buffer.Length); return VobSubParser.IsMpeg2PackHeader(buffer) || VobSubParser.IsPrivateStream1(buffer, 0); } } public static bool IsSpDvdSup(string fileName) { using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { var buffer = new byte[SpHeader.SpHeaderLength]; if (fs.Read(buffer, 0, buffer.Length) != buffer.Length) { return false; } var header = new SpHeader(buffer); if (header.Identifier != "SP" || header.NextBlockPosition < 5) { return false; } buffer = new byte[header.NextBlockPosition]; if (fs.Read(buffer, 0, buffer.Length) != buffer.Length) { return false; } buffer = new byte[SpHeader.SpHeaderLength]; if (fs.Read(buffer, 0, buffer.Length) != buffer.Length) { return false; } header = new SpHeader(buffer); return header.Identifier == "SP"; } } /// /// Checks if file is an MXF file /// /// Input file /// true if file is an MXF file, otherwise false public static bool IsMaterialExchangeFormat(string fileName) { using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { var buffer = new byte[65536]; var count = fs.Read(buffer, 0, buffer.Length); if (count < 100) return false; for (int i = 0; i < count - 11; i++) { //Header Partition PackId = 06 0E 2B 34 02 05 01 01 0D 01 02 if (buffer[i + 00] == 0x06 && buffer[i + 01] == 0x0E && buffer[i + 02] == 0x2B && buffer[i + 03] == 0x34 && buffer[i + 04] == 0x02 && buffer[i + 05] == 0x05 && buffer[i + 06] == 0x01 && buffer[i + 07] == 0x01 && buffer[i + 08] == 0x0D && buffer[i + 09] == 0x01 && buffer[i + 10] == 0x02) { return true; } } } return false; } public static bool HasUtf8Bom(string fileName) { using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { var buffer = new byte[3]; fs.Read(buffer, 0, buffer.Length); return buffer[0] == 0xef && buffer[1] == 0xbb && buffer[2] == 0xbf; } } public static bool IsSubtitleFileAllBinaryZeroes(string fileName) { using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { if (fs.Length < 10) return false; // too short to be a proper subtitle file int numberOfBytes = 1; var buffer = new byte[1024]; while (numberOfBytes > 0) { numberOfBytes = fs.Read(buffer, 0, buffer.Length); for (int i = 0; i < numberOfBytes; i++) { if (buffer[i] > 0) { return false; } } } } return true; } public static bool IsFile(string path) { if (!Path.IsPathRooted(path)) return false; return ((File.GetAttributes(path) & FileAttributes.Directory) != FileAttributes.Directory); } public static bool IsDirectory(string path) { if (!Path.IsPathRooted(path)) return false; return ((File.GetAttributes(path) & FileAttributes.Directory) == FileAttributes.Directory); } public static bool IsPlainText(string fileName) { var fileInfo = new FileInfo(fileName); if (fileInfo.Length < 20) return false; // too short to be plain text if (fileInfo.Length > 5000000) return false; // too large to be plain text var enc = LanguageAutoDetect.GetEncodingFromFile(fileName); var s = File.ReadAllText(fileName, enc); int numberCount = 0; int letterCount = 0; int len = s.Length; for (int i = 0; i < len; i++) { char ch = s[i]; if (char.IsLetter(ch) || " -,.!?[]()\r\n".Contains(ch)) { letterCount++; } else if (char.IsControl(ch) && ch != '\t') // binary found { return false; } else if (CharUtils.IsDigit(ch)) { numberCount++; } } if (len < 100) { return numberCount < 5 && letterCount > 20; } var numberThreshold = len * 0.002 + 1; var letterThreshold = len * 0.8; return numberCount < numberThreshold && letterCount > letterThreshold; } } }