| 1 | using System; | 
 
 
 
 
 | 2 | using System.Collections.Generic; | 
 
 
 
 
 | 3 | using System.IO; | 
 
 
 
 
 | 4 | using System.Text; | 
 
 
 
 
 | 5 |  | 
 
 
 
 
 | 6 | namespace Oni | 
 
 
 
 
 | 7 | { | 
 
 
 
 
 | 8 | internal sealed class SubtitleImporter : Importer | 
 
 
 
 
 | 9 | { | 
 
 
 
 
 | 10 | #region Private data | 
 
 
 
 
 | 11 | private List<byte> subtitles; | 
 
 
 
 
 | 12 | private List<int> offsets; | 
 
 
 
 
 | 13 | #endregion | 
 
 
 
 
 | 14 |  | 
 
 
 
 
 | 15 | public override void Import(string filePath, string outputDirPath) | 
 
 
 
 
 | 16 | { | 
 
 
 
 
 | 17 | ReadTextFile(filePath); | 
 
 
 
 
 | 18 |  | 
 
 
 
 
 | 19 | string name = Path.GetFileNameWithoutExtension(filePath); | 
 
 
 
 
 | 20 |  | 
 
 
 
 
 | 21 | BeginImport(); | 
 
 
 
 
 | 22 | WriteSUBT(name, subtitles.ToArray()); | 
 
 
 
 
 | 23 | Write(outputDirPath); | 
 
 
 
 
 | 24 | } | 
 
 
 
 
 | 25 |  | 
 
 
 
 
 | 26 | private void ReadTextFile(string filePath) | 
 
 
 
 
 | 27 | { | 
 
 
 
 
 | 28 | subtitles = new List<byte>(); | 
 
 
 
 
 | 29 | offsets = new List<int>(); | 
 
 
 
 
 | 30 |  | 
 
 
 
 
 | 31 | var data = File.ReadAllBytes(filePath); | 
 
 
 
 
 | 32 | int i = SkipPreamble(data); | 
 
 
 
 
 | 33 |  | 
 
 
 
 
 | 34 | while (i < data.Length) | 
 
 
 
 
 | 35 | { | 
 
 
 
 
 | 36 | int nameStart = i; | 
 
 
 
 
 | 37 |  | 
 
 
 
 
 | 38 | while (!IsNewLine(data, i) && data[i] != '=') | 
 
 
 
 
 | 39 | i++; | 
 
 
 
 
 | 40 |  | 
 
 
 
 
 | 41 | int nameEnd = i; | 
 
 
 
 
 | 42 |  | 
 
 
 
 
 | 43 | if (IsNewLine(data, i)) | 
 
 
 
 
 | 44 | { | 
 
 
 
 
 | 45 | // | 
 
 
 
 
 | 46 | // This was an empty line or a line that does not contain a =. Skip it. | 
 
 
 
 
 | 47 | // | 
 
 
 
 
 | 48 |  | 
 
 
 
 
 | 49 | continue; | 
 
 
 
 
 | 50 | } | 
 
 
 
 
 | 51 |  | 
 
 
 
 
 | 52 | i++; | 
 
 
 
 
 | 53 |  | 
 
 
 
 
 | 54 | int textStart = i; | 
 
 
 
 
 | 55 |  | 
 
 
 
 
 | 56 | while (!IsNewLine(data, i)) | 
 
 
 
 
 | 57 | i++; | 
 
 
 
 
 | 58 |  | 
 
 
 
 
 | 59 | int textEnd = i; | 
 
 
 
 
 | 60 |  | 
 
 
 
 
 | 61 | if (nameEnd > nameStart) | 
 
 
 
 
 | 62 | { | 
 
 
 
 
 | 63 | offsets.Add(subtitles.Count); | 
 
 
 
 
 | 64 |  | 
 
 
 
 
 | 65 | for (int j = nameStart; j < nameEnd; j++) | 
 
 
 
 
 | 66 | subtitles.Add(data[j]); | 
 
 
 
 
 | 67 |  | 
 
 
 
 
 | 68 | subtitles.Add(0); | 
 
 
 
 
 | 69 |  | 
 
 
 
 
 | 70 | for (int j = textStart; j < textEnd; j++) | 
 
 
 
 
 | 71 | subtitles.Add(data[j]); | 
 
 
 
 
 | 72 |  | 
 
 
 
 
 | 73 | subtitles.Add(0); | 
 
 
 
 
 | 74 | } | 
 
 
 
 
 | 75 |  | 
 
 
 
 
 | 76 | i = SkipNewLine(data, i); | 
 
 
 
 
 | 77 | } | 
 
 
 
 
 | 78 | } | 
 
 
 
 
 | 79 |  | 
 
 
 
 
 | 80 | private static int SkipPreamble(byte[] data) | 
 
 
 
 
 | 81 | { | 
 
 
 
 
 | 82 | int offset = CheckPreamble(data, Encoding.UTF8.GetPreamble()); | 
 
 
 
 
 | 83 |  | 
 
 
 
 
 | 84 | if (offset > 0) | 
 
 
 
 
 | 85 | return offset; | 
 
 
 
 
 | 86 |  | 
 
 
 
 
 | 87 | if (CheckPreamble(data, Encoding.Unicode.GetPreamble()) != 0 | 
 
 
 
 
 | 88 | || CheckPreamble(data, Encoding.BigEndianUnicode.GetPreamble()) != 0 | 
 
 
 
 
 | 89 | || CheckPreamble(data, Encoding.UTF32.GetPreamble()) != 0) | 
 
 
 
 
 | 90 | { | 
 
 
 
 
 | 91 | throw new InvalidDataException("UTF16/32 input text files are not supported."); | 
 
 
 
 
 | 92 | } | 
 
 
 
 
 | 93 |  | 
 
 
 
 
 | 94 | if (data.Length >= 4) | 
 
 
 
 
 | 95 | { | 
 
 
 
 
 | 96 | if ((data[1] == 0 && data[3] == 0) | 
 
 
 
 
 | 97 | || (data[0] == 0 && data[2] == 0)) | 
 
 
 
 
 | 98 | { | 
 
 
 
 
 | 99 | throw new InvalidDataException("UTF16/32 input text files are not supported."); | 
 
 
 
 
 | 100 | } | 
 
 
 
 
 | 101 | } | 
 
 
 
 
 | 102 |  | 
 
 
 
 
 | 103 | return 0; | 
 
 
 
 
 | 104 | } | 
 
 
 
 
 | 105 |  | 
 
 
 
 
 | 106 | private static int CheckPreamble(byte[] data, byte[] preamble) | 
 
 
 
 
 | 107 | { | 
 
 
 
 
 | 108 | if (data.Length < preamble.Length) | 
 
 
 
 
 | 109 | return 0; | 
 
 
 
 
 | 110 |  | 
 
 
 
 
 | 111 | for (int i = 0; i < preamble.Length; i++) | 
 
 
 
 
 | 112 | { | 
 
 
 
 
 | 113 | if (data[i] != preamble[i]) | 
 
 
 
 
 | 114 | return 0; | 
 
 
 
 
 | 115 | } | 
 
 
 
 
 | 116 |  | 
 
 
 
 
 | 117 | return preamble.Length; | 
 
 
 
 
 | 118 | } | 
 
 
 
 
 | 119 |  | 
 
 
 
 
 | 120 | private static bool IsNewLine(byte[] data, int offset) | 
 
 
 
 
 | 121 | { | 
 
 
 
 
 | 122 | if (offset >= data.Length) | 
 
 
 
 
 | 123 | return true; | 
 
 
 
 
 | 124 |  | 
 
 
 
 
 | 125 | return (SkipNewLine(data, offset) > offset); | 
 
 
 
 
 | 126 | } | 
 
 
 
 
 | 127 |  | 
 
 
 
 
 | 128 | private static int SkipNewLine(byte[] data, int offset) | 
 
 
 
 
 | 129 | { | 
 
 
 
 
 | 130 | if (offset < data.Length) | 
 
 
 
 
 | 131 | { | 
 
 
 
 
 | 132 | if (data[offset] == '\n') | 
 
 
 
 
 | 133 | { | 
 
 
 
 
 | 134 | offset++; | 
 
 
 
 
 | 135 | } | 
 
 
 
 
 | 136 | else if (data[offset] == '\r') | 
 
 
 
 
 | 137 | { | 
 
 
 
 
 | 138 | offset++; | 
 
 
 
 
 | 139 |  | 
 
 
 
 
 | 140 | if (offset < data.Length && data[offset] == '\n') | 
 
 
 
 
 | 141 | offset++; | 
 
 
 
 
 | 142 | } | 
 
 
 
 
 | 143 | } | 
 
 
 
 
 | 144 |  | 
 
 
 
 
 | 145 | return offset; | 
 
 
 
 
 | 146 | } | 
 
 
 
 
 | 147 |  | 
 
 
 
 
 | 148 | private void WriteSUBT(string name, byte[] subtitles) | 
 
 
 
 
 | 149 | { | 
 
 
 
 
 | 150 | var subt = CreateInstance(TemplateTag.SUBT, name); | 
 
 
 
 
 | 151 |  | 
 
 
 
 
 | 152 | using (var writer = subt.OpenWrite(16)) | 
 
 
 
 
 | 153 | { | 
 
 
 
 
 | 154 | writer.Write(WriteRawPart(subtitles)); | 
 
 
 
 
 | 155 | writer.Write(offsets.Count); | 
 
 
 
 
 | 156 | writer.Write(offsets.ToArray()); | 
 
 
 
 
 | 157 | } | 
 
 
 
 
 | 158 | } | 
 
 
 
 
 | 159 | } | 
 
 
 
 
 | 160 | } |