mirror of
https://github.com/SubtitleEdit/subtitleedit.git
synced 2024-11-22 03:02:35 +01:00
libse - initial commit to separate UI and logic
This commit is contained in:
parent
15645f3bae
commit
1046ece216
@ -46,6 +46,10 @@ TITLE %BUILDTYPE%ing SubtitleEdit - Release^|Any CPU...
|
||||
/maxcpucount /consoleloggerparameters:DisableMPLogging;Summary;Verbosity=minimal
|
||||
IF %ERRORLEVEL% NEQ 0 GOTO EndWithError
|
||||
|
||||
ECHO.
|
||||
ECHO ILRepack...
|
||||
"packages\ILRepack.2.0.1\tools\ILRepack.exe" /out:"bin\Release\SubtitleEdit.exe" "bin\Release\SubtitleEdit.exe" "bin\Release\libse.dll" "packages\NHunspell.1.2.5554.16953\lib\net\NHunspell.dll" "packages\zlib.net.1.0.4.0\lib\zlib.net.dll" "DLLs\Interop.QuartzTypeLib.dll" /targetplatform:v4 /internalize /parallel
|
||||
ECHO.
|
||||
ECHO.
|
||||
POPD
|
||||
|
||||
|
470
libse/BluRaySup/BluRaySupPalette.cs
Normal file
470
libse/BluRaySup/BluRaySupPalette.cs
Normal file
@ -0,0 +1,470 @@
|
||||
/*
|
||||
* Copyright 2009 Volker Oth (0xdeadbeef)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* NOTE: Converted to C# and modified by Nikse.dk@gmail.com
|
||||
*/
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.BluRaySup
|
||||
{
|
||||
public class BluRaySupPalette
|
||||
{
|
||||
/** Number of palette entries */
|
||||
private int size;
|
||||
/** Byte buffer for RED info */
|
||||
private byte[] r;
|
||||
/** Byte buffer for GREEN info */
|
||||
private byte[] g;
|
||||
/** Byte buffer for BLUE info */
|
||||
private byte[] b;
|
||||
/** Byte buffer for alpha info */
|
||||
private byte[] a;
|
||||
/** Byte buffer for Y (luminance) info */
|
||||
private byte[] y;
|
||||
/** Byte buffer for Cb (chrominance blue) info */
|
||||
private byte[] cb;
|
||||
/** Byte buffer for Cr (chrominance red) info */
|
||||
private byte[] cr;
|
||||
/** Use BT.601 color model instead of BT.709 */
|
||||
private bool useBT601;
|
||||
|
||||
/**
|
||||
* Convert YCBCr color info to RGB
|
||||
* @param y 8 bit luminance
|
||||
* @param cb 8 bit chrominance blue
|
||||
* @param cr 8 bit chrominance red
|
||||
* @return Integer array with red, blue, green component (in this order)
|
||||
*/
|
||||
public static int[] YCbCr2Rgb(int y, int cb, int cr, bool useBt601)
|
||||
{
|
||||
int[] rgb = new int[3];
|
||||
double r, g, b;
|
||||
|
||||
y -= 16;
|
||||
cb -= 128;
|
||||
cr -= 128;
|
||||
|
||||
var y1 = y * 1.164383562;
|
||||
if (useBt601)
|
||||
{
|
||||
/* BT.601 for YCbCr 16..235 -> RGB 0..255 (PC) */
|
||||
r = y1 + cr * 1.596026317;
|
||||
g = y1 - cr * 0.8129674985 - cb * 0.3917615979;
|
||||
b = y1 + cb * 2.017232218;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* BT.709 for YCbCr 16..235 -> RGB 0..255 (PC) */
|
||||
r = y1 + cr * 1.792741071;
|
||||
g = y1 - cr * 0.5329093286 - cb * 0.2132486143;
|
||||
b = y1 + cb * 2.112401786;
|
||||
}
|
||||
rgb[0] = (int)(r + 0.5);
|
||||
rgb[1] = (int)(g + 0.5);
|
||||
rgb[2] = (int)(b + 0.5);
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (rgb[i] < 0)
|
||||
rgb[i] = 0;
|
||||
else if (rgb[i] > 255)
|
||||
rgb[i] = 255;
|
||||
}
|
||||
return rgb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert RGB color info to YCBCr
|
||||
* @param r 8 bit red component
|
||||
* @param g 8 bit green component
|
||||
* @param b 8 bit blue component
|
||||
* @return Integer array with luminance (Y), chrominance blue (Cb), chrominance red (Cr) (in this order)
|
||||
*/
|
||||
private static int[] Rgb2YCbCr(int r, int g, int b, bool useBt601)
|
||||
{
|
||||
int[] yCbCr = new int[3];
|
||||
double y, cb, cr;
|
||||
|
||||
if (useBt601)
|
||||
{
|
||||
/* BT.601 for RGB 0..255 (PC) -> YCbCr 16..235 */
|
||||
y = r * 0.299 * 219 / 255 + g * 0.587 * 219 / 255 + b * 0.114 * 219 / 255;
|
||||
cb = -r * 0.168736 * 224 / 255 - g * 0.331264 * 224 / 255 + b * 0.5 * 224 / 255;
|
||||
cr = r * 0.5 * 224 / 255 - g * 0.418688 * 224 / 255 - b * 0.081312 * 224 / 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* BT.709 for RGB 0..255 (PC) -> YCbCr 16..235 */
|
||||
y = r * 0.2126 * 219 / 255 + g * 0.7152 * 219 / 255 + b * 0.0722 * 219 / 255;
|
||||
cb = -r * 0.2126 / 1.8556 * 224 / 255 - g * 0.7152 / 1.8556 * 224 / 255 + b * 0.5 * 224 / 255;
|
||||
cr = r * 0.5 * 224 / 255 - g * 0.7152 / 1.5748 * 224 / 255 - b * 0.0722 / 1.5748 * 224 / 255;
|
||||
}
|
||||
yCbCr[0] = 16 + (int)(y + 0.5);
|
||||
yCbCr[1] = 128 + (int)(cb + 0.5);
|
||||
yCbCr[2] = 128 + (int)(cr + 0.5);
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (yCbCr[i] < 16)
|
||||
yCbCr[i] = 16;
|
||||
else
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
if (yCbCr[i] > 235)
|
||||
yCbCr[i] = 235;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (yCbCr[i] > 240)
|
||||
yCbCr[i] = 240;
|
||||
}
|
||||
}
|
||||
}
|
||||
return yCbCr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ctor - initializes palette with transparent black (RGBA: 0x00000000)
|
||||
* @param palSize Number of palette entries
|
||||
* @param use601 Use BT.601 instead of BT.709
|
||||
*/
|
||||
public BluRaySupPalette(int palSize, bool use601)
|
||||
{
|
||||
size = palSize;
|
||||
useBT601 = use601;
|
||||
r = new byte[size];
|
||||
g = new byte[size];
|
||||
b = new byte[size];
|
||||
a = new byte[size];
|
||||
y = new byte[size];
|
||||
cb = new byte[size];
|
||||
cr = new byte[size];
|
||||
|
||||
// set at least all alpha values to invisible
|
||||
int[] yCbCr = Rgb2YCbCr(0, 0, 0, useBT601);
|
||||
for (int i = 0; i < palSize; i++)
|
||||
{
|
||||
a[i] = 0;
|
||||
r[i] = 0;
|
||||
g[i] = 0;
|
||||
b[i] = 0;
|
||||
y[i] = (byte)yCbCr[0];
|
||||
cb[i] = (byte)yCbCr[1];
|
||||
cr[i] = (byte)yCbCr[2];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ctor - initializes palette with transparent black (RGBA: 0x00000000)
|
||||
* @param palSize Number of palette entries
|
||||
*/
|
||||
public BluRaySupPalette(int palSize)
|
||||
: this(palSize, false)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Ctor - construct palette from red, green blue and alpha buffers
|
||||
* @param red Byte buffer containing the red components
|
||||
* @param green Byte buffer containing the green components
|
||||
* @param blue Byte buffer containing the blue components
|
||||
* @param alpha Byte buffer containing the alpha components
|
||||
* @param use601 Use BT.601 instead of BT.709
|
||||
*/
|
||||
public BluRaySupPalette(byte[] red, byte[] green, byte[] blue, byte[] alpha, bool use601)
|
||||
{
|
||||
size = red.Length;
|
||||
useBT601 = use601;
|
||||
r = new byte[size];
|
||||
g = new byte[size];
|
||||
b = new byte[size];
|
||||
a = new byte[size];
|
||||
y = new byte[size];
|
||||
cb = new byte[size];
|
||||
cr = new byte[size];
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
a[i] = alpha[i];
|
||||
r[i] = red[i];
|
||||
g[i] = green[i];
|
||||
b[i] = blue[i];
|
||||
var yCbCr = Rgb2YCbCr(r[i] & 0xff, g[i] & 0xff, b[i] & 0xff, useBT601);
|
||||
y[i] = (byte)yCbCr[0];
|
||||
cb[i] = (byte)yCbCr[1];
|
||||
cr[i] = (byte)yCbCr[2];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ctor - construct palette from red, green blue and alpha buffers
|
||||
* @param red Byte buffer containing the red components
|
||||
* @param green Byte buffer containing the green components
|
||||
* @param blue Byte buffer containing the blue components
|
||||
* @param alpha Byte buffer containing the alpha components
|
||||
*/
|
||||
public BluRaySupPalette(byte[] red, byte[] green, byte[] blue, byte[] alpha)
|
||||
: this(red, green, blue, alpha, false)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Ctor - construct new (independent) palette from existing one
|
||||
* @param p Palette to copy values from
|
||||
*/
|
||||
public BluRaySupPalette(BluRaySupPalette p)
|
||||
{
|
||||
size = p.GetSize();
|
||||
useBT601 = p.UsesBt601();
|
||||
r = new byte[size];
|
||||
g = new byte[size];
|
||||
b = new byte[size];
|
||||
a = new byte[size];
|
||||
y = new byte[size];
|
||||
cb = new byte[size];
|
||||
cr = new byte[size];
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
a[i] = p.a[i];
|
||||
r[i] = p.r[i];
|
||||
g[i] = p.g[i];
|
||||
b[i] = p.b[i];
|
||||
y[i] = p.y[i];
|
||||
cb[i] = p.cb[i];
|
||||
cr[i] = p.cr[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set palette index "index" to color "c" in ARGB format
|
||||
* @param index Palette index
|
||||
* @param c Color in ARGB format
|
||||
*/
|
||||
public void SetArgb(int index, int c)
|
||||
{
|
||||
int a1 = (c >> 24) & 0xff;
|
||||
int r1 = (c >> 16) & 0xff;
|
||||
int g1 = (c >> 8) & 0xff;
|
||||
int b1 = c & 0xff;
|
||||
SetRgb(index, r1, g1, b1);
|
||||
SetAlpha(index, a1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return palette entry at index as Integer in ARGB format
|
||||
* @param index Palette index
|
||||
* @return Palette entry at index as Integer in ARGB format
|
||||
*/
|
||||
public int GetArgb(int index)
|
||||
{
|
||||
return ((a[index] & 0xff) << 24) | ((r[index] & 0xff) << 16) | ((g[index] & 0xff) << 8) | (b[index] & 0xff);
|
||||
}
|
||||
|
||||
internal void SetColor(int index, System.Drawing.Color color)
|
||||
{
|
||||
SetRgb(index, color.R, color.G, color.B);
|
||||
SetAlpha(index, color.A);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set palette entry (RGB mode)
|
||||
* @param index Palette index
|
||||
* @param red 8bit red component
|
||||
* @param green 8bit green component
|
||||
* @param blue 8bit blue component
|
||||
*/
|
||||
public void SetRgb(int index, int red, int green, int blue)
|
||||
{
|
||||
r[index] = (byte)red;
|
||||
g[index] = (byte)green;
|
||||
b[index] = (byte)blue;
|
||||
// create yCbCr
|
||||
int[] yCbCr = Rgb2YCbCr(red, green, blue, useBT601);
|
||||
y[index] = (byte)yCbCr[0];
|
||||
cb[index] = (byte)yCbCr[1];
|
||||
cr[index] = (byte)yCbCr[2];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set palette entry (YCbCr mode)
|
||||
* @param index Palette index
|
||||
* @param yn 8bit Y component
|
||||
* @param cbn 8bit Cb component
|
||||
* @param crn 8bit Cr component
|
||||
*/
|
||||
public void SetYCbCr(int index, int yn, int cbn, int crn)
|
||||
{
|
||||
y[index] = (byte)yn;
|
||||
cb[index] = (byte)cbn;
|
||||
cr[index] = (byte)crn;
|
||||
// create RGB
|
||||
int[] rgb = YCbCr2Rgb(yn, cbn, crn, useBT601);
|
||||
r[index] = (byte)rgb[0];
|
||||
g[index] = (byte)rgb[1];
|
||||
b[index] = (byte)rgb[2];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set alpha channel
|
||||
* @param index Palette index
|
||||
* @param alpha 8bit alpha channel value
|
||||
*/
|
||||
public void SetAlpha(int index, int alpha)
|
||||
{
|
||||
a[index] = (byte)alpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get alpha channel
|
||||
* @param index Palette index
|
||||
* @return 8bit alpha channel value
|
||||
*/
|
||||
public int GetAlpha(int index)
|
||||
{
|
||||
return a[index] & 0xff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return byte array of alpha channel components
|
||||
* @return Byte array of alpha channel components (don't modify!)
|
||||
*/
|
||||
public byte[] GetAlpha()
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Integer array containing 8bit red, green, blue components (in this order)
|
||||
* @param index Palette index
|
||||
* @return Integer array containing 8bit red, green, blue components (in this order)
|
||||
*/
|
||||
public int[] GetRgb(int index)
|
||||
{
|
||||
int[] rgb = new int[3];
|
||||
rgb[0] = r[index] & 0xff;
|
||||
rgb[1] = g[index] & 0xff;
|
||||
rgb[2] = b[index] & 0xff;
|
||||
return rgb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Integer array containing 8bit Y, Cb, Cr components (in this order)
|
||||
* @param index Palette index
|
||||
* @return Integer array containing 8bit Y, Cb, Cr components (in this order)
|
||||
*/
|
||||
public int[] GetYCbCr(int index)
|
||||
{
|
||||
int[] yCbCr = new int[3];
|
||||
yCbCr[0] = y[index] & 0xff;
|
||||
yCbCr[1] = cb[index] & 0xff;
|
||||
yCbCr[2] = cr[index] & 0xff;
|
||||
return yCbCr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return byte array of red components
|
||||
* @return Byte array of red components (don't modify!)
|
||||
*/
|
||||
public byte[] GetR()
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return byte array of green components
|
||||
* @return Byte array of green components (don't modify!)
|
||||
*/
|
||||
public byte[] GetG()
|
||||
{
|
||||
return g;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return byte array of blue components
|
||||
* @return Byte array of blue components (don't modify!)
|
||||
*/
|
||||
public byte[] GetB()
|
||||
{
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return byte array of Y components
|
||||
* @return Byte array of Y components (don't modify!)
|
||||
*/
|
||||
public byte[] GetY()
|
||||
{
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return byte array of Cb components
|
||||
* @return Byte array of Cb components (don't modify!)
|
||||
*/
|
||||
public byte[] GetCb()
|
||||
{
|
||||
return cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return byte array of Cr components
|
||||
* @return Byte array of Cr components (don't modify!)
|
||||
*/
|
||||
public byte[] GetCr()
|
||||
{
|
||||
return cr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get size of palette (number of entries)
|
||||
* @return Size of palette (number of entries)
|
||||
*/
|
||||
public int GetSize()
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return index of most transparent palette entry or the index of the first completely transparent color
|
||||
* @return Index of most transparent palette entry or the index of the first completely transparent color
|
||||
*/
|
||||
public int GetTransparentIndex()
|
||||
{
|
||||
// find (most) transparent index in palette
|
||||
int transpIdx = 0;
|
||||
int minAlpha = 0x100;
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
if ((a[i] & 0xff) < minAlpha)
|
||||
{
|
||||
minAlpha = a[i] & 0xff;
|
||||
transpIdx = i;
|
||||
if (minAlpha == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return transpIdx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get: use of BT.601 color model instead of BT.709
|
||||
* @return True if BT.601 is used
|
||||
*/
|
||||
public bool UsesBt601()
|
||||
{
|
||||
return useBT601;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
810
libse/BluRaySup/BluRaySupParser.cs
Normal file
810
libse/BluRaySup/BluRaySupParser.cs
Normal file
@ -0,0 +1,810 @@
|
||||
/*
|
||||
* Copyright 2009 Volker Oth (0xdeadbeef)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* NOTE: Converted to C# and modified by Nikse.dk@gmail.com
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.BluRaySup
|
||||
{
|
||||
public static class BluRaySupParser
|
||||
{
|
||||
private class SupSegment
|
||||
{
|
||||
/// <summary>
|
||||
/// Type of segment
|
||||
/// </summary>
|
||||
public int Type;
|
||||
|
||||
/// <summary>
|
||||
/// segment size in bytes
|
||||
/// </summary>
|
||||
public int Size;
|
||||
|
||||
/// <summary>
|
||||
/// segment PTS time stamp
|
||||
/// </summary>
|
||||
public long PtsTimestamp;
|
||||
|
||||
/// <summary>
|
||||
/// segment DTS time stamp
|
||||
/// </summary>
|
||||
public long DtsTimestamp;
|
||||
}
|
||||
|
||||
public class PcsObject
|
||||
{
|
||||
public int ObjectId;
|
||||
public int WindowId;
|
||||
public bool IsForced;
|
||||
public Point Origin;
|
||||
}
|
||||
|
||||
public static class SupDecoder
|
||||
{
|
||||
private const int AlphaCrop = 14;
|
||||
|
||||
public static BluRaySupPalette DecodePalette(IList<PaletteInfo> paletteInfos)
|
||||
{
|
||||
BluRaySupPalette palette = new BluRaySupPalette(256);
|
||||
// by definition, index 0xff is always completely transparent
|
||||
// also all entries must be fully transparent after initialization
|
||||
|
||||
bool fadeOut = false;
|
||||
for (int j = 0; j < paletteInfos.Count; j++)
|
||||
{
|
||||
PaletteInfo p = paletteInfos[j];
|
||||
int index = 0;
|
||||
|
||||
for (int i = 0; i < p.PaletteSize; i++)
|
||||
{
|
||||
// each palette entry consists of 5 bytes
|
||||
int palIndex = p.PaletteBuffer[index];
|
||||
int y = p.PaletteBuffer[++index];
|
||||
int cr = p.PaletteBuffer[++index];
|
||||
int cb = p.PaletteBuffer[++index];
|
||||
int alpha = p.PaletteBuffer[++index];
|
||||
|
||||
int alphaOld = palette.GetAlpha(palIndex);
|
||||
// avoid fading out
|
||||
if (alpha >= alphaOld)
|
||||
{
|
||||
if (alpha < AlphaCrop)
|
||||
{// to not mess with scaling algorithms, make transparent color black
|
||||
y = 16;
|
||||
cr = 128;
|
||||
cb = 128;
|
||||
}
|
||||
palette.SetAlpha(palIndex, alpha);
|
||||
}
|
||||
else
|
||||
{
|
||||
fadeOut = true;
|
||||
}
|
||||
|
||||
palette.SetYCbCr(palIndex, y, cb, cr);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
if (fadeOut)
|
||||
{
|
||||
System.Diagnostics.Debug.Print("fade out detected -> patched palette\n");
|
||||
}
|
||||
return palette;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decode caption from the input stream
|
||||
/// </summary>
|
||||
/// <returns>bitmap of the decoded caption</returns>
|
||||
public static Bitmap DecodeImage(PcsObject pcs, IList<OdsData> data, List<PaletteInfo> palettes)
|
||||
{
|
||||
long ticks = DateTime.Now.Ticks;
|
||||
|
||||
if (pcs == null || data == null || data.Count == 0)
|
||||
return new Bitmap(1, 1);
|
||||
|
||||
int w = data[0].Size.Width;
|
||||
int h = data[0].Size.Height;
|
||||
|
||||
var bm = new FastBitmap(new Bitmap(w, h));
|
||||
bm.LockImage();
|
||||
BluRaySupPalette pal = DecodePalette(palettes);
|
||||
|
||||
int index = 0;
|
||||
int ofs = 0;
|
||||
int xpos = 0;
|
||||
|
||||
byte[] buf = data[0].Fragment.ImageBuffer;
|
||||
index = 0;
|
||||
do
|
||||
{
|
||||
int b = buf[index++] & 0xff;
|
||||
if (b == 0 && index < buf.Length)
|
||||
{
|
||||
b = buf[index++] & 0xff;
|
||||
if (b == 0)
|
||||
{
|
||||
// next line
|
||||
ofs = (ofs / w) * w;
|
||||
if (xpos < w)
|
||||
ofs += w;
|
||||
xpos = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int size;
|
||||
if ((b & 0xC0) == 0x40)
|
||||
{
|
||||
if (index < buf.Length)
|
||||
{
|
||||
// 00 4x xx -> xxx zeroes
|
||||
size = ((b - 0x40) << 8) + (buf[index++] & 0xff);
|
||||
Color c = Color.FromArgb(pal.GetArgb(0));
|
||||
for (int i = 0; i < size; i++)
|
||||
PutPixel(bm, ofs++, c);
|
||||
xpos += size;
|
||||
}
|
||||
}
|
||||
else if ((b & 0xC0) == 0x80)
|
||||
{
|
||||
if (index < buf.Length)
|
||||
{
|
||||
// 00 8x yy -> x times value y
|
||||
size = (b - 0x80);
|
||||
b = buf[index++] & 0xff;
|
||||
Color c = Color.FromArgb(pal.GetArgb(b));
|
||||
for (int i = 0; i < size; i++)
|
||||
PutPixel(bm, ofs++, c);
|
||||
xpos += size;
|
||||
}
|
||||
}
|
||||
else if ((b & 0xC0) != 0)
|
||||
{
|
||||
if (index < buf.Length)
|
||||
{
|
||||
// 00 cx yy zz -> xyy times value z
|
||||
size = ((b - 0xC0) << 8) + (buf[index++] & 0xff);
|
||||
b = buf[index++] & 0xff;
|
||||
Color c = Color.FromArgb(pal.GetArgb(b));
|
||||
for (int i = 0; i < size; i++)
|
||||
PutPixel(bm, ofs++, c);
|
||||
xpos += size;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 00 xx -> xx times 0
|
||||
Color c = Color.FromArgb(pal.GetArgb(0));
|
||||
for (int i = 0; i < b; i++)
|
||||
PutPixel(bm, ofs++, c);
|
||||
xpos += b;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PutPixel(bm, ofs++, b, pal);
|
||||
xpos++;
|
||||
}
|
||||
} while (index < buf.Length);
|
||||
|
||||
bm.UnlockImage();
|
||||
return bm.GetBitmap();
|
||||
}
|
||||
|
||||
private static void PutPixel(FastBitmap bmp, int index, int color, BluRaySupPalette palette)
|
||||
{
|
||||
int x = index % bmp.Width;
|
||||
int y = index / bmp.Width;
|
||||
if (x < bmp.Width && y < bmp.Height)
|
||||
bmp.SetPixel(x, y, Color.FromArgb(palette.GetArgb(color)));
|
||||
}
|
||||
|
||||
private static void PutPixel(FastBitmap bmp, int index, Color color)
|
||||
{
|
||||
if (color.A > 0)
|
||||
{
|
||||
int x = index % bmp.Width;
|
||||
int y = index / bmp.Width;
|
||||
if (x < bmp.Width && y < bmp.Height)
|
||||
bmp.SetPixel(x, y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class PcsData
|
||||
{
|
||||
public int CompNum;
|
||||
public CompositionState CompositionState;
|
||||
public bool PaletteUpdate;
|
||||
public long StartTime; // Pts
|
||||
public long EndTime; // end Pts
|
||||
public Size Size;
|
||||
public int FramesPerSecondType;
|
||||
public int PaletteId;
|
||||
public List<PcsObject> PcsObjects;
|
||||
public string Message;
|
||||
public List<List<OdsData>> BitmapObjects;
|
||||
public List<PaletteInfo> PaletteInfos;
|
||||
|
||||
/// <summary>
|
||||
/// if true, contains forced entry
|
||||
/// </summary>
|
||||
public bool IsForced
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (PcsObject obj in PcsObjects)
|
||||
{
|
||||
if (obj.IsForced)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public Bitmap GetBitmap()
|
||||
{
|
||||
if (PcsObjects.Count == 1)
|
||||
return SupDecoder.DecodeImage(PcsObjects[0], BitmapObjects[0], PaletteInfos);
|
||||
|
||||
var r = Rectangle.Empty;
|
||||
for (int ioIndex = 0; ioIndex < PcsObjects.Count; ioIndex++)
|
||||
{
|
||||
var ioRect = new Rectangle(PcsObjects[ioIndex].Origin, BitmapObjects[ioIndex][0].Size);
|
||||
if (r.IsEmpty)
|
||||
r = ioRect;
|
||||
else
|
||||
r = Rectangle.Union(r, ioRect);
|
||||
}
|
||||
var mergedBmp = new Bitmap(r.Width, r.Height, PixelFormat.Format32bppArgb);
|
||||
for (var ioIndex = 0; ioIndex < PcsObjects.Count; ioIndex++)
|
||||
{
|
||||
var offset = PcsObjects[ioIndex].Origin - new Size(r.Location);
|
||||
using (var singleBmp = SupDecoder.DecodeImage(PcsObjects[ioIndex], BitmapObjects[ioIndex], PaletteInfos))
|
||||
using (var gSideBySide = Graphics.FromImage(mergedBmp))
|
||||
{
|
||||
gSideBySide.DrawImage(singleBmp, offset.X, offset.Y);
|
||||
}
|
||||
}
|
||||
return mergedBmp;
|
||||
}
|
||||
}
|
||||
|
||||
public class PdsData
|
||||
{
|
||||
public string Message;
|
||||
public int PaletteId;
|
||||
public int PaletteVersion;
|
||||
public PaletteInfo PaletteInfo;
|
||||
}
|
||||
|
||||
public class OdsData
|
||||
{
|
||||
public int ObjectId;
|
||||
public int ObjectVersion;
|
||||
public string Message;
|
||||
public bool IsFirst;
|
||||
public Size Size;
|
||||
public ImageObjectFragment Fragment;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PGS composition state
|
||||
/// </summary>
|
||||
public enum CompositionState
|
||||
{
|
||||
/// <summary>
|
||||
/// Normal: doesn't have to be complete
|
||||
/// </summary>
|
||||
Normal,
|
||||
|
||||
/// <summary>
|
||||
/// Acquisition point
|
||||
/// </summary>
|
||||
AcquPoint,
|
||||
|
||||
/// <summary>
|
||||
/// Epoch start - clears the screen
|
||||
/// </summary>
|
||||
EpochStart,
|
||||
|
||||
/// <summary>
|
||||
/// Epoch continue
|
||||
/// </summary>
|
||||
EpochContinue,
|
||||
|
||||
/// <summary>
|
||||
/// Unknown value
|
||||
/// </summary>
|
||||
Invalid,
|
||||
}
|
||||
|
||||
private const int HeaderSize = 13;
|
||||
|
||||
/// <summary>
|
||||
/// Parses a Blu-ray sup file
|
||||
/// </summary>
|
||||
/// <param name="fileName">BluRay sup file name</param>
|
||||
/// <param name="log">Parsing info is logged here</param>
|
||||
/// <returns>List of BluRaySupPictures</returns>
|
||||
public static List<PcsData> ParseBluRaySup(string fileName, StringBuilder log)
|
||||
{
|
||||
using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
{
|
||||
return ParseBluRaySup(fs, log, false);
|
||||
}
|
||||
}
|
||||
|
||||
private static SupSegment ParseSegmentHeader(byte[] buffer, StringBuilder log)
|
||||
{
|
||||
var segment = new SupSegment();
|
||||
if (buffer[0] == 0x50 && buffer[1] == 0x47) // 80 + 71 - P G
|
||||
{
|
||||
segment.PtsTimestamp = BigEndianInt32(buffer, 2); // read PTS
|
||||
segment.DtsTimestamp = BigEndianInt32(buffer, 6); // read PTS
|
||||
segment.Type = buffer[10];
|
||||
segment.Size = BigEndianInt16(buffer, 11);
|
||||
}
|
||||
else
|
||||
{
|
||||
log.AppendLine("Unable to read segment - PG missing!");
|
||||
}
|
||||
return segment;
|
||||
}
|
||||
|
||||
private static SupSegment ParseSegmentHeaderFromMatroska(byte[] buffer)
|
||||
{
|
||||
var segment = new SupSegment();
|
||||
segment.Type = buffer[0];
|
||||
segment.Size = BigEndianInt16(buffer, 1);
|
||||
return segment;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse an PCS packet which contains width/height info
|
||||
/// </summary>
|
||||
/// <param name="buffer">Raw data buffer, starting right after segment</param>
|
||||
private static PcsObject ParsePcs(byte[] buffer, int offset)
|
||||
{
|
||||
var pcs = new PcsObject();
|
||||
// composition_object:
|
||||
pcs.ObjectId = BigEndianInt16(buffer, 11 + offset); // 16bit object_id_ref
|
||||
pcs.WindowId = buffer[13 + offset];
|
||||
// skipped: 8bit window_id_ref
|
||||
// object_cropped_flag: 0x80, forced_on_flag = 0x040, 6bit reserved
|
||||
int forcedCropped = buffer[14 + offset];
|
||||
pcs.IsForced = ((forcedCropped & 0x40) == 0x40);
|
||||
pcs.Origin = new Point(BigEndianInt16(buffer, 15 + offset), BigEndianInt16(buffer, 17 + offset));
|
||||
return pcs;
|
||||
}
|
||||
|
||||
private static PcsData ParsePicture(byte[] buffer, SupSegment segment)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var pcs = new PcsData();
|
||||
pcs.Size = new Size(BigEndianInt16(buffer, 0), BigEndianInt16(buffer, 2));
|
||||
pcs.FramesPerSecondType = buffer[4]; // hi nibble: frame_rate, lo nibble: reserved
|
||||
pcs.CompNum = BigEndianInt16(buffer, 5);
|
||||
pcs.CompositionState = GetCompositionState(buffer[7]);
|
||||
pcs.StartTime = segment.PtsTimestamp;
|
||||
// 8bit palette_update_flag (0x80), 7bit reserved
|
||||
pcs.PaletteUpdate = (buffer[8] == 0x80);
|
||||
pcs.PaletteId = buffer[9]; // 8bit palette_id_ref
|
||||
int compositionObjectCount = buffer[10]; // 8bit number_of_composition_objects (0..2)
|
||||
|
||||
sb.AppendFormat("CompNum: {0}, Pts: {1}, State: {2}, PalUpdate: {3}, PalId {4}", pcs.CompNum, ToolBox.PtsToTimeString(pcs.StartTime), pcs.CompositionState, pcs.PaletteUpdate, pcs.PaletteId);
|
||||
|
||||
if (pcs.CompositionState == CompositionState.Invalid)
|
||||
{
|
||||
sb.Append("Illegal composition state Invalid");
|
||||
}
|
||||
else
|
||||
{
|
||||
int offset = 0;
|
||||
pcs.PcsObjects = new List<PcsObject>();
|
||||
for (int compObjIndex = 0; compObjIndex < compositionObjectCount; compObjIndex++)
|
||||
{
|
||||
PcsObject pcsObj = ParsePcs(buffer, offset);
|
||||
pcs.PcsObjects.Add(pcsObj);
|
||||
sb.AppendLine();
|
||||
sb.AppendFormat("ObjId: {0}, WinId: {1}, Forced: {2}, X: {3}, Y: {4}",
|
||||
pcsObj.ObjectId, pcsObj.WindowId, pcsObj.IsForced, pcsObj.Origin.X, pcsObj.Origin.Y);
|
||||
offset += 8;
|
||||
}
|
||||
}
|
||||
pcs.Message = sb.ToString();
|
||||
return pcs;
|
||||
}
|
||||
|
||||
private static bool CompletePcs(PcsData pcs, Dictionary<int, List<OdsData>> bitmapObjects, Dictionary<int, List<PaletteInfo>> palettes)
|
||||
{
|
||||
if (pcs == null || pcs.PcsObjects == null || palettes == null)
|
||||
return false;
|
||||
|
||||
if (pcs.PcsObjects.Count == 0)
|
||||
return true;
|
||||
|
||||
if (!palettes.ContainsKey(pcs.PaletteId))
|
||||
return false;
|
||||
|
||||
pcs.PaletteInfos = new List<PaletteInfo>(palettes[pcs.PaletteId]);
|
||||
pcs.BitmapObjects = new List<List<OdsData>>();
|
||||
for (int index = 0; index < pcs.PcsObjects.Count; index++)
|
||||
{
|
||||
int objId = pcs.PcsObjects[index].ObjectId;
|
||||
if (!bitmapObjects.ContainsKey(objId))
|
||||
return false;
|
||||
pcs.BitmapObjects.Add(bitmapObjects[objId]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// parse an PDS packet which contain palette info
|
||||
/// </summary>
|
||||
/// <param name="buffer">Buffer of raw byte data, starting right after segment</param>
|
||||
/// <param name="segment">object containing info about the current segment</param>
|
||||
/// <returns>number of valid palette entries (-1 for fault)</returns>
|
||||
private static PdsData ParsePds(byte[] buffer, SupSegment segment)
|
||||
{
|
||||
int paletteId = buffer[0]; // 8bit palette ID (0..7)
|
||||
// 8bit palette version number (incremented for each palette change)
|
||||
int paletteUpdate = buffer[1];
|
||||
|
||||
var p = new PaletteInfo();
|
||||
p.PaletteSize = (segment.Size - 2) / 5;
|
||||
|
||||
if (p.PaletteSize <= 0)
|
||||
return new PdsData { Message = "Empty palette" };
|
||||
|
||||
p.PaletteBuffer = new byte[p.PaletteSize * 5];
|
||||
Buffer.BlockCopy(buffer, 2, p.PaletteBuffer, 0, p.PaletteSize * 5); // save palette buffer in palette object
|
||||
|
||||
return new PdsData
|
||||
{
|
||||
Message = "PalId: " + paletteId + ", update: " + paletteUpdate + ", " + p.PaletteSize + " entries",
|
||||
PaletteId = paletteId,
|
||||
PaletteVersion = paletteUpdate,
|
||||
PaletteInfo = p,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// parse an ODS packet which contain the image data
|
||||
/// </summary>
|
||||
/// <param name="buffer">raw byte date, starting right after segment</param>
|
||||
/// <param name="segment">object containing info about the current segment</param>
|
||||
/// <returns>true if this is a valid new object (neither invalid nor a fragment)</returns>
|
||||
private static OdsData ParseOds(byte[] buffer, SupSegment segment, bool forceFirst)
|
||||
{
|
||||
int objId = BigEndianInt16(buffer, 0); // 16bit object_id
|
||||
int objVer = buffer[2]; // 16bit object_id nikse - index 2 or 1???
|
||||
int objSeq = buffer[3]; // 8bit first_in_sequence (0x80),
|
||||
// last_in_sequence (0x40), 6bits reserved
|
||||
bool first = ((objSeq & 0x80) == 0x80) || forceFirst;
|
||||
bool last = (objSeq & 0x40) == 0x40;
|
||||
|
||||
var info = new ImageObjectFragment();
|
||||
if (first)
|
||||
{
|
||||
int width = BigEndianInt16(buffer, 7); // object_width
|
||||
int height = BigEndianInt16(buffer, 9); // object_height
|
||||
|
||||
info.ImagePacketSize = segment.Size - 11; // Image packet size (image bytes)
|
||||
info.ImageBuffer = new byte[info.ImagePacketSize];
|
||||
Buffer.BlockCopy(buffer, 11, info.ImageBuffer, 0, info.ImagePacketSize);
|
||||
|
||||
return new OdsData
|
||||
{
|
||||
IsFirst = true,
|
||||
Size = new Size(width, height),
|
||||
ObjectId = objId,
|
||||
ObjectVersion = objVer,
|
||||
Fragment = info,
|
||||
Message = "ObjId: " + objId + ", ver: " + objVer + ", seq: first" + (last ? "/" : "") + (last ? "" + "last" : "") + ", width: " + width + ", height: " + height,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
info.ImagePacketSize = segment.Size - 4;
|
||||
info.ImageBuffer = new byte[info.ImagePacketSize];
|
||||
Buffer.BlockCopy(buffer, 4, info.ImageBuffer, 0, info.ImagePacketSize);
|
||||
|
||||
return new OdsData
|
||||
{
|
||||
IsFirst = false,
|
||||
ObjectId = objId,
|
||||
ObjectVersion = objVer,
|
||||
Fragment = info,
|
||||
Message = "Continued ObjId: " + objId + ", ver: " + objVer + ", seq: " + (last ? "" + "last" : ""),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static List<PcsData> ParseBluRaySup(Stream ms, StringBuilder log, bool fromMatroskaFile)
|
||||
{
|
||||
long position = ms.Position;
|
||||
int segmentCount = 0;
|
||||
var palettes = new Dictionary<int, List<PaletteInfo>>();
|
||||
bool forceFirstOds = true;
|
||||
var bitmapObjects = new Dictionary<int, List<OdsData>>();
|
||||
PcsData latestPcs = null;
|
||||
int latestCompNum = -1;
|
||||
var pcsList = new List<PcsData>();
|
||||
byte[] headerBuffer;
|
||||
if (fromMatroskaFile)
|
||||
headerBuffer = new byte[3];
|
||||
else
|
||||
headerBuffer = new byte[HeaderSize];
|
||||
|
||||
while (position < ms.Length)
|
||||
{
|
||||
ms.Seek(position, SeekOrigin.Begin);
|
||||
|
||||
// Read segment header
|
||||
ms.Read(headerBuffer, 0, headerBuffer.Length);
|
||||
SupSegment segment;
|
||||
if (fromMatroskaFile)
|
||||
segment = ParseSegmentHeaderFromMatroska(headerBuffer);
|
||||
else
|
||||
segment = ParseSegmentHeader(headerBuffer, log);
|
||||
position += headerBuffer.Length;
|
||||
|
||||
// Read segment data
|
||||
var buffer = new byte[segment.Size];
|
||||
ms.Read(buffer, 0, buffer.Length);
|
||||
log.Append(segmentCount + ": ");
|
||||
|
||||
switch (segment.Type)
|
||||
{
|
||||
case 0x14: // Palette
|
||||
if (latestPcs != null)
|
||||
{
|
||||
log.AppendLine(string.Format("0x14 - Palette - PDS offset={0} size={1}", position, segment.Size));
|
||||
PdsData pds = ParsePds(buffer, segment);
|
||||
log.AppendLine(pds.Message);
|
||||
if (pds.PaletteInfo != null)
|
||||
{
|
||||
if (!palettes.ContainsKey(pds.PaletteId))
|
||||
{
|
||||
palettes[pds.PaletteId] = new List<PaletteInfo>();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (latestPcs.PaletteUpdate)
|
||||
{
|
||||
palettes[pds.PaletteId].RemoveAt(palettes[pds.PaletteId].Count - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
log.AppendLine("Extra Palette");
|
||||
}
|
||||
}
|
||||
palettes[pds.PaletteId].Add(pds.PaletteInfo);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x15: // Image bitmap data
|
||||
if (latestPcs != null)
|
||||
{
|
||||
log.AppendLine(string.Format("0x15 - Bitmap data - ODS offset={0} size={1}", position, segment.Size));
|
||||
OdsData ods = ParseOds(buffer, segment, forceFirstOds);
|
||||
log.AppendLine(ods.Message);
|
||||
if (!latestPcs.PaletteUpdate)
|
||||
{
|
||||
List<OdsData> odsList;
|
||||
if (ods.IsFirst)
|
||||
{
|
||||
odsList = new List<OdsData>();
|
||||
odsList.Add(ods);
|
||||
bitmapObjects[ods.ObjectId] = odsList;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bitmapObjects.TryGetValue(ods.ObjectId, out odsList))
|
||||
{
|
||||
odsList.Add(ods);
|
||||
}
|
||||
else
|
||||
{
|
||||
log.AppendLine(string.Format("INVALID ObjectId {0} in ODS, offset={1}", ods.ObjectId, position));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log.AppendLine(string.Format("Bitmap Data Ignore due to PaletteUpdate offset={0}", position));
|
||||
}
|
||||
forceFirstOds = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x16: // Picture time codes
|
||||
if (latestPcs != null)
|
||||
{
|
||||
if (CompletePcs(latestPcs, bitmapObjects, palettes))
|
||||
{
|
||||
pcsList.Add(latestPcs);
|
||||
}
|
||||
latestPcs = null;
|
||||
}
|
||||
|
||||
log.AppendLine(string.Format("0x16 - Picture codes, offset={0} size={1}", position, segment.Size));
|
||||
forceFirstOds = true;
|
||||
PcsData nextPcs = ParsePicture(buffer, segment);
|
||||
log.AppendLine(nextPcs.Message);
|
||||
latestPcs = nextPcs;
|
||||
latestCompNum = nextPcs.CompNum;
|
||||
if (latestPcs.CompositionState == CompositionState.EpochStart)
|
||||
{
|
||||
bitmapObjects.Clear();
|
||||
palettes.Clear();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x17: // Window display
|
||||
if (latestPcs != null)
|
||||
{
|
||||
log.AppendLine(string.Format("0x17 - Window display offset={0} size={1}", position, segment.Size));
|
||||
int windowCount = buffer[0];
|
||||
int offset = 0;
|
||||
for (int nextWindow = 0; nextWindow < windowCount; nextWindow++)
|
||||
{
|
||||
int windowId = buffer[1 + offset];
|
||||
int x = BigEndianInt16(buffer, 2 + offset);
|
||||
int y = BigEndianInt16(buffer, 4 + offset);
|
||||
int width = BigEndianInt16(buffer, 6 + offset);
|
||||
int height = BigEndianInt16(buffer, 8 + offset);
|
||||
log.AppendLine(string.Format("WinId: {4}, X: {0}, Y: {1}, Width: {2}, Height: {3}",
|
||||
x, y, width, height, windowId));
|
||||
offset += 9;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x80:
|
||||
forceFirstOds = true;
|
||||
log.AppendLine(string.Format("0x80 - END offset={0} size={1}", position, segment.Size));
|
||||
if (latestPcs != null)
|
||||
{
|
||||
if (CompletePcs(latestPcs, bitmapObjects, palettes))
|
||||
{
|
||||
pcsList.Add(latestPcs);
|
||||
}
|
||||
latestPcs = null;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
log.AppendLine(string.Format("0x?? - END offset={0} UNKOWN SEGMENT TYPE={1}", position, segment.Type));
|
||||
break;
|
||||
}
|
||||
position += segment.Size;
|
||||
segmentCount++;
|
||||
}
|
||||
|
||||
if (latestPcs != null)
|
||||
{
|
||||
if (CompletePcs(latestPcs, bitmapObjects, palettes))
|
||||
pcsList.Add(latestPcs);
|
||||
latestPcs = null;
|
||||
}
|
||||
|
||||
for (int pcsIndex = 1; pcsIndex < pcsList.Count; pcsIndex++)
|
||||
pcsList[pcsIndex - 1].EndTime = pcsList[pcsIndex].StartTime;
|
||||
pcsList.RemoveAll(pcs => pcs.PcsObjects.Count == 0);
|
||||
|
||||
foreach (PcsData pcs in pcsList)
|
||||
{
|
||||
foreach (List<OdsData> odsList in pcs.BitmapObjects)
|
||||
{
|
||||
if (odsList.Count > 1)
|
||||
{
|
||||
int bufSize = 0;
|
||||
foreach (OdsData ods in odsList)
|
||||
bufSize += ods.Fragment.ImagePacketSize;
|
||||
byte[] buf = new byte[bufSize];
|
||||
int offset = 0;
|
||||
foreach (OdsData ods in odsList)
|
||||
{
|
||||
Buffer.BlockCopy(ods.Fragment.ImageBuffer, 0, buf, offset, ods.Fragment.ImagePacketSize);
|
||||
offset += ods.Fragment.ImagePacketSize;
|
||||
}
|
||||
odsList[0].Fragment.ImageBuffer = buf;
|
||||
odsList[0].Fragment.ImagePacketSize = bufSize;
|
||||
while (odsList.Count > 1)
|
||||
odsList.RemoveAt(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int pcsIndex = pcsList.Count - 1; pcsIndex > 0; pcsIndex--)
|
||||
{
|
||||
var cur = pcsList[pcsIndex];
|
||||
var prev = pcsList[pcsIndex - 1];
|
||||
if (Math.Abs(prev.EndTime - cur.StartTime) < 10 && prev.Size.Width == cur.Size.Width && prev.Size.Height == cur.Size.Height)
|
||||
{
|
||||
if (cur.BitmapObjects.Count > 0 && cur.BitmapObjects[0].Count > 0 &&
|
||||
prev.BitmapObjects.Count > 0 && prev.BitmapObjects[0].Count > 0 &&
|
||||
ByteArraysEqual(cur.BitmapObjects[0][0].Fragment.ImageBuffer, prev.BitmapObjects[0][0].Fragment.ImageBuffer))
|
||||
{
|
||||
prev.EndTime = cur.EndTime;
|
||||
pcsList.RemoveAt(pcsIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pcsList;
|
||||
}
|
||||
|
||||
private static bool ByteArraysEqual(byte[] b1, byte[] b2)
|
||||
{
|
||||
if (b1 == b2)
|
||||
return true;
|
||||
if (b1 == null || b2 == null)
|
||||
return false;
|
||||
if (b1.Length != b2.Length)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < b1.Length; i++)
|
||||
{
|
||||
if (b1[i] != b2[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static CompositionState GetCompositionState(byte type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case 0x00:
|
||||
return CompositionState.Normal;
|
||||
case 0x40:
|
||||
return CompositionState.AcquPoint;
|
||||
case 0x80:
|
||||
return CompositionState.EpochStart;
|
||||
case 0xC0:
|
||||
return CompositionState.EpochContinue;
|
||||
default:
|
||||
return CompositionState.Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
private static int BigEndianInt16(byte[] buffer, int index)
|
||||
{
|
||||
if (buffer.Length < 2)
|
||||
return 0;
|
||||
return (buffer[index + 1]) + (buffer[index + 0] << 8);
|
||||
}
|
||||
|
||||
private static uint BigEndianInt32(byte[] buffer, int index)
|
||||
{
|
||||
if (buffer.Length < 4)
|
||||
return 0;
|
||||
return (uint)((buffer[index + 3]) + (buffer[index + 2] << 8) + (buffer[index + 1] << 0x10) + (buffer[index + 0] << 0x18));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
572
libse/BluRaySup/BluRaySupPicture.cs
Normal file
572
libse/BluRaySup/BluRaySupPicture.cs
Normal file
@ -0,0 +1,572 @@
|
||||
/*
|
||||
* Copyright 2009 Volker Oth (0xdeadbeef)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* NOTE: Converted to C# and modified by Nikse.dk@gmail.com
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.BluRaySup
|
||||
{
|
||||
|
||||
public class BluRaySupPicture
|
||||
{
|
||||
/// <summary>
|
||||
/// screen width
|
||||
/// </summary>
|
||||
public int Width { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// screen height
|
||||
/// </summary>
|
||||
public int Height { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// start time in milliseconds
|
||||
/// </summary>
|
||||
public long StartTime { get; set; }
|
||||
|
||||
public int StartTimeForWrite
|
||||
{
|
||||
get { return (int)((StartTime - 45) * 90.0); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// end time in milliseconds
|
||||
/// </summary>
|
||||
public long EndTime { get; set; }
|
||||
|
||||
public int EndTimeForWrite
|
||||
{
|
||||
get { return (int)((EndTime - 45) * 90.0); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// if true, this is a forced subtitle
|
||||
/// </summary>
|
||||
public bool IsForced { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// composition number - increased at start and end PCS
|
||||
/// </summary>
|
||||
public int CompositionNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// objectID used in decoded object
|
||||
/// </summary>
|
||||
public int ObjectId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// list of ODS packets containing image info
|
||||
/// </summary>
|
||||
public List<ImageObject> ImageObjects;
|
||||
|
||||
/// <summary>
|
||||
/// width of subtitle window (might be larger than image)
|
||||
/// </summary>
|
||||
public int WindowWidth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// height of subtitle window (might be larger than image)
|
||||
/// </summary>
|
||||
public int WindowHeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// upper left corner of subtitle window x
|
||||
/// </summary>
|
||||
public int WindowXOffset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// upper left corner of subtitle window y
|
||||
/// </summary>
|
||||
public int WindowYOffset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// FPS type (e.g. 0x10 = 24p)
|
||||
/// </summary>
|
||||
public int FramesPerSecondType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of (list of) palette info - there are up to 8 palettes per epoch, each can be updated several times
|
||||
/// </summary>
|
||||
public List<List<PaletteInfo>> Palettes;
|
||||
|
||||
/// <summary>
|
||||
/// Create RLE buffer from bitmap
|
||||
/// </summary>
|
||||
/// <param name="bm">Bitmap to compress</param>
|
||||
/// <param name="palette">Palette used for bitmap encoding</param>
|
||||
/// <returns>RLE buffer</returns>
|
||||
private static byte[] EncodeImage(NikseBitmap bm, Dictionary<Color, int> palette)
|
||||
{
|
||||
var bytes = new List<Byte>();
|
||||
for (int y = 0; y < bm.Height; y++)
|
||||
{
|
||||
var ofs = y * bm.Width;
|
||||
//eol = false;
|
||||
int x;
|
||||
int len;
|
||||
for (x = 0; x < bm.Width; x += len, ofs += len)
|
||||
{
|
||||
Color c = bm.GetPixel(x, y);
|
||||
byte color;
|
||||
if (palette.ContainsKey(c))
|
||||
color = (byte)palette[c];
|
||||
else
|
||||
color = FindBestMatch(c, palette);
|
||||
|
||||
for (len = 1; x + len < bm.Width; len++)
|
||||
if (bm.GetPixel(x + len, y) != c)
|
||||
break;
|
||||
|
||||
if (len <= 2 && color != 0)
|
||||
{
|
||||
// only a single occurrence -> add color
|
||||
bytes.Add(color);
|
||||
if (len == 2)
|
||||
bytes.Add(color);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (len > 0x3fff)
|
||||
len = 0x3fff;
|
||||
bytes.Add(0); // rle id
|
||||
// commented out due to bug in SupRip
|
||||
/*if (color == 0 && x+len == bm.Width)
|
||||
{
|
||||
bytes.Add(0);
|
||||
eol = true;
|
||||
}
|
||||
else */
|
||||
if (color == 0 && len < 0x40)
|
||||
{
|
||||
// 00 xx -> xx times 0
|
||||
bytes.Add((byte)len);
|
||||
}
|
||||
else if (color == 0)
|
||||
{
|
||||
// 00 4x xx -> xxx zeroes
|
||||
bytes.Add((byte)(0x40 | (len >> 8)));
|
||||
bytes.Add((byte)len);
|
||||
}
|
||||
else if (len < 0x40)
|
||||
{
|
||||
// 00 8x cc -> x times value cc
|
||||
bytes.Add((byte)(0x80 | len));
|
||||
bytes.Add(color);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 00 cx yy cc -> xyy times value cc
|
||||
bytes.Add((byte)(0xc0 | (len >> 8)));
|
||||
bytes.Add((byte)len);
|
||||
bytes.Add(color);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (/*!eol &&*/ x == bm.Width)
|
||||
{
|
||||
bytes.Add(0); // rle id
|
||||
bytes.Add(0);
|
||||
}
|
||||
}
|
||||
int size = bytes.Count;
|
||||
var retval = new byte[size];
|
||||
for (int i = 0; i < size; i++)
|
||||
retval[i] = bytes[i];
|
||||
return retval;
|
||||
}
|
||||
|
||||
private static byte FindBestMatch(Color color, Dictionary<Color, int> palette)
|
||||
{
|
||||
int smallestDiff = 1000;
|
||||
int smallestDiffIndex = -1;
|
||||
foreach (var kvp in palette)
|
||||
{
|
||||
int diff = Math.Abs(kvp.Key.A - color.A) + Math.Abs(kvp.Key.R - color.R) + Math.Abs(kvp.Key.G - color.G) + Math.Abs(kvp.Key.B - color.B);
|
||||
if (diff < smallestDiff)
|
||||
{
|
||||
smallestDiff = diff;
|
||||
smallestDiffIndex = kvp.Value;
|
||||
}
|
||||
}
|
||||
return (byte)smallestDiffIndex;
|
||||
}
|
||||
|
||||
private static bool HasCloseColor(Color color, Dictionary<Color, int> palette, int maxDifference)
|
||||
{
|
||||
foreach (var kvp in palette)
|
||||
{
|
||||
int difference = Math.Abs(kvp.Key.A - color.A) + Math.Abs(kvp.Key.R - color.R) + Math.Abs(kvp.Key.G - color.G) + Math.Abs(kvp.Key.B - color.B);
|
||||
if (difference < maxDifference)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Dictionary<Color, int> GetBitmapPalette(NikseBitmap bitmap)
|
||||
{
|
||||
var pal = new Dictionary<Color, int>();
|
||||
for (int y = 0; y < bitmap.Height; y++)
|
||||
{
|
||||
for (int x = 0; x < bitmap.Width; x++)
|
||||
{
|
||||
var c = bitmap.GetPixel(x, y);
|
||||
if (c != Color.Transparent)
|
||||
{
|
||||
if (pal.Count < 200 && !pal.ContainsKey(c))
|
||||
pal.Add(c, pal.Count);
|
||||
else if (pal.Count < 254 && !HasCloseColor(c, pal, 5))
|
||||
pal.Add(c, pal.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
pal.Add(Color.Transparent, pal.Count); // last entry must be transparent
|
||||
return pal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get ID for given frame rate
|
||||
/// </summary>
|
||||
/// <param name="fps">frame rate</param>
|
||||
/// <returns>byte ID for the given frame rate</returns>
|
||||
private static int GetFpsId(double fps)
|
||||
{
|
||||
if (Math.Abs(fps - Core.Fps24Hz) < 0.01) // 24
|
||||
return 0x20;
|
||||
if (Math.Abs(fps - Core.FpsPal) < 0.01) // 25
|
||||
return 0x30;
|
||||
if (Math.Abs(fps - Core.FpsNtsc) < 0.01) // 29.97
|
||||
return 0x40;
|
||||
if (Math.Abs(fps - Core.FpsPalI) < 0.01) // 50
|
||||
return 0x60;
|
||||
if (Math.Abs(fps - Core.FpsNtscI) < 0.1) // 59.94
|
||||
return 0x70;
|
||||
|
||||
return 0x10; // 23.976
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the binary stream representation of one caption
|
||||
/// </summary>
|
||||
/// <param name="pic">SubPicture object containing caption info</param>
|
||||
/// <param name="bmp">Bitmap</param>
|
||||
/// <param name="fps">Frames per second</param>
|
||||
/// <param name="bottomMargin">Image bottom margin</param>
|
||||
/// <param name="leftOrRightMargin">Image left/right margin</param>
|
||||
/// <param name="alignment">Alignment of image</param>
|
||||
/// <returns>Byte buffer containing the binary stream representation of one caption</returns>
|
||||
public static byte[] CreateSupFrame(BluRaySupPicture pic, Bitmap bmp, double fps, int bottomMargin, int leftOrRightMargin, ContentAlignment alignment)
|
||||
{
|
||||
var bm = new NikseBitmap(bmp);
|
||||
var colorPalette = GetBitmapPalette(bm);
|
||||
var pal = new BluRaySupPalette(colorPalette.Count);
|
||||
int k = 0;
|
||||
foreach (var kvp in colorPalette)
|
||||
{
|
||||
pal.SetColor(k, kvp.Key);
|
||||
k++;
|
||||
}
|
||||
|
||||
byte[] rleBuf = EncodeImage(bm, colorPalette);
|
||||
|
||||
// for some obscure reason, a packet can be a maximum 0xfffc bytes
|
||||
// since 13 bytes are needed for the header("PG", PTS, DTS, ID, SIZE)
|
||||
// there are only 0xffef bytes available for the packet
|
||||
// since the first ODS packet needs an additional 11 bytes for info
|
||||
// and the following ODS packets need 4 additional bytes, the
|
||||
// first package can store only 0xffe4 RLE buffer bytes and the
|
||||
// following packets can store 0xffeb RLE buffer bytes
|
||||
int numAddPackets;
|
||||
if (rleBuf.Length <= 0xffe4)
|
||||
numAddPackets = 0; // no additional packets needed;
|
||||
else
|
||||
numAddPackets = 1 + (rleBuf.Length - 0xffe4) / 0xffeb;
|
||||
|
||||
// a typical frame consists of 8 packets. It can be enlonged by additional
|
||||
// object frames
|
||||
int palSize = colorPalette.Count;
|
||||
|
||||
var packetHeader = new byte[]
|
||||
{
|
||||
0x50, 0x47, // 0: "PG"
|
||||
0x00, 0x00, 0x00, 0x00, // 2: PTS - presentation time stamp
|
||||
0x00, 0x00, 0x00, 0x00, // 6: DTS - decoding time stamp
|
||||
0x00, // 10: segment_type
|
||||
0x00, 0x00 // 11: segment_length (bytes following till next PG)
|
||||
};
|
||||
var headerPcsStart = new byte[]
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, // 0: video_width, video_height
|
||||
0x10, // 4: hi nibble: frame_rate (0x10=24p), lo nibble: reserved
|
||||
0x00, 0x00, // 5: composition_number (increased by start and end header)
|
||||
0x80, // 7: composition_state (0x80: epoch start)
|
||||
0x00, // 8: palette_update_flag (0x80), 7bit reserved
|
||||
0x00, // 9: palette_id_ref (0..7)
|
||||
0x01, // 10: number_of_composition_objects (0..2)
|
||||
0x00, 0x00, // 11: 16bit object_id_ref
|
||||
0x00, // 13: window_id_ref (0..1)
|
||||
0x00, // 14: object_cropped_flag: 0x80, forced_on_flag = 0x040, 6bit reserved
|
||||
0x00, 0x00, 0x00, 0x00 // 15: composition_object_horizontal_position, composition_object_vertical_position
|
||||
};
|
||||
var headerPcsEnd = new byte[]
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, // 0: video_width, video_height
|
||||
0x10, // 4: hi nibble: frame_rate (0x10=24p), lo nibble: reserved
|
||||
0x00, 0x00, // 5: composition_number (increased by start and end header)
|
||||
0x00, // 7: composition_state (0x00: normal)
|
||||
0x00, // 8: palette_update_flag (0x80), 7bit reserved
|
||||
0x00, // 9: palette_id_ref (0..7)
|
||||
0x00 // 10: number_of_composition_objects (0..2)
|
||||
};
|
||||
var headerWds = new byte[]
|
||||
{
|
||||
0x01, // 0 : number of windows (currently assumed 1, 0..2 is legal)
|
||||
0x00, // 1 : window id (0..1)
|
||||
0x00, 0x00, 0x00, 0x00, // 2 : x-ofs, y-ofs
|
||||
0x00, 0x00, 0x00, 0x00 // 6 : width, height
|
||||
};
|
||||
var headerOdsFirst = new byte[]
|
||||
{
|
||||
0x00, 0x00, // 0: object_id
|
||||
0x00, // 2: object_version_number
|
||||
0xC0, // 3: first_in_sequence (0x80), last_in_sequence (0x40), 6bits reserved
|
||||
0x00, 0x00, 0x00, // 4: object_data_length - full RLE buffer length (including 4 bytes size info)
|
||||
0x00, 0x00, 0x00, 0x00 // 7: object_width, object_height
|
||||
};
|
||||
var headerOdsNext = new byte[]
|
||||
{
|
||||
0x00, 0x00, // 0: object_id
|
||||
0x00, // 2: object_version_number
|
||||
0x40 // 3: first_in_sequence (0x80), last_in_sequence (0x40), 6bits reserved
|
||||
};
|
||||
|
||||
int size = packetHeader.Length * (8 + numAddPackets);
|
||||
size += headerPcsStart.Length + headerPcsEnd.Length;
|
||||
size += 2 * headerWds.Length + headerOdsFirst.Length;
|
||||
size += numAddPackets * headerOdsNext.Length;
|
||||
size += (2 + palSize * 5) /* PDS */;
|
||||
size += rleBuf.Length;
|
||||
|
||||
switch (alignment)
|
||||
{
|
||||
case ContentAlignment.BottomLeft:
|
||||
pic.WindowXOffset = leftOrRightMargin;
|
||||
pic.WindowYOffset = pic.Height - (bm.Height + bottomMargin);
|
||||
break;
|
||||
case ContentAlignment.BottomRight:
|
||||
pic.WindowXOffset = pic.Width - bm.Width - bottomMargin;
|
||||
pic.WindowYOffset = pic.Height - (bm.Height + leftOrRightMargin);
|
||||
break;
|
||||
case ContentAlignment.MiddleCenter:
|
||||
pic.WindowXOffset = (pic.Width - bm.Width) / 2;
|
||||
pic.WindowYOffset = (pic.Height - bm.Height) / 2;
|
||||
break;
|
||||
case ContentAlignment.MiddleLeft:
|
||||
pic.WindowXOffset = leftOrRightMargin;
|
||||
pic.WindowYOffset = (pic.Height - bm.Height) / 2;
|
||||
break;
|
||||
case ContentAlignment.MiddleRight:
|
||||
pic.WindowXOffset = pic.Width - bm.Width - leftOrRightMargin;
|
||||
pic.WindowYOffset = (pic.Height - bm.Height) / 2;
|
||||
break;
|
||||
case ContentAlignment.TopCenter:
|
||||
pic.WindowXOffset = (pic.Width - bm.Width) / 2;
|
||||
pic.WindowYOffset = bottomMargin;
|
||||
break;
|
||||
case ContentAlignment.TopLeft:
|
||||
pic.WindowXOffset = leftOrRightMargin;
|
||||
pic.WindowYOffset = bottomMargin;
|
||||
break;
|
||||
case ContentAlignment.TopRight:
|
||||
pic.WindowXOffset = pic.Width - bm.Width - leftOrRightMargin;
|
||||
pic.WindowYOffset = bottomMargin;
|
||||
break;
|
||||
default: // ContentAlignment.BottomCenter:
|
||||
pic.WindowXOffset = (pic.Width - bm.Width) / 2;
|
||||
pic.WindowYOffset = pic.Height - (bm.Height + bottomMargin);
|
||||
break;
|
||||
}
|
||||
|
||||
int yOfs = pic.WindowYOffset - Core.CropOfsY;
|
||||
if (yOfs < 0)
|
||||
{
|
||||
yOfs = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int yMax = pic.Height - pic.WindowHeight - 2 * Core.CropOfsY;
|
||||
if (yOfs > yMax)
|
||||
yOfs = yMax;
|
||||
}
|
||||
|
||||
int h = pic.Height - 2 * Core.CropOfsY;
|
||||
|
||||
var buf = new byte[size];
|
||||
int index = 0;
|
||||
|
||||
int fpsId = GetFpsId(fps);
|
||||
|
||||
/* time (in 90kHz resolution) needed to initialize (clear) the screen buffer
|
||||
based on the composition pixel rate of 256e6 bit/s - always rounded up */
|
||||
int frameInitTime = (pic.Width * pic.Height * 9 + 3199) / 3200; // better use default height here
|
||||
/* time (in 90kHz resolution) needed to initialize (clear) the window area
|
||||
based on the composition pixel rate of 256e6 bit/s - always rounded up
|
||||
Note: no cropping etc. -> window size == image size */
|
||||
int windowInitTime = (bm.Width * bm.Height * 9 + 3199) / 3200;
|
||||
/* time (in 90kHz resolution) needed to decode the image
|
||||
based on the decoding pixel rate of 128e6 bit/s - always rounded up */
|
||||
int imageDecodeTime = (bm.Width * bm.Height * 9 + 1599) / 1600;
|
||||
// write PCS start
|
||||
packetHeader[10] = 0x16; // ID
|
||||
int dts = pic.StartTimeForWrite - (frameInitTime + windowInitTime + imageDecodeTime); //int dts = pic.StartTimeForWrite - windowInitTime; ???
|
||||
|
||||
ToolBox.SetDWord(packetHeader, 2, pic.StartTimeForWrite); // PTS
|
||||
ToolBox.SetDWord(packetHeader, 6, dts); // DTS
|
||||
ToolBox.SetWord(packetHeader, 11, headerPcsStart.Length); // size
|
||||
for (int i = 0; i < packetHeader.Length; i++)
|
||||
buf[index++] = packetHeader[i];
|
||||
ToolBox.SetWord(headerPcsStart, 0, pic.Width);
|
||||
ToolBox.SetWord(headerPcsStart, 2, h); // cropped height
|
||||
ToolBox.SetByte(headerPcsStart, 4, fpsId);
|
||||
ToolBox.SetWord(headerPcsStart, 5, pic.CompositionNumber);
|
||||
headerPcsStart[14] = (byte)(pic.IsForced ? 0x40 : 0);
|
||||
ToolBox.SetWord(headerPcsStart, 15, pic.WindowXOffset);
|
||||
ToolBox.SetWord(headerPcsStart, 17, yOfs);
|
||||
for (int i = 0; i < headerPcsStart.Length; i++)
|
||||
buf[index++] = headerPcsStart[i];
|
||||
|
||||
// write WDS
|
||||
packetHeader[10] = 0x17; // ID
|
||||
int timestamp = pic.StartTimeForWrite - windowInitTime;
|
||||
ToolBox.SetDWord(packetHeader, 2, timestamp); // PTS (keep DTS)
|
||||
ToolBox.SetWord(packetHeader, 11, headerWds.Length); // size
|
||||
for (int i = 0; i < packetHeader.Length; i++)
|
||||
buf[index++] = packetHeader[i];
|
||||
ToolBox.SetWord(headerWds, 2, pic.WindowXOffset);
|
||||
ToolBox.SetWord(headerWds, 4, yOfs);
|
||||
ToolBox.SetWord(headerWds, 6, bm.Width);
|
||||
ToolBox.SetWord(headerWds, 8, bm.Height);
|
||||
for (int i = 0; i < headerWds.Length; i++)
|
||||
buf[index++] = headerWds[i];
|
||||
|
||||
// write PDS
|
||||
packetHeader[10] = 0x14; // ID
|
||||
ToolBox.SetDWord(packetHeader, 2, dts); // PTS (=DTS of PCS/WDS)
|
||||
ToolBox.SetDWord(packetHeader, 6, 0); // DTS (0)
|
||||
ToolBox.SetWord(packetHeader, 11, (2 + palSize * 5)); // size
|
||||
for (int i = 0; i < packetHeader.Length; i++)
|
||||
buf[index++] = packetHeader[i];
|
||||
buf[index++] = 0;
|
||||
buf[index++] = 0;
|
||||
for (int i = 0; i < palSize; i++)
|
||||
{
|
||||
buf[index++] = (byte)i; // index
|
||||
buf[index++] = pal.GetY()[i]; // Y
|
||||
buf[index++] = pal.GetCr()[i]; // Cr
|
||||
buf[index++] = pal.GetCb()[i]; // Cb
|
||||
buf[index++] = pal.GetAlpha()[i]; // Alpha
|
||||
}
|
||||
|
||||
// write first OBJ
|
||||
int bufSize = rleBuf.Length;
|
||||
int rleIndex = 0;
|
||||
if (bufSize > 0xffe4)
|
||||
bufSize = 0xffe4;
|
||||
packetHeader[10] = 0x15; // ID
|
||||
timestamp = dts + imageDecodeTime;
|
||||
ToolBox.SetDWord(packetHeader, 2, timestamp); // PTS
|
||||
ToolBox.SetDWord(packetHeader, 6, dts); // DTS
|
||||
ToolBox.SetWord(packetHeader, 11, headerOdsFirst.Length + bufSize); // size
|
||||
for (int i = 0; i < packetHeader.Length; i++)
|
||||
buf[index++] = packetHeader[i];
|
||||
int marker = (int)((numAddPackets == 0) ? 0xC0000000 : 0x80000000);
|
||||
ToolBox.SetDWord(headerOdsFirst, 3, marker | (rleBuf.Length + 4));
|
||||
ToolBox.SetWord(headerOdsFirst, 7, bm.Width);
|
||||
ToolBox.SetWord(headerOdsFirst, 9, bm.Height);
|
||||
for (int i = 0; i < headerOdsFirst.Length; i++)
|
||||
buf[index++] = headerOdsFirst[i];
|
||||
for (int i = 0; i < bufSize; i++)
|
||||
buf[index++] = rleBuf[rleIndex++];
|
||||
|
||||
// write additional OBJ packets
|
||||
bufSize = rleBuf.Length - bufSize; // remaining bytes to write
|
||||
for (int p = 0; p < numAddPackets; p++)
|
||||
{
|
||||
int psize = bufSize;
|
||||
if (psize > 0xffeb)
|
||||
psize = 0xffeb;
|
||||
packetHeader[10] = 0x15; // ID (keep DTS & PTS)
|
||||
ToolBox.SetWord(packetHeader, 11, headerOdsNext.Length + psize); // size
|
||||
for (int i = 0; i < packetHeader.Length; i++)
|
||||
buf[index++] = packetHeader[i];
|
||||
for (int i = 0; i < headerOdsNext.Length; i++)
|
||||
buf[index++] = headerOdsNext[i];
|
||||
for (int i = 0; i < psize; i++)
|
||||
buf[index++] = rleBuf[rleIndex++];
|
||||
bufSize -= psize;
|
||||
}
|
||||
|
||||
// write END
|
||||
packetHeader[10] = 0x80; // ID
|
||||
ToolBox.SetDWord(packetHeader, 6, 0); // DTS (0) (keep PTS of ODS)
|
||||
ToolBox.SetWord(packetHeader, 11, 0); // size
|
||||
for (int i = 0; i < packetHeader.Length; i++)
|
||||
buf[index++] = packetHeader[i];
|
||||
|
||||
// write PCS end
|
||||
packetHeader[10] = 0x16; // ID
|
||||
ToolBox.SetDWord(packetHeader, 2, pic.EndTimeForWrite); // PTS
|
||||
dts = pic.EndTimeForWrite - 1; //dts = pic.StartTimeForWrite - 1;
|
||||
ToolBox.SetDWord(packetHeader, 6, dts); // DTS
|
||||
ToolBox.SetWord(packetHeader, 11, headerPcsEnd.Length); // size
|
||||
for (int i = 0; i < packetHeader.Length; i++)
|
||||
buf[index++] = packetHeader[i];
|
||||
ToolBox.SetWord(headerPcsEnd, 0, pic.Width);
|
||||
ToolBox.SetWord(headerPcsEnd, 2, h); // cropped height
|
||||
ToolBox.SetByte(headerPcsEnd, 4, fpsId);
|
||||
ToolBox.SetWord(headerPcsEnd, 5, pic.CompositionNumber + 1);
|
||||
for (int i = 0; i < headerPcsEnd.Length; i++)
|
||||
buf[index++] = headerPcsEnd[i];
|
||||
|
||||
// write WDS
|
||||
packetHeader[10] = 0x17; // ID
|
||||
timestamp = pic.EndTimeForWrite - windowInitTime;
|
||||
ToolBox.SetDWord(packetHeader, 2, timestamp); // PTS (keep DTS of PCS)
|
||||
ToolBox.SetWord(packetHeader, 11, headerWds.Length); // size
|
||||
for (int i = 0; i < packetHeader.Length; i++)
|
||||
buf[index++] = packetHeader[i];
|
||||
ToolBox.SetWord(headerWds, 2, pic.WindowXOffset);
|
||||
ToolBox.SetWord(headerWds, 4, yOfs);
|
||||
ToolBox.SetWord(headerWds, 6, bm.Width);
|
||||
ToolBox.SetWord(headerWds, 8, bm.Height);
|
||||
for (int i = 0; i < headerWds.Length; i++)
|
||||
buf[index++] = headerWds[i];
|
||||
|
||||
// write END
|
||||
packetHeader[10] = 0x80; // ID
|
||||
ToolBox.SetDWord(packetHeader, 2, dts); // PTS (DTS of end PCS)
|
||||
ToolBox.SetDWord(packetHeader, 6, 0); // DTS (0)
|
||||
ToolBox.SetWord(packetHeader, 11, 0); // size
|
||||
for (int i = 0; i < packetHeader.Length; i++)
|
||||
buf[index++] = packetHeader[i];
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
90
libse/BluRaySup/Core.cs
Normal file
90
libse/BluRaySup/Core.cs
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2009 Volker Oth (0xdeadbeef)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* NOTE: Converted to C# and modified by Nikse.dk@gmail.com
|
||||
*/
|
||||
namespace Nikse.SubtitleEdit.Core.BluRaySup
|
||||
{
|
||||
public static class Core
|
||||
{
|
||||
|
||||
/** Use BT.601 color model instead of BT.709 */
|
||||
private const bool UseBt601 = false;
|
||||
|
||||
/** Flag that defines whether to swap Cr/Cb components when loading a SUP */
|
||||
private const bool SwapCrCb = false;
|
||||
|
||||
/** Alpha threshold for cropping */
|
||||
private const int AlphaCrop = 14;
|
||||
|
||||
/** Two equal captions are merged of they are closer than 200ms (0.2*90000 = 18000) */
|
||||
private const int MergePtSdiff = 18000;
|
||||
|
||||
/** Frames per seconds for 24p (23.976) */
|
||||
public const double Fps24P = 24000.0 / 1001;
|
||||
/** Frames per seconds for wrong 24P (23.975) */
|
||||
public const double Fps23975 = 23.975;
|
||||
/** Frames per seconds for 24Hz (24.0) */
|
||||
public const double Fps24Hz = 24.0;
|
||||
/** Frames per seconds for PAL progressive (25.0) */
|
||||
public const double FpsPal = 25.0;
|
||||
/** Frames per seconds for NTSC progressive (29.97) */
|
||||
public const double FpsNtsc = 30000.0 / 1001;
|
||||
/** Frames per seconds for PAL interlaced (50.0) */
|
||||
public const double FpsPalI = 50.0;
|
||||
/** Frames per seconds for NTSC interlaced (59.94) */
|
||||
public const double FpsNtscI = 60000.0 / 1001;
|
||||
|
||||
/**
|
||||
* Get maximum time difference for merging captions.
|
||||
* @return Maximum time difference for merging captions
|
||||
*/
|
||||
public static int GetMergePtSdiff()
|
||||
{
|
||||
return MergePtSdiff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get: use of BT.601 color model instead of BT.709.
|
||||
* @return True if BT.601 is used
|
||||
*/
|
||||
public static bool UsesBt601()
|
||||
{
|
||||
return UseBt601;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get flag that defines whether to swap Cr/Cb components when loading a SUP.
|
||||
* @return True: swap cr/cb
|
||||
*/
|
||||
public static bool GetSwapCrCb()
|
||||
{
|
||||
return SwapCrCb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get alpha threshold for cropping.
|
||||
* @return Alpha threshold for cropping
|
||||
*/
|
||||
public static int GetAlphaCrop()
|
||||
{
|
||||
return AlphaCrop;
|
||||
}
|
||||
|
||||
public static int CropOfsY { get; set; }
|
||||
|
||||
public const double FpsTrg = FpsPal;
|
||||
}
|
||||
}
|
60
libse/BluRaySup/ImageObject.cs
Normal file
60
libse/BluRaySup/ImageObject.cs
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2009 Volker Oth (0xdeadbeef)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* NOTE: Converted to C# and modified by Nikse.dk@gmail.com
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.BluRaySup
|
||||
{
|
||||
public class ImageObject
|
||||
{
|
||||
/// <summary>
|
||||
/// list of ODS packets containing image info
|
||||
/// </summary>
|
||||
public List<ImageObjectFragment> Fragments;
|
||||
|
||||
/// <summary>
|
||||
/// palette identifier
|
||||
/// </summary>
|
||||
public int PaletteId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// overall size of RLE buffer (might be spread over several packages)
|
||||
/// </summary>
|
||||
public int BufferSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// with of subtitle image
|
||||
/// </summary>
|
||||
public int Width { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// height of subtitle image
|
||||
/// </summary>
|
||||
public int Height { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// upper left corner of subtitle x
|
||||
/// </summary>
|
||||
public int XOffset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// upper left corner of subtitle y
|
||||
/// </summary>
|
||||
public int YOffset { get; set; }
|
||||
}
|
||||
}
|
37
libse/BluRaySup/ImageObjectFragment.cs
Normal file
37
libse/BluRaySup/ImageObjectFragment.cs
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2009 Volker Oth (0xdeadbeef)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* NOTE: Converted to C# and modified by Nikse.dk@gmail.com
|
||||
*/
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.BluRaySup
|
||||
{
|
||||
/// <summary>
|
||||
/// contains offset and size of one fragment containing (parts of the) RLE buffer
|
||||
/// </summary>
|
||||
public class ImageObjectFragment
|
||||
{
|
||||
/// <summary>
|
||||
/// size of this part of the RLE buffer
|
||||
/// </summary>
|
||||
public int ImagePacketSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Buffer for raw image data fragment
|
||||
/// </summary>
|
||||
public byte[] ImageBuffer { get; set; }
|
||||
}
|
||||
|
||||
}
|
50
libse/BluRaySup/PaletteInfo.cs
Normal file
50
libse/BluRaySup/PaletteInfo.cs
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2009 Volker Oth (0xdeadbeef)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* NOTE: Converted to C# and modified by Nikse.dk@gmail.com
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.BluRaySup
|
||||
{
|
||||
/// <summary>
|
||||
/// contains offset and size of one update of a palette
|
||||
/// </summary>
|
||||
public class PaletteInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// number of palette entries
|
||||
/// </summary>
|
||||
public int PaletteSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// raw palette data
|
||||
/// </summary>
|
||||
public byte[] PaletteBuffer { get; set; }
|
||||
|
||||
public PaletteInfo()
|
||||
{
|
||||
}
|
||||
|
||||
public PaletteInfo(PaletteInfo paletteInfo)
|
||||
{
|
||||
PaletteSize = paletteInfo.PaletteSize;
|
||||
PaletteBuffer = new byte[paletteInfo.PaletteBuffer.Length];
|
||||
Buffer.BlockCopy(paletteInfo.PaletteBuffer, 0, PaletteBuffer, 0, PaletteBuffer.Length);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
122
libse/BluRaySup/ToolBox.cs
Normal file
122
libse/BluRaySup/ToolBox.cs
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright 2009 Volker Oth (0xdeadbeef)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* NOTE: Converted to C# and modified by Nikse.dk@gmail.com
|
||||
*/
|
||||
|
||||
using System.Text;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.BluRaySup
|
||||
{
|
||||
public static class ToolBox
|
||||
{
|
||||
/// <summary>
|
||||
/// Convert bytes to a C-style hex string with leading zeroes
|
||||
/// </summary>
|
||||
public static string ToHex(byte[] buffer, int index, int digits)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
for (int i = index; i < index + digits; i++)
|
||||
{
|
||||
string s = string.Format("{0:X}", buffer[i]);
|
||||
if (s.Length < 2)
|
||||
sb.Append('0');
|
||||
sb.Append(s);
|
||||
}
|
||||
return "0x" + sb;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a long integer to a C-style hex string with leading zeroes
|
||||
/// </summary>
|
||||
public static string ToHex(int number, int digits)
|
||||
{
|
||||
string s = string.Format("{0:X}", number);
|
||||
if (s.Length < digits)
|
||||
s = s.PadLeft(digits, '0');
|
||||
return "0x" + s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert time in milliseconds to array containing hours, minutes, seconds and milliseconds
|
||||
* @param ms Time in milliseconds
|
||||
* @return Array containing hours, minutes, seconds and milliseconds (in this order)
|
||||
*/
|
||||
public static int[] MillisecondsToTime(long ms)
|
||||
{
|
||||
int[] time = new int[4];
|
||||
// time[0] = hours
|
||||
time[0] = (int)(ms / (60 * 60 * 1000));
|
||||
ms -= time[0] * 60 * 60 * 1000;
|
||||
// time[1] = minutes
|
||||
time[1] = (int)(ms / (60 * 1000));
|
||||
ms -= time[1] * 60 * 1000;
|
||||
// time[2] = seconds
|
||||
time[2] = (int)(ms / 1000);
|
||||
ms -= time[2] * 1000;
|
||||
time[3] = (int)ms;
|
||||
return time;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert time in 90kHz ticks to string hh:mm:ss.ms
|
||||
/// </summary>
|
||||
/// <param name="pts">Time in 90kHz resolution</param>
|
||||
/// <returns>String in format hh:mm:ss:ms</returns>
|
||||
public static string PtsToTimeString(long pts)
|
||||
{
|
||||
int[] time = MillisecondsToTime((pts + 45) / 90);
|
||||
return string.Format(@"{0:D2}:{1:D2}:{2:D2}.{3:D3}", time[0], time[1], time[2], time[3]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write (big endian) double word to buffer[index] (index points at most significant byte)
|
||||
/// </summary>
|
||||
/// <param name="buffer">Byte array</param>
|
||||
/// <param name="index">Index to write to</param>
|
||||
/// <param name="val">Integer value of double word to write</param>
|
||||
public static void SetDWord(byte[] buffer, int index, int val)
|
||||
{
|
||||
buffer[index] = (byte)(val >> 24);
|
||||
buffer[index + 1] = (byte)(val >> 16);
|
||||
buffer[index + 2] = (byte)(val >> 8);
|
||||
buffer[index + 3] = (byte)(val);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write (big endian) word to buffer[index] (index points at most significant byte)
|
||||
/// </summary>
|
||||
/// <param name="buffer">Byte array</param>
|
||||
/// <param name="index">index Index to write to</param>
|
||||
/// <param name="val">val Integer value of word to write</param>
|
||||
public static void SetWord(byte[] buffer, int index, int val)
|
||||
{
|
||||
buffer[index] = (byte)(val >> 8);
|
||||
buffer[index + 1] = (byte)(val);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write byte to buffer[index]
|
||||
/// </summary>
|
||||
/// <param name="buffer">Byte array</param>
|
||||
/// <param name="index">Index to write to</param>
|
||||
/// <param name="val">Integer value of byte to write</param>
|
||||
public static void SetByte(byte[] buffer, int index, int val)
|
||||
{
|
||||
buffer[index] = (byte)(val);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
22
libse/BmpReader.cs
Normal file
22
libse/BmpReader.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using System;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core
|
||||
{
|
||||
public class BmpReader
|
||||
{
|
||||
|
||||
public string HeaderId { get; private set; }
|
||||
public UInt32 HeaderFileSize { get; private set; }
|
||||
public UInt32 OffsetToPixelArray { get; private set; }
|
||||
|
||||
public BmpReader(string fileName)
|
||||
{
|
||||
byte[] buffer = System.IO.File.ReadAllBytes(fileName);
|
||||
HeaderId = System.Text.Encoding.UTF8.GetString(buffer, 0, 2);
|
||||
HeaderFileSize = BitConverter.ToUInt32(buffer, 2);
|
||||
OffsetToPixelArray = BitConverter.ToUInt32(buffer, 0xa);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
230
libse/Configuration.cs
Normal file
230
libse/Configuration.cs
Normal file
@ -0,0 +1,230 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Configuration settings via Singleton pattern
|
||||
/// </summary>
|
||||
public class Configuration
|
||||
{
|
||||
private static readonly Lazy<Configuration> _instance = new Lazy<Configuration>(() => new Configuration());
|
||||
|
||||
private readonly string _baseDir;
|
||||
private readonly string _dataDir;
|
||||
private readonly Lazy<Settings> _settings;
|
||||
|
||||
private Configuration()
|
||||
{
|
||||
_baseDir = GetBaseDirectory();
|
||||
_dataDir = GetDataDirectory();
|
||||
_settings = new Lazy<Settings>(Settings.GetSettings);
|
||||
}
|
||||
|
||||
public static string SettingsFileName
|
||||
{
|
||||
get
|
||||
{
|
||||
return DataDirectory + "Settings.xml";
|
||||
}
|
||||
}
|
||||
|
||||
public static string DictionariesFolder
|
||||
{
|
||||
get
|
||||
{
|
||||
return DataDirectory + "Dictionaries" + Path.DirectorySeparatorChar;
|
||||
}
|
||||
}
|
||||
|
||||
public static string IconsFolder
|
||||
{
|
||||
get
|
||||
{
|
||||
return BaseDirectory + "Icons" + Path.DirectorySeparatorChar;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsRunningOnLinux()
|
||||
{
|
||||
return Environment.OSVersion.Platform == PlatformID.Unix;
|
||||
}
|
||||
|
||||
public static bool IsRunningOnMac()
|
||||
{
|
||||
return Environment.OSVersion.Platform == PlatformID.MacOSX;
|
||||
}
|
||||
|
||||
public static string TesseractDataFolder
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsRunningOnLinux() || IsRunningOnMac())
|
||||
{
|
||||
if (Directory.Exists("/usr/share/tesseract-ocr/tessdata"))
|
||||
return "/usr/share/tesseract-ocr/tessdata";
|
||||
if (Directory.Exists("/usr/share/tesseract/tessdata"))
|
||||
return "/usr/share/tesseract/tessdata";
|
||||
if (Directory.Exists("/usr/share/tessdata"))
|
||||
return "/usr/share/tessdata";
|
||||
}
|
||||
return TesseractFolder + "tessdata";
|
||||
}
|
||||
}
|
||||
|
||||
public static string TesseractOriginalFolder
|
||||
{
|
||||
get
|
||||
{
|
||||
return BaseDirectory + "Tesseract" + Path.DirectorySeparatorChar;
|
||||
}
|
||||
}
|
||||
|
||||
public static string TesseractFolder
|
||||
{
|
||||
get
|
||||
{
|
||||
return DataDirectory + "Tesseract" + Path.DirectorySeparatorChar;
|
||||
}
|
||||
}
|
||||
|
||||
public static string VobSubCompareFolder
|
||||
{
|
||||
get
|
||||
{
|
||||
return DataDirectory + "VobSub" + Path.DirectorySeparatorChar;
|
||||
}
|
||||
}
|
||||
|
||||
public static string OcrFolder
|
||||
{
|
||||
get
|
||||
{
|
||||
return DataDirectory + "Ocr" + Path.DirectorySeparatorChar;
|
||||
}
|
||||
}
|
||||
|
||||
public static string WaveformsFolder
|
||||
{
|
||||
get
|
||||
{
|
||||
return DataDirectory + "Waveforms" + Path.DirectorySeparatorChar;
|
||||
}
|
||||
}
|
||||
|
||||
public static string SpectrogramsFolder
|
||||
{
|
||||
get
|
||||
{
|
||||
return DataDirectory + "Spectrograms" + Path.DirectorySeparatorChar;
|
||||
}
|
||||
}
|
||||
|
||||
public static string AutoBackupFolder
|
||||
{
|
||||
get
|
||||
{
|
||||
return DataDirectory + "AutoBackup" + Path.DirectorySeparatorChar;
|
||||
}
|
||||
}
|
||||
|
||||
public static string PluginsDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(DataDirectory, "Plugins");
|
||||
}
|
||||
}
|
||||
|
||||
public static string DataDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
return _instance.Value._dataDir;
|
||||
}
|
||||
}
|
||||
|
||||
public static string BaseDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
return _instance.Value._baseDir;
|
||||
}
|
||||
}
|
||||
|
||||
public static Settings Settings
|
||||
{
|
||||
get
|
||||
{
|
||||
return _instance.Value._settings.Value;
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetInstallerPath()
|
||||
{
|
||||
const string valueName = "InstallLocation";
|
||||
var value = RegistryUtil.GetValue(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\SubtitleEdit_is1", valueName);
|
||||
if (value != null && Directory.Exists(value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
value = RegistryUtil.GetValue(@"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\SubtitleEdit_is1", valueName);
|
||||
if (value != null && Directory.Exists(value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string GetBaseDirectory()
|
||||
{
|
||||
var assembly = System.Reflection.Assembly.GetEntryAssembly();
|
||||
var baseDirectory = Path.GetDirectoryName(assembly == null
|
||||
? System.Reflection.Assembly.GetExecutingAssembly().Location
|
||||
: assembly.Location);
|
||||
|
||||
return baseDirectory.EndsWith(Path.DirectorySeparatorChar)
|
||||
? baseDirectory
|
||||
: baseDirectory + Path.DirectorySeparatorChar;
|
||||
}
|
||||
|
||||
private string GetDataDirectory()
|
||||
{
|
||||
if (IsRunningOnLinux() || IsRunningOnMac())
|
||||
{
|
||||
return _baseDir;
|
||||
}
|
||||
|
||||
var installerPath = GetInstallerPath();
|
||||
var hasUninstallFiles = Directory.GetFiles(_baseDir, "unins*.*").Length > 0;
|
||||
var hasDictionaryFolder = Directory.Exists(Path.Combine(_baseDir, "Dictionaries"));
|
||||
var appDataRoamingPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Subtitle Edit");
|
||||
|
||||
if ((installerPath == null || !installerPath.TrimEnd(Path.DirectorySeparatorChar).Equals(_baseDir.TrimEnd(Path.DirectorySeparatorChar), StringComparison.OrdinalIgnoreCase))
|
||||
&& !hasUninstallFiles && (hasDictionaryFolder || !Directory.Exists(Path.Combine(appDataRoamingPath, "Dictionaries"))))
|
||||
{
|
||||
return _baseDir;
|
||||
}
|
||||
|
||||
if (Directory.Exists(appDataRoamingPath))
|
||||
{
|
||||
return appDataRoamingPath + Path.DirectorySeparatorChar;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(appDataRoamingPath);
|
||||
Directory.CreateDirectory(Path.Combine(appDataRoamingPath, "Dictionaries"));
|
||||
return appDataRoamingPath + Path.DirectorySeparatorChar;
|
||||
}
|
||||
catch
|
||||
{
|
||||
System.Windows.Forms.MessageBox.Show("Please re-install Subtitle Edit (installer version)");
|
||||
System.Windows.Forms.Application.ExitThread();
|
||||
return _baseDir;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
147
libse/ContainerFormats/AviRiffData.cs
Normal file
147
libse/ContainerFormats/AviRiffData.cs
Normal file
@ -0,0 +1,147 @@
|
||||
// (c) Giora Tamir (giora@gtamir.com), 2005
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.ContainerFormats
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
internal struct AVIMAINHEADER
|
||||
{ // 'avih'
|
||||
public int dwMicroSecPerFrame;
|
||||
public int dwMaxBytesPerSec;
|
||||
public int dwPaddingGranularity;
|
||||
public int dwFlags;
|
||||
public int dwTotalFrames;
|
||||
public int dwInitialFrames;
|
||||
public int dwStreams;
|
||||
public int dwSuggestedBufferSize;
|
||||
public int dwWidth;
|
||||
public int dwHeight;
|
||||
public int dwReserved0;
|
||||
public int dwReserved1;
|
||||
public int dwReserved2;
|
||||
public int dwReserved3;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
internal struct AVIEXTHEADER
|
||||
{ // 'dmlh'
|
||||
public int dwGrandFrames; // total number of frames in the file
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 244)]
|
||||
public int[] dwFuture; // to be defined later
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
internal struct RECT
|
||||
{
|
||||
public short left;
|
||||
public short top;
|
||||
public short right;
|
||||
public short bottom;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
internal struct AVISTREAMHEADER
|
||||
{ // 'strh'
|
||||
public int fccType; // stream type codes
|
||||
public int fccHandler;
|
||||
public int dwFlags;
|
||||
public short wPriority;
|
||||
public short wLanguage;
|
||||
public int dwInitialFrames;
|
||||
public int dwScale;
|
||||
public int dwRate; // dwRate/dwScale is stream tick rate in ticks/s
|
||||
public int dwStart;
|
||||
public int dwLength;
|
||||
public int dwSuggestedBufferSize;
|
||||
public int dwQuality;
|
||||
public int dwSampleSize;
|
||||
public RECT rcFrame;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
internal struct AVIOLDINDEXENTRY
|
||||
{
|
||||
public int dwChunkId;
|
||||
public int dwFlags;
|
||||
public int dwOffset; // offset of riff chunk header for the data
|
||||
public int dwSize; // size of the data (excluding riff header size)
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
internal struct TIMECODE
|
||||
{
|
||||
public short wFrameRate;
|
||||
public short wFrameFract;
|
||||
public int cFrames;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
internal struct TIMECODEDATA
|
||||
{
|
||||
private TIMECODE time;
|
||||
public int dwSMPTEflags;
|
||||
public int dwUser;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
internal struct WAVEFORMATEX
|
||||
{
|
||||
public short wFormatTag;
|
||||
public short nChannels;
|
||||
public int nSamplesPerSec;
|
||||
public int nAvgBytesPerSec;
|
||||
public short nBlockAlign;
|
||||
public short wBitsPerSample;
|
||||
public short cbSize;
|
||||
}
|
||||
|
||||
internal static class AviRiffData
|
||||
{
|
||||
#region AVI constants
|
||||
|
||||
// AVIMAINHEADER flags
|
||||
public const int AVIF_HASINDEX = 0x00000010; // Index at end of file?
|
||||
public const int AVIF_MUSTUSEINDEX = 0x00000020;
|
||||
public const int AVIF_ISINTERLEAVED = 0x00000100;
|
||||
public const int AVIF_TRUSTCKTYPE = 0x00000800; // Use CKType to find key frames
|
||||
public const int AVIF_WASCAPTUREFILE = 0x00010000;
|
||||
public const int AVIF_COPYRIGHTED = 0x00020000;
|
||||
|
||||
// AVISTREAMINFO flags
|
||||
public const int AVISF_DISABLED = 0x00000001;
|
||||
public const int AVISF_VIDEO_PALCHANGES = 0x00010000;
|
||||
|
||||
// AVIOLDINDEXENTRY flags
|
||||
public const int AVIIF_LIST = 0x00000001;
|
||||
public const int AVIIF_KEYFRAME = 0x00000010;
|
||||
public const int AVIIF_NO_TIME = 0x00000100;
|
||||
public const int AVIIF_COMPRESSOR = 0x0FFF0000; // unused?
|
||||
|
||||
// TIMECODEDATA flags
|
||||
public const int TIMECODE_SMPTE_BINARY_GROUP = 0x07;
|
||||
public const int TIMECODE_SMPTE_COLOR_FRAME = 0x08;
|
||||
|
||||
// AVI stream FourCC codes
|
||||
public static readonly int streamtypeVIDEO = RiffParser.ToFourCC("vids");
|
||||
public static readonly int streamtypeAUDIO = RiffParser.ToFourCC("auds");
|
||||
//public static readonly int streamtypeMIDI = RiffParser.ToFourCC("mids");
|
||||
//public static readonly int streamtypeTEXT = RiffParser.ToFourCC("txts");
|
||||
|
||||
// AVI section FourCC codes
|
||||
public static readonly int ckidAVIHeaderList = RiffParser.ToFourCC("hdrl");
|
||||
public static readonly int ckidMainAVIHeader = RiffParser.ToFourCC("avih");
|
||||
//public static readonly int ckidODML = RiffParser.ToFourCC("odml");
|
||||
//public static readonly int ckidAVIExtHeader = RiffParser.ToFourCC("dmlh");
|
||||
public static readonly int ckidAVIStreamList = RiffParser.ToFourCC("strl");
|
||||
public static readonly int ckidAVIStreamHeader = RiffParser.ToFourCC("strh");
|
||||
//public static readonly int ckidStreamFormat = RiffParser.ToFourCC("strf");
|
||||
//public static readonly int ckidAVIOldIndex = RiffParser.ToFourCC("idx1");
|
||||
public static readonly int ckidINFOList = RiffParser.ToFourCC("INFO");
|
||||
public static readonly int ckidAVIISFT = RiffParser.ToFourCC("ISFT");
|
||||
public const int ckidMP3 = 0x0055;
|
||||
public static readonly int ckidWaveFMT = RiffParser.ToFourCC("fmt ");
|
||||
|
||||
#endregion AVI constants
|
||||
}
|
||||
}
|
53
libse/ContainerFormats/Ebml/Element.cs
Normal file
53
libse/ContainerFormats/Ebml/Element.cs
Normal file
@ -0,0 +1,53 @@
|
||||
namespace Nikse.SubtitleEdit.Core.ContainerFormats.Ebml
|
||||
{
|
||||
internal class Element
|
||||
{
|
||||
private readonly ElementId _id;
|
||||
private readonly long _dataPosition;
|
||||
private readonly long _dataSize;
|
||||
|
||||
public Element(ElementId id, long dataPosition, long dataSize)
|
||||
{
|
||||
_id = id;
|
||||
_dataPosition = dataPosition;
|
||||
_dataSize = dataSize;
|
||||
}
|
||||
|
||||
public ElementId Id
|
||||
{
|
||||
get
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
}
|
||||
|
||||
public long DataPosition
|
||||
{
|
||||
get
|
||||
{
|
||||
return _dataPosition;
|
||||
}
|
||||
}
|
||||
|
||||
public long DataSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return _dataSize;
|
||||
}
|
||||
}
|
||||
|
||||
public long EndPosition
|
||||
{
|
||||
get
|
||||
{
|
||||
return _dataPosition + _dataSize;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format(@"{0} ({1})", _id, _dataSize);
|
||||
}
|
||||
}
|
||||
}
|
43
libse/ContainerFormats/Ebml/ElementId.cs
Normal file
43
libse/ContainerFormats/Ebml/ElementId.cs
Normal file
@ -0,0 +1,43 @@
|
||||
namespace Nikse.SubtitleEdit.Core.ContainerFormats.Ebml
|
||||
{
|
||||
internal enum ElementId
|
||||
{
|
||||
None = 0,
|
||||
|
||||
Ebml = 0x1A45DFA3,
|
||||
Segment = 0x18538067,
|
||||
|
||||
Info = 0x1549A966,
|
||||
TimecodeScale = 0x2AD7B1,
|
||||
Duration = 0x4489,
|
||||
|
||||
Tracks = 0x1654AE6B,
|
||||
TrackEntry = 0xAE,
|
||||
TrackNumber = 0xD7,
|
||||
TrackType = 0x83,
|
||||
DefaultDuration = 0x23E383,
|
||||
Name = 0x536E,
|
||||
Language = 0x22B59C,
|
||||
CodecId = 0x86,
|
||||
CodecPrivate = 0x63A2,
|
||||
Video = 0xE0,
|
||||
PixelWidth = 0xB0,
|
||||
PixelHeight = 0xBA,
|
||||
Audio = 0xE1,
|
||||
ContentEncodings = 0x6D80,
|
||||
ContentEncoding = 0x6240,
|
||||
ContentEncodingOrder = 0x5031,
|
||||
ContentEncodingScope = 0x5032,
|
||||
ContentEncodingType = 0x5033,
|
||||
ContentCompression = 0x5034,
|
||||
ContentCompAlgo = 0x4254,
|
||||
ContentCompSettings = 0x4255,
|
||||
|
||||
Cluster = 0x1F43B675,
|
||||
Timecode = 0xE7,
|
||||
SimpleBlock = 0xA3,
|
||||
BlockGroup = 0xA0,
|
||||
Block = 0xA1,
|
||||
BlockDuration = 0x9B
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
namespace Nikse.SubtitleEdit.Core.ContainerFormats.MaterialExchangeFormat
|
||||
{
|
||||
public enum KeyIdentifier
|
||||
{
|
||||
Unknown,
|
||||
PartitionPack,
|
||||
Preface,
|
||||
EssenceElement,
|
||||
OperationalPattern,
|
||||
PartitionMetadata,
|
||||
StructuralMetadata,
|
||||
DataDefinitionVideo,
|
||||
DataDefinitionAudio,
|
||||
Primer
|
||||
}
|
||||
}
|
155
libse/ContainerFormats/MaterialExchangeFormat/KlvPacket.cs
Normal file
155
libse/ContainerFormats/MaterialExchangeFormat/KlvPacket.cs
Normal file
@ -0,0 +1,155 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Nikse.SubtitleEdit.Core.VobSub;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.ContainerFormats.MaterialExchangeFormat
|
||||
{
|
||||
/// <summary>
|
||||
/// Key-Length-Value MXF package - http://en.wikipedia.org/wiki/KLV + http://en.wikipedia.org/wiki/Material_Exchange_Format
|
||||
/// </summary>
|
||||
public class KlvPacket
|
||||
{
|
||||
public static byte[] PartitionPack = { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, 0x0D, 0x01, 0x02, 0x01, 0x01, 0xff, 0xff, 0x00 }; // 0xff can have different values
|
||||
public static byte[] Preface = { 0x06, 0x0E, 0x2B, 0x34, 0x02, 0x53, 0x01, 0x01, 0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x2F, 0x00 };
|
||||
public static byte[] EssenceElement = { 0x06, 0x0E, 0x2B, 0x34, 0x01, 0x02, 0x01, 0x01, 0x0D, 0x01, 0x03, 0x01, 0xff, 0xff, 0xff, 0xff };
|
||||
public static byte[] OperationalPattern = { 0x06, 0x0E, 0x2B, 0x34, 0x04, 0x01, 0x01, 0x01, 0x0D, 0x01, 0x02, 0x01, 0x00, 0xff, 0xff, 0x00 };
|
||||
public static byte[] PartitionMetadata = { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, 0x0d, 0x01, 0x02, 0x01, 0x01, 0x04, 0x04, 0x00 };
|
||||
public static byte[] StructuralMetadata = { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01, 0x0d, 0x01, 0x01, 0x01, 0x00, 0xff, 0xff, 0x00 };
|
||||
public static byte[] DataDefinitionVideo = { 0x06, 0x0E, 0x2B, 0x34, 0x04, 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0x02, 0x01, 0xff, 0xff, 0x00 };
|
||||
public static byte[] DataDefinitionAudio = { 0x06, 0x0E, 0x2B, 0x34, 0x04, 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0x02, 0x02, 0xff, 0xff, 0x00 };
|
||||
public static byte[] Primer = { 0x06, 0xe, 0x2b, 0x34, 0x02, 0x05, 0x1, 0xff, 0x0d, 0x01, 0x02, 0x01, 0x01, 0x05, 0x01, 0xff };
|
||||
|
||||
private const int KeySize = 16;
|
||||
|
||||
public byte[] Key;
|
||||
public long DataSize;
|
||||
public long TotalSize;
|
||||
public long DataPosition;
|
||||
public PartitionStatus PartionStatus = PartitionStatus.Unknown;
|
||||
|
||||
public KlvPacket(Stream stream)
|
||||
{
|
||||
// read 16-bytes key
|
||||
Key = new byte[KeySize];
|
||||
int read = stream.Read(Key, 0, Key.Length);
|
||||
if (read < Key.Length)
|
||||
{
|
||||
throw new Exception("MXF KLV packet - stream does not have 16 bytes available for key");
|
||||
}
|
||||
int lengthSize;
|
||||
DataSize = GetBasicEncodingRuleLength(stream, out lengthSize);
|
||||
DataPosition = stream.Position;
|
||||
TotalSize = KeySize + lengthSize + DataSize;
|
||||
if (Key[14] >= 1 && Key[14] <= 4)
|
||||
{
|
||||
PartionStatus = (PartitionStatus)Key[14];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read length - never be more than 9 bytes in size (which means max 8 bytes of payload length)
|
||||
/// There are four kinds of encoding for the Length field: 1-byte, 2-byte, 4-byte
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="bytesInLength"></param>
|
||||
/// <returns></returns>
|
||||
private long GetBasicEncodingRuleLength(Stream stream, out int bytesInLength)
|
||||
{
|
||||
int first = stream.ReadByte();
|
||||
if (first > 127) // first bit set
|
||||
{
|
||||
bytesInLength = first & Helper.B01111111;
|
||||
if (bytesInLength > 8)
|
||||
{
|
||||
throw new Exception("MXF KLV packet - lenght bytes > 8");
|
||||
}
|
||||
DataSize = 0;
|
||||
for (int i = 0; i < bytesInLength; i++)
|
||||
{
|
||||
DataSize = DataSize * 256 + stream.ReadByte();
|
||||
}
|
||||
bytesInLength++;
|
||||
return DataSize;
|
||||
}
|
||||
bytesInLength = 1;
|
||||
return first;
|
||||
}
|
||||
|
||||
public KeyIdentifier IdentifierType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsKey(PartitionPack))
|
||||
{
|
||||
return KeyIdentifier.PartitionPack;
|
||||
}
|
||||
if (IsKey(Preface))
|
||||
{
|
||||
return KeyIdentifier.Preface;
|
||||
}
|
||||
if (IsKey(EssenceElement))
|
||||
{
|
||||
return KeyIdentifier.EssenceElement;
|
||||
}
|
||||
if (IsKey(OperationalPattern))
|
||||
{
|
||||
return KeyIdentifier.OperationalPattern;
|
||||
}
|
||||
if (IsKey(PartitionMetadata))
|
||||
{
|
||||
return KeyIdentifier.PartitionMetadata;
|
||||
}
|
||||
if (IsKey(StructuralMetadata))
|
||||
{
|
||||
return KeyIdentifier.StructuralMetadata;
|
||||
}
|
||||
if (IsKey(DataDefinitionVideo))
|
||||
{
|
||||
return KeyIdentifier.DataDefinitionVideo;
|
||||
}
|
||||
if (IsKey(DataDefinitionAudio))
|
||||
{
|
||||
return KeyIdentifier.DataDefinitionAudio;
|
||||
}
|
||||
if (IsKey(Primer))
|
||||
{
|
||||
return KeyIdentifier.DataDefinitionAudio;
|
||||
}
|
||||
|
||||
return KeyIdentifier.Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsKey(byte[] key)
|
||||
{
|
||||
if (KeySize != key.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < KeySize; i++)
|
||||
{
|
||||
if (Key[i] != key[i] && key[i] != 0xff)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public string DisplayKey
|
||||
{
|
||||
get
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
for (int i = 0; i < KeySize; i++)
|
||||
{
|
||||
sb.Append(Key[i].ToString("X2") + "-");
|
||||
}
|
||||
return sb.ToString().TrimEnd('-');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
129
libse/ContainerFormats/MaterialExchangeFormat/MxfParser.cs
Normal file
129
libse/ContainerFormats/MaterialExchangeFormat/MxfParser.cs
Normal file
@ -0,0 +1,129 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Nikse.Core;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.ContainerFormats.MaterialExchangeFormat
|
||||
{
|
||||
public class MxfParser
|
||||
{
|
||||
public string FileName { get; private set; }
|
||||
public bool IsValid { get; private set; }
|
||||
|
||||
private readonly List<string> _subtitleList = new List<string>();
|
||||
public List<string> GetSubtitles()
|
||||
{
|
||||
return _subtitleList;
|
||||
}
|
||||
|
||||
private long _startPosition;
|
||||
|
||||
public MxfParser(string fileName)
|
||||
{
|
||||
FileName = fileName;
|
||||
using (var fs = new FileStream(FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
{
|
||||
ParseMxf(fs);
|
||||
}
|
||||
}
|
||||
|
||||
public MxfParser(Stream stream)
|
||||
{
|
||||
FileName = null;
|
||||
ParseMxf(stream);
|
||||
}
|
||||
|
||||
private void ParseMxf(Stream stream)
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
ReadHeaderPartitionPack(stream);
|
||||
if (IsValid)
|
||||
{
|
||||
var length = stream.Length;
|
||||
long next = _startPosition;
|
||||
while (next + 20 < length)
|
||||
{
|
||||
stream.Seek(next, SeekOrigin.Begin);
|
||||
var klv = new KlvPacket(stream);
|
||||
|
||||
//Console.WriteLine();
|
||||
//Console.WriteLine("Key: " + klv.DisplayKey);
|
||||
//Console.WriteLine("Type: " + klv.IdentifyerType);
|
||||
//Console.WriteLine("Total size: " + klv.TotalSize);
|
||||
//Console.WriteLine("Data position: " + klv.DataPosition);
|
||||
//if (klv.IdentifyerType == KeyIdentifier.PartitionPack)
|
||||
// Console.WriteLine("Partition status: " + klv.PartionStatus);
|
||||
|
||||
next += klv.TotalSize;
|
||||
|
||||
if (klv.IdentifierType == KeyIdentifier.EssenceElement &&
|
||||
klv.DataSize < 500000)
|
||||
{
|
||||
stream.Seek(klv.DataPosition, SeekOrigin.Begin);
|
||||
var buffer = new byte[klv.DataSize];
|
||||
stream.Read(buffer, 0, buffer.Length);
|
||||
string s = System.Text.Encoding.UTF8.GetString(buffer);
|
||||
if (IsSubtitle(s))
|
||||
{
|
||||
_subtitleList.Add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsSubtitle(string s)
|
||||
{
|
||||
if (s.Contains("\0"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!s.Contains("xml") && !s.Contains(" --> ") && !s.Contains("00:00"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var list = new List<string>();
|
||||
foreach (string line in s.Replace(Environment.NewLine, "\r").Replace("\n", "\r").Split('\r'))
|
||||
{
|
||||
list.Add(line);
|
||||
}
|
||||
var subtitle = new Subtitle();
|
||||
return subtitle.ReloadLoadSubtitle(list, null) != null;
|
||||
}
|
||||
|
||||
private void ReadHeaderPartitionPack(Stream stream)
|
||||
{
|
||||
IsValid = false;
|
||||
var buffer = new byte[65536];
|
||||
var count = stream.Read(buffer, 0, buffer.Length);
|
||||
if (count < 100)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_startPosition = 0;
|
||||
|
||||
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 && // OID
|
||||
buffer[i + 01] == 0x0E && // payload is 14 bytes
|
||||
buffer[i + 02] == 0x2B && // 0x2B+34 lookup bytes
|
||||
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)
|
||||
{
|
||||
_startPosition = i;
|
||||
IsValid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
namespace Nikse.SubtitleEdit.Core.ContainerFormats.MaterialExchangeFormat
|
||||
{
|
||||
public enum PartitionStatus
|
||||
{
|
||||
Unknown = 0,
|
||||
OpenAndIncomplete = 1,
|
||||
ClosedAndIncomplete = 2,
|
||||
OpenAndComplete = 3,
|
||||
ClosedAndComplete = 4,
|
||||
}
|
||||
}
|
649
libse/ContainerFormats/Matroska/MatroskaFile.cs
Normal file
649
libse/ContainerFormats/Matroska/MatroskaFile.cs
Normal file
@ -0,0 +1,649 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Nikse.Core;
|
||||
using Nikse.SubtitleEdit.Core.ContainerFormats.Ebml;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.ContainerFormats.Matroska
|
||||
{
|
||||
public class MatroskaFile : IDisposable
|
||||
{
|
||||
public delegate void LoadMatroskaCallback(long position, long total);
|
||||
|
||||
private readonly string _path;
|
||||
private readonly FileStream _stream;
|
||||
private readonly bool _valid;
|
||||
private int _pixelWidth, _pixelHeight;
|
||||
private double _frameRate;
|
||||
private string _videoCodecId;
|
||||
|
||||
private int _subtitleRipTrackNumber;
|
||||
private List<MatroskaSubtitle> _subtitleRip = new List<MatroskaSubtitle>();
|
||||
private List<MatroskaTrackInfo> _tracks;
|
||||
|
||||
private readonly Element _segmentElement;
|
||||
private long _timecodeScale = 1000000;
|
||||
private double _duration;
|
||||
|
||||
public MatroskaFile(string path)
|
||||
{
|
||||
_path = path;
|
||||
_stream = new FastFileStream(path);
|
||||
|
||||
// read header
|
||||
var headerElement = ReadElement();
|
||||
if (headerElement != null && headerElement.Id == ElementId.Ebml)
|
||||
{
|
||||
// read segment
|
||||
_stream.Seek(headerElement.DataSize, SeekOrigin.Current);
|
||||
_segmentElement = ReadElement();
|
||||
if (_segmentElement != null && _segmentElement.Id == ElementId.Segment)
|
||||
{
|
||||
_valid = true; // matroska file must start with ebml header and segment
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsValid
|
||||
{
|
||||
get
|
||||
{
|
||||
return _valid;
|
||||
}
|
||||
}
|
||||
|
||||
public string Path
|
||||
{
|
||||
get
|
||||
{
|
||||
return _path;
|
||||
}
|
||||
}
|
||||
|
||||
public List<MatroskaTrackInfo> GetTracks(bool subtitleOnly = false)
|
||||
{
|
||||
ReadSegmentInfoAndTracks();
|
||||
|
||||
if (_tracks == null)
|
||||
return new List<MatroskaTrackInfo>();
|
||||
|
||||
return subtitleOnly
|
||||
? _tracks.Where(t => t.IsSubtitle).ToList()
|
||||
: _tracks;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get first time of track
|
||||
/// </summary>
|
||||
/// <param name="trackNumber">Track number</param>
|
||||
/// <returns>Start time in milliseconds</returns>
|
||||
public long GetTrackStartTime(int trackNumber)
|
||||
{
|
||||
// go to segment
|
||||
_stream.Seek(_segmentElement.DataPosition, SeekOrigin.Begin);
|
||||
|
||||
Element element;
|
||||
while (_stream.Position < _stream.Length && (element = ReadElement()) != null)
|
||||
{
|
||||
switch (element.Id)
|
||||
{
|
||||
case ElementId.Info:
|
||||
ReadInfoElement(element);
|
||||
break;
|
||||
case ElementId.Tracks:
|
||||
ReadTracksElement(element);
|
||||
break;
|
||||
case ElementId.Cluster:
|
||||
return FindTrackStartInCluster(element, trackNumber);
|
||||
}
|
||||
_stream.Seek(element.EndPosition, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private long FindTrackStartInCluster(Element cluster, int targetTrackNumber)
|
||||
{
|
||||
long clusterTimeCode = 0L;
|
||||
long trackStartTime = -1L;
|
||||
bool done = false;
|
||||
|
||||
Element element;
|
||||
while (_stream.Position < cluster.EndPosition && (element = ReadElement()) != null && !done)
|
||||
{
|
||||
switch (element.Id)
|
||||
{
|
||||
case ElementId.None:
|
||||
done = true;
|
||||
break;
|
||||
case ElementId.Timecode:
|
||||
// Absolute timestamp of the cluster (based on TimecodeScale)
|
||||
clusterTimeCode = (long)ReadUInt((int)element.DataSize);
|
||||
break;
|
||||
case ElementId.BlockGroup:
|
||||
ReadBlockGroupElement(element, clusterTimeCode);
|
||||
break;
|
||||
case ElementId.SimpleBlock:
|
||||
var trackNumber = (int)ReadVariableLengthUInt();
|
||||
if (trackNumber == targetTrackNumber)
|
||||
{
|
||||
// Timecode (relative to Cluster timecode, signed int16)
|
||||
trackStartTime = ReadInt16();
|
||||
done = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
_stream.Seek(element.EndPosition, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
return (clusterTimeCode + trackStartTime) * _timecodeScale / 1000000;
|
||||
}
|
||||
|
||||
private void ReadVideoElement(Element videoElement)
|
||||
{
|
||||
Element element;
|
||||
while (_stream.Position < videoElement.EndPosition && (element = ReadElement()) != null)
|
||||
{
|
||||
switch (element.Id)
|
||||
{
|
||||
case ElementId.PixelWidth:
|
||||
_pixelWidth = (int)ReadUInt((int)element.DataSize);
|
||||
break;
|
||||
case ElementId.PixelHeight:
|
||||
_pixelHeight = (int)ReadUInt((int)element.DataSize);
|
||||
break;
|
||||
default:
|
||||
_stream.Seek(element.DataSize, SeekOrigin.Current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadTrackEntryElement(Element trackEntryElement)
|
||||
{
|
||||
long defaultDuration = 0;
|
||||
bool isVideo = false;
|
||||
bool isAudio = false;
|
||||
bool isSubtitle = false;
|
||||
var trackNumber = 0;
|
||||
string name = string.Empty;
|
||||
string language = string.Empty;
|
||||
string codecId = string.Empty;
|
||||
string codecPrivate = string.Empty;
|
||||
//var biCompression = string.Empty;
|
||||
int contentCompressionAlgorithm = -1;
|
||||
int contentEncodingType = -1;
|
||||
|
||||
Element element;
|
||||
while (_stream.Position < trackEntryElement.EndPosition && (element = ReadElement()) != null)
|
||||
{
|
||||
switch (element.Id)
|
||||
{
|
||||
case ElementId.DefaultDuration:
|
||||
defaultDuration = (int)ReadUInt((int)element.DataSize);
|
||||
break;
|
||||
case ElementId.Video:
|
||||
ReadVideoElement(element);
|
||||
isVideo = true;
|
||||
break;
|
||||
case ElementId.Audio:
|
||||
isAudio = true;
|
||||
break;
|
||||
case ElementId.TrackNumber:
|
||||
trackNumber = (int)ReadUInt((int)element.DataSize);
|
||||
break;
|
||||
case ElementId.Name:
|
||||
name = ReadString((int)element.DataSize, Encoding.UTF8);
|
||||
break;
|
||||
case ElementId.Language:
|
||||
language = ReadString((int)element.DataSize, Encoding.ASCII);
|
||||
break;
|
||||
case ElementId.CodecId:
|
||||
codecId = ReadString((int)element.DataSize, Encoding.ASCII);
|
||||
break;
|
||||
case ElementId.TrackType:
|
||||
switch (_stream.ReadByte())
|
||||
{
|
||||
case 1:
|
||||
isVideo = true;
|
||||
break;
|
||||
case 2:
|
||||
isAudio = true;
|
||||
break;
|
||||
case 17:
|
||||
isSubtitle = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ElementId.CodecPrivate:
|
||||
codecPrivate = ReadString((int)element.DataSize, Encoding.UTF8);
|
||||
//if (codecPrivate.Length > 20)
|
||||
// biCompression = codecPrivate.Substring(16, 4);
|
||||
break;
|
||||
case ElementId.ContentEncodings:
|
||||
contentCompressionAlgorithm = 0; // default value
|
||||
contentEncodingType = 0; // default value
|
||||
|
||||
var contentEncodingElement = ReadElement();
|
||||
if (contentEncodingElement != null && contentEncodingElement.Id == ElementId.ContentEncoding)
|
||||
{
|
||||
ReadContentEncodingElement(element, ref contentCompressionAlgorithm, ref contentEncodingType);
|
||||
}
|
||||
break;
|
||||
}
|
||||
_stream.Seek(element.EndPosition, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
_tracks.Add(new MatroskaTrackInfo
|
||||
{
|
||||
TrackNumber = trackNumber,
|
||||
IsVideo = isVideo,
|
||||
IsAudio = isAudio,
|
||||
IsSubtitle = isSubtitle,
|
||||
Language = language,
|
||||
CodecId = codecId,
|
||||
CodecPrivate = codecPrivate,
|
||||
Name = name,
|
||||
ContentEncodingType = contentEncodingType,
|
||||
ContentCompressionAlgorithm = contentCompressionAlgorithm
|
||||
});
|
||||
|
||||
if (isVideo)
|
||||
{
|
||||
if (defaultDuration > 0)
|
||||
{
|
||||
_frameRate = 1.0 / (defaultDuration / 1000000000.0);
|
||||
}
|
||||
_videoCodecId = codecId;
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadContentEncodingElement(Element contentEncodingElement, ref int contentCompressionAlgorithm, ref int contentEncodingType)
|
||||
{
|
||||
Element element;
|
||||
while (_stream.Position < contentEncodingElement.EndPosition && (element = ReadElement()) != null)
|
||||
{
|
||||
switch (element.Id)
|
||||
{
|
||||
case ElementId.ContentEncodingOrder:
|
||||
var contentEncodingOrder = ReadUInt((int)element.DataSize);
|
||||
System.Diagnostics.Debug.WriteLine("ContentEncodingOrder: " + contentEncodingOrder);
|
||||
break;
|
||||
case ElementId.ContentEncodingScope:
|
||||
var contentEncodingScope = ReadUInt((int)element.DataSize);
|
||||
System.Diagnostics.Debug.WriteLine("ContentEncodingScope: " + contentEncodingScope);
|
||||
break;
|
||||
case ElementId.ContentEncodingType:
|
||||
contentEncodingType = (int)ReadUInt((int)element.DataSize);
|
||||
break;
|
||||
case ElementId.ContentCompression:
|
||||
Element compElement;
|
||||
while (_stream.Position < element.EndPosition && (compElement = ReadElement()) != null)
|
||||
{
|
||||
switch (compElement.Id)
|
||||
{
|
||||
case ElementId.ContentCompAlgo:
|
||||
contentCompressionAlgorithm = (int)ReadUInt((int)compElement.DataSize);
|
||||
break;
|
||||
case ElementId.ContentCompSettings:
|
||||
var contentCompSettings = ReadUInt((int)compElement.DataSize);
|
||||
System.Diagnostics.Debug.WriteLine("ContentCompSettings: " + contentCompSettings);
|
||||
break;
|
||||
default:
|
||||
_stream.Seek(element.DataSize, SeekOrigin.Current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
_stream.Seek(element.DataSize, SeekOrigin.Current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadInfoElement(Element infoElement)
|
||||
{
|
||||
Element element;
|
||||
while (_stream.Position < infoElement.EndPosition && (element = ReadElement()) != null)
|
||||
{
|
||||
switch (element.Id)
|
||||
{
|
||||
case ElementId.TimecodeScale:
|
||||
// Timestamp scale in nanoseconds (1.000.000 means all timestamps in the segment are expressed in milliseconds)
|
||||
_timecodeScale = (int)ReadUInt((int)element.DataSize);
|
||||
break;
|
||||
case ElementId.Duration:
|
||||
// Duration of the segment (based on TimecodeScale)
|
||||
_duration = element.DataSize == 4 ? ReadFloat32() : ReadFloat64();
|
||||
_duration /= _timecodeScale * 1000000.0;
|
||||
break;
|
||||
default:
|
||||
_stream.Seek(element.DataSize, SeekOrigin.Current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadTracksElement(Element tracksElement)
|
||||
{
|
||||
_tracks = new List<MatroskaTrackInfo>();
|
||||
|
||||
Element element;
|
||||
while (_stream.Position < tracksElement.EndPosition && (element = ReadElement()) != null)
|
||||
{
|
||||
if (element.Id == ElementId.TrackEntry)
|
||||
{
|
||||
ReadTrackEntryElement(element);
|
||||
}
|
||||
else
|
||||
{
|
||||
_stream.Seek(element.DataSize, SeekOrigin.Current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <param name="duration">Duration of the segment in milliseconds.</param>
|
||||
public void GetInfo(out double frameRate, out int pixelWidth, out int pixelHeight, out double duration, out string videoCodec)
|
||||
{
|
||||
ReadSegmentInfoAndTracks();
|
||||
|
||||
pixelWidth = _pixelWidth;
|
||||
pixelHeight = _pixelHeight;
|
||||
frameRate = _frameRate;
|
||||
duration = _duration;
|
||||
videoCodec = _videoCodecId;
|
||||
}
|
||||
|
||||
private void ReadCluster(Element clusterElement)
|
||||
{
|
||||
long clusterTimeCode = 0;
|
||||
|
||||
Element element;
|
||||
while (_stream.Position < clusterElement.EndPosition && (element = ReadElement()) != null)
|
||||
{
|
||||
switch (element.Id)
|
||||
{
|
||||
case ElementId.Timecode:
|
||||
clusterTimeCode = (long)ReadUInt((int)element.DataSize);
|
||||
break;
|
||||
case ElementId.BlockGroup:
|
||||
ReadBlockGroupElement(element, clusterTimeCode);
|
||||
break;
|
||||
case ElementId.SimpleBlock:
|
||||
var subtitle = ReadSubtitleBlock(element, clusterTimeCode);
|
||||
if (subtitle != null)
|
||||
{
|
||||
_subtitleRip.Add(subtitle);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
_stream.Seek(element.DataSize, SeekOrigin.Current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadBlockGroupElement(Element clusterElement, long clusterTimeCode)
|
||||
{
|
||||
MatroskaSubtitle subtitle = null;
|
||||
|
||||
Element element;
|
||||
while (_stream.Position < clusterElement.EndPosition && (element = ReadElement()) != null)
|
||||
{
|
||||
switch (element.Id)
|
||||
{
|
||||
case ElementId.Block:
|
||||
subtitle = ReadSubtitleBlock(element, clusterTimeCode);
|
||||
if (subtitle == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_subtitleRip.Add(subtitle);
|
||||
break;
|
||||
case ElementId.BlockDuration:
|
||||
var duration = (long)ReadUInt((int)element.DataSize);
|
||||
if (subtitle != null)
|
||||
{
|
||||
subtitle.Duration = duration;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
_stream.Seek(element.DataSize, SeekOrigin.Current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private MatroskaSubtitle ReadSubtitleBlock(Element blockElement, long clusterTimeCode)
|
||||
{
|
||||
var trackNumber = (int)ReadVariableLengthUInt();
|
||||
if (trackNumber != _subtitleRipTrackNumber)
|
||||
{
|
||||
_stream.Seek(blockElement.EndPosition, SeekOrigin.Begin);
|
||||
return null;
|
||||
}
|
||||
|
||||
var timeCode = ReadInt16();
|
||||
|
||||
// lacing
|
||||
var flags = (byte)_stream.ReadByte();
|
||||
int frames;
|
||||
switch (flags & 6)
|
||||
{
|
||||
case 0: // 00000000 = No lacing
|
||||
System.Diagnostics.Debug.Print("No lacing");
|
||||
break;
|
||||
case 2: // 00000010 = Xiph lacing
|
||||
frames = _stream.ReadByte() + 1;
|
||||
System.Diagnostics.Debug.Print("Xiph lacing ({0} frames)", frames);
|
||||
break;
|
||||
case 4: // 00000100 = Fixed-size lacing
|
||||
frames = _stream.ReadByte() + 1;
|
||||
for (var i = 0; i < frames; i++)
|
||||
{
|
||||
_stream.ReadByte(); // frames
|
||||
}
|
||||
System.Diagnostics.Debug.Print("Fixed-size lacing ({0} frames)", frames);
|
||||
break;
|
||||
case 6: // 00000110 = EMBL lacing
|
||||
frames = _stream.ReadByte() + 1;
|
||||
System.Diagnostics.Debug.Print("EBML lacing ({0} frames)", frames);
|
||||
break;
|
||||
}
|
||||
|
||||
// save subtitle data
|
||||
var dataLength = (int)(blockElement.EndPosition - _stream.Position);
|
||||
var data = new byte[dataLength];
|
||||
_stream.Read(data, 0, dataLength);
|
||||
|
||||
return new MatroskaSubtitle(data, clusterTimeCode + timeCode);
|
||||
}
|
||||
|
||||
public List<MatroskaSubtitle> GetSubtitle(int trackNumber, LoadMatroskaCallback progressCallback)
|
||||
{
|
||||
_subtitleRipTrackNumber = trackNumber;
|
||||
ReadSegmentCluster(progressCallback);
|
||||
return _subtitleRip;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_stream != null)
|
||||
{
|
||||
_stream.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadSegmentInfoAndTracks()
|
||||
{
|
||||
// go to segment
|
||||
_stream.Seek(_segmentElement.DataPosition, SeekOrigin.Begin);
|
||||
|
||||
Element element;
|
||||
while (_stream.Position < _segmentElement.EndPosition && (element = ReadElement()) != null)
|
||||
{
|
||||
switch (element.Id)
|
||||
{
|
||||
case ElementId.Info:
|
||||
ReadInfoElement(element);
|
||||
break;
|
||||
case ElementId.Tracks:
|
||||
ReadTracksElement(element);
|
||||
return;
|
||||
default:
|
||||
_stream.Seek(element.DataSize, SeekOrigin.Current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadSegmentCluster(LoadMatroskaCallback progressCallback)
|
||||
{
|
||||
// go to segment
|
||||
_stream.Seek(_segmentElement.DataPosition, SeekOrigin.Begin);
|
||||
|
||||
Element element;
|
||||
while (_stream.Position < _segmentElement.EndPosition && (element = ReadElement()) != null)
|
||||
{
|
||||
if (element.Id == ElementId.Cluster)
|
||||
{
|
||||
ReadCluster(element);
|
||||
}
|
||||
else
|
||||
{
|
||||
_stream.Seek(element.DataSize, SeekOrigin.Current);
|
||||
}
|
||||
|
||||
if (progressCallback != null)
|
||||
{
|
||||
progressCallback.Invoke(element.EndPosition, _stream.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Element ReadElement()
|
||||
{
|
||||
var id = (ElementId)ReadVariableLengthUInt(false);
|
||||
if (id <= ElementId.None)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var size = (long)ReadVariableLengthUInt();
|
||||
return new Element(id, _stream.Position, size);
|
||||
}
|
||||
|
||||
private ulong ReadVariableLengthUInt(bool unsetFirstBit = true)
|
||||
{
|
||||
// Begin loop with byte set to newly read byte
|
||||
var first = _stream.ReadByte();
|
||||
var length = 0;
|
||||
|
||||
// Begin by counting the bits unset before the highest set bit
|
||||
var mask = 0x80;
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
// Start at left, shift to right
|
||||
if ((first & mask) == mask)
|
||||
{
|
||||
length = i + 1;
|
||||
break;
|
||||
}
|
||||
mask >>= 1;
|
||||
}
|
||||
if (length == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read remaining big endian bytes and convert to 64-bit unsigned integer.
|
||||
var result = (ulong)(unsetFirstBit ? first & (0xFF >> length) : first);
|
||||
result <<= --length * 8;
|
||||
for (var i = 1; i <= length; i++)
|
||||
{
|
||||
result |= (ulong)_stream.ReadByte() << (length - i) * 8;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a fixed length unsigned integer from the current stream and advances the current
|
||||
/// position of the stream by the integer length in bytes.
|
||||
/// </summary>
|
||||
/// <param name="length">The length in bytes of the integer.</param>
|
||||
/// <returns>A 64-bit unsigned integer.</returns>
|
||||
private ulong ReadUInt(int length)
|
||||
{
|
||||
var data = new byte[length];
|
||||
_stream.Read(data, 0, length);
|
||||
|
||||
// Convert the big endian byte array to a 64-bit unsigned integer.
|
||||
var result = 0UL;
|
||||
var shift = 0;
|
||||
for (var i = length - 1; i >= 0; i--)
|
||||
{
|
||||
result |= (ulong)data[i] << shift;
|
||||
shift += 8;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 2-byte signed integer from the current stream and advances the current position
|
||||
/// of the stream by two bytes.
|
||||
/// </summary>
|
||||
/// <returns>A 2-byte signed integer read from the current stream.</returns>
|
||||
private short ReadInt16()
|
||||
{
|
||||
var data = new byte[2];
|
||||
_stream.Read(data, 0, 2);
|
||||
return (short)(data[0] << 8 | data[1]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 4-byte floating point value from the current stream and advances the current
|
||||
/// position of the stream by four bytes.
|
||||
/// </summary>
|
||||
/// <returns>A 4-byte floating point value read from the current stream.</returns>
|
||||
private unsafe float ReadFloat32()
|
||||
{
|
||||
var data = new byte[4];
|
||||
_stream.Read(data, 0, 4);
|
||||
|
||||
var result = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
|
||||
return *(float*)&result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 8-byte floating point value from the current stream and advances the current
|
||||
/// position of the stream by eight bytes.
|
||||
/// </summary>
|
||||
/// <returns>A 8-byte floating point value read from the current stream.</returns>
|
||||
private unsafe double ReadFloat64()
|
||||
{
|
||||
var data = new byte[8];
|
||||
_stream.Read(data, 0, 8);
|
||||
|
||||
var lo = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
|
||||
var hi = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7];
|
||||
var result = (uint)hi | (long)lo << 32;
|
||||
return *(double*)&result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a fixed length string from the current stream using the specified encoding.
|
||||
/// </summary>
|
||||
/// <param name="length">The length in bytes of the string.</param>
|
||||
/// <param name="encoding">The encoding of the string.</param>
|
||||
/// <returns>The string being read.</returns>
|
||||
private string ReadString(int length, Encoding encoding)
|
||||
{
|
||||
var buffer = new byte[length];
|
||||
_stream.Read(buffer, 0, length);
|
||||
return encoding.GetString(buffer);
|
||||
}
|
||||
}
|
||||
}
|
41
libse/ContainerFormats/Matroska/MatroskaSubtitle.cs
Normal file
41
libse/ContainerFormats/Matroska/MatroskaSubtitle.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using System;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.ContainerFormats.Matroska
|
||||
{
|
||||
public class MatroskaSubtitle
|
||||
{
|
||||
public byte[] Data { get; set; }
|
||||
public long Start { get; set; }
|
||||
public long Duration { get; set; }
|
||||
|
||||
public MatroskaSubtitle(byte[] data, long start, long duration)
|
||||
{
|
||||
Data = data;
|
||||
Start = start;
|
||||
Duration = duration;
|
||||
}
|
||||
|
||||
public MatroskaSubtitle(byte[] data, long start)
|
||||
: this(data, start, 0)
|
||||
{
|
||||
}
|
||||
|
||||
public long End
|
||||
{
|
||||
get
|
||||
{
|
||||
return Start + Duration;
|
||||
}
|
||||
}
|
||||
|
||||
public string Text
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Data != null)
|
||||
return System.Text.Encoding.UTF8.GetString(Data).Replace("\\N", Environment.NewLine);
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
19
libse/ContainerFormats/Matroska/MatroskaTrackInfo.cs
Normal file
19
libse/ContainerFormats/Matroska/MatroskaTrackInfo.cs
Normal file
@ -0,0 +1,19 @@
|
||||
namespace Nikse.SubtitleEdit.Core.ContainerFormats.Matroska
|
||||
{
|
||||
public class MatroskaTrackInfo
|
||||
{
|
||||
public int TrackNumber { get; set; }
|
||||
public string Uid { get; set; }
|
||||
public bool IsVideo { get; set; }
|
||||
public bool IsAudio { get; set; }
|
||||
public bool IsSubtitle { get; set; }
|
||||
public string CodecId { get; set; }
|
||||
public string CodecPrivate { get; set; }
|
||||
public int DefaultDuration { get; set; }
|
||||
public string Language { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
public int ContentCompressionAlgorithm { get; set; }
|
||||
public int ContentEncodingType { get; set; }
|
||||
}
|
||||
}
|
82
libse/ContainerFormats/Mp4/Boxes/Box.cs
Normal file
82
libse/ContainerFormats/Mp4/Boxes/Box.cs
Normal file
@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.ContainerFormats.Mp4.Boxes
|
||||
{
|
||||
public class Box
|
||||
{
|
||||
public byte[] Buffer;
|
||||
public ulong Position;
|
||||
public string Name;
|
||||
public UInt64 Size;
|
||||
|
||||
public static uint GetUInt(byte[] buffer, int index)
|
||||
{
|
||||
return (uint)((buffer[index] << 24) + (buffer[index + 1] << 16) + (buffer[index + 2] << 8) + buffer[index + 3]);
|
||||
}
|
||||
|
||||
public uint GetUInt(int index)
|
||||
{
|
||||
return (uint)((Buffer[index] << 24) + (Buffer[index + 1] << 16) + (Buffer[index + 2] << 8) + Buffer[index + 3]);
|
||||
}
|
||||
|
||||
public UInt64 GetUInt64(int index)
|
||||
{
|
||||
return (UInt64)Buffer[index] << 56 | (UInt64)Buffer[index + 1] << 48 | (UInt64)Buffer[index + 2] << 40 | (UInt64)Buffer[index + 3] << 32 |
|
||||
(UInt64)Buffer[index + 4] << 24 | (UInt64)Buffer[index + 5] << 16 | (UInt64)Buffer[index + 6] << 8 | Buffer[index + 7];
|
||||
}
|
||||
|
||||
public static UInt64 GetUInt64(byte[] buffer, int index)
|
||||
{
|
||||
return (UInt64)buffer[index] << 56 | (UInt64)buffer[index + 1] << 48 | (UInt64)buffer[index + 2] << 40 | (UInt64)buffer[index + 3] << 32 |
|
||||
(UInt64)buffer[index + 4] << 24 | (UInt64)buffer[index + 5] << 16 | (UInt64)buffer[index + 6] << 8 | buffer[index + 7];
|
||||
}
|
||||
|
||||
public static int GetWord(byte[] buffer, int index)
|
||||
{
|
||||
return (buffer[index] << 8) + buffer[index + 1];
|
||||
}
|
||||
|
||||
public int GetWord(int index)
|
||||
{
|
||||
return (Buffer[index] << 8) + Buffer[index + 1];
|
||||
}
|
||||
|
||||
public string GetString(int index, int count)
|
||||
{
|
||||
return Encoding.UTF8.GetString(Buffer, index, count);
|
||||
}
|
||||
|
||||
public static string GetString(byte[] buffer, int index, int count)
|
||||
{
|
||||
if (count <= 0)
|
||||
return string.Empty;
|
||||
return Encoding.UTF8.GetString(buffer, index, count);
|
||||
}
|
||||
|
||||
internal bool InitializeSizeAndName(System.IO.FileStream fs)
|
||||
{
|
||||
Buffer = new byte[8];
|
||||
var bytesRead = fs.Read(Buffer, 0, Buffer.Length);
|
||||
if (bytesRead < Buffer.Length)
|
||||
return false;
|
||||
Size = GetUInt(0);
|
||||
Name = GetString(4, 4);
|
||||
|
||||
if (Size == 0)
|
||||
{
|
||||
Size = (UInt64)(fs.Length - fs.Position);
|
||||
}
|
||||
if (Size == 1)
|
||||
{
|
||||
bytesRead = fs.Read(Buffer, 0, Buffer.Length);
|
||||
if (bytesRead < Buffer.Length)
|
||||
return false;
|
||||
Size = GetUInt64(0) - 8;
|
||||
}
|
||||
Position = ((ulong)(fs.Position)) + Size - 8;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
489
libse/ContainerFormats/Mp4/Boxes/Mdhd.cs
Normal file
489
libse/ContainerFormats/Mp4/Boxes/Mdhd.cs
Normal file
@ -0,0 +1,489 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.ContainerFormats.Mp4.Boxes
|
||||
{
|
||||
public class Mdhd : Box
|
||||
{
|
||||
|
||||
public readonly UInt64 CreationTime;
|
||||
public readonly UInt64 ModificationTime;
|
||||
public readonly UInt32 TimeScale;
|
||||
public readonly UInt64 Duration;
|
||||
public readonly string Iso639ThreeLetterCode;
|
||||
public readonly int Quality;
|
||||
|
||||
public Mdhd(FileStream fs, ulong size)
|
||||
{
|
||||
Buffer = new byte[size - 4];
|
||||
fs.Read(Buffer, 0, Buffer.Length);
|
||||
int languageIndex = 20;
|
||||
int version = Buffer[0];
|
||||
if (version == 0)
|
||||
{
|
||||
CreationTime = GetUInt(4);
|
||||
ModificationTime = GetUInt(8);
|
||||
TimeScale = GetUInt(12);
|
||||
Duration = GetUInt(16);
|
||||
Quality = GetWord(22);
|
||||
}
|
||||
else
|
||||
{
|
||||
CreationTime = GetUInt64(4);
|
||||
ModificationTime = GetUInt64(12);
|
||||
TimeScale = GetUInt(16);
|
||||
Duration = GetUInt64(20);
|
||||
languageIndex = 24;
|
||||
Quality = GetWord(26);
|
||||
}
|
||||
|
||||
// language code = skip first byte, 5 bytes + 5 bytes + 5 bytes (add 0x60 to get ascii value)
|
||||
int languageByte = ((Buffer[languageIndex] << 1) >> 3) + 0x60;
|
||||
int languageByte2 = ((Buffer[languageIndex] & 0x3) << 3) + (Buffer[languageIndex + 1] >> 5) + 0x60;
|
||||
int languageByte3 = (Buffer[languageIndex + 1] & 0x1f) + 0x60;
|
||||
char x = (char)languageByte;
|
||||
char x2 = (char)languageByte2;
|
||||
char x3 = (char)languageByte3;
|
||||
Iso639ThreeLetterCode = x.ToString(CultureInfo.InvariantCulture) + x2.ToString(CultureInfo.InvariantCulture) + x3.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
public string LanguageString
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (Iso639ThreeLetterCode)
|
||||
{
|
||||
case ("abk"): return "Abkhazian";
|
||||
case ("ace"): return "Achinese";
|
||||
case ("ach"): return "Acoli";
|
||||
case ("ada"): return "Adangme";
|
||||
case ("aar"): return "Afar";
|
||||
case ("afh"): return "Afrihili";
|
||||
case ("afr"): return "Afrikaans";
|
||||
case ("afa"): return "Afro-Asiatic (Other)";
|
||||
case ("aka"): return "Akan";
|
||||
case ("akk"): return "Akkadian";
|
||||
case ("alb"): return "Albanian";
|
||||
case ("sqi"): return "Albanian";
|
||||
case ("ale"): return "Aleut";
|
||||
case ("alg"): return "Algonquian languages";
|
||||
case ("tut"): return "Altaic (Other)";
|
||||
case ("amh"): return "Amharic";
|
||||
case ("apa"): return "Apache languages";
|
||||
case ("ara"): return "Arabic";
|
||||
case ("arc"): return "Aramaic";
|
||||
case ("arg"): return "Arabic";
|
||||
case ("arp"): return "Arapaho";
|
||||
case ("arn"): return "Araucanian";
|
||||
case ("arw"): return "Arawak";
|
||||
case ("arm"): return "Armenian";
|
||||
case ("hye"): return "Armenian";
|
||||
case ("art"): return "Artificial (Other)";
|
||||
case ("asm"): return "Assamese";
|
||||
case ("ava"): return "Avaric";
|
||||
case ("ath"): return "Athapascan languages";
|
||||
case ("ave"): return "Avestan";
|
||||
case ("awa"): return "Awadhi";
|
||||
case ("aym"): return "Aymara";
|
||||
case ("aze"): return "Azerbaijani";
|
||||
case ("nah"): return "Aztec";
|
||||
case ("ban"): return "Balinese";
|
||||
case ("bat"): return "Baltic (Other)";
|
||||
case ("bal"): return "Baluchi";
|
||||
case ("bam"): return "Bambara";
|
||||
case ("bai"): return "Bamileke languages";
|
||||
case ("bad"): return "Banda";
|
||||
case ("bnt"): return "Bantu (Other)";
|
||||
case ("bas"): return "Basa";
|
||||
case ("bak"): return "Bashkir";
|
||||
case ("baq"): return "Basque";
|
||||
case ("eus"): return "Basque";
|
||||
case ("bej"): return "Beja";
|
||||
case ("bem"): return "Bemba";
|
||||
case ("ben"): return "Bengali";
|
||||
case ("ber"): return "Berber (Other)";
|
||||
case ("bho"): return "Bhojpuri";
|
||||
case ("bih"): return "Bihari";
|
||||
case ("bik"): return "Bikol";
|
||||
case ("bin"): return "Bini";
|
||||
case ("bis"): return "Bislama";
|
||||
case ("bra"): return "Braj";
|
||||
case ("bre"): return "Breton";
|
||||
case ("bug"): return "Buginese";
|
||||
case ("bul"): return "Bulgarian";
|
||||
case ("bua"): return "Buriat";
|
||||
case ("bur"): return "Burmese";
|
||||
case ("mya"): return "Burmese";
|
||||
case ("bel"): return "Byelorussian";
|
||||
case ("cad"): return "Caddo";
|
||||
case ("car"): return "Carib";
|
||||
case ("cat"): return "Catalan";
|
||||
case ("cau"): return "Caucasian (Other)";
|
||||
case ("ceb"): return "Cebuano";
|
||||
case ("cel"): return "Celtic (Other)";
|
||||
case ("cai"): return "Central American Indian (Other)";
|
||||
case ("chg"): return "Chagatai";
|
||||
case ("cha"): return "Chamorro";
|
||||
case ("che"): return "Chechen";
|
||||
case ("chr"): return "Cherokee";
|
||||
case ("chy"): return "Cheyenne";
|
||||
case ("chb"): return "Chibcha";
|
||||
case ("chi"): return "Chinese";
|
||||
case ("zho"): return "Chinese";
|
||||
case ("chn"): return "Chinook jargon";
|
||||
case ("cho"): return "Choctaw";
|
||||
case ("chu"): return "Church Slavic";
|
||||
case ("chv"): return "Chuvash";
|
||||
case ("cop"): return "Coptic";
|
||||
case ("cor"): return "Cornish";
|
||||
case ("cos"): return "Corsican";
|
||||
case ("cre"): return "Cree";
|
||||
case ("mus"): return "Creek";
|
||||
case ("crp"): return "Creoles and Pidgins (Other)";
|
||||
case ("cpe"): return "Creoles and Pidgins, English-based (Other)";
|
||||
case ("cpf"): return "Creoles and Pidgins, French-based (Other)";
|
||||
case ("cpp"): return "Creoles and Pidgins, Portuguese-based (Other)";
|
||||
case ("cus"): return "Cushitic (Other)";
|
||||
case (" "): return "Croatian";
|
||||
case ("ces"): return "Czech";
|
||||
case ("cze"): return "Czech";
|
||||
case ("dak"): return "Dakota";
|
||||
case ("dan"): return "Danish";
|
||||
case ("del"): return "Delaware";
|
||||
case ("din"): return "Dinka";
|
||||
case ("div"): return "Divehi";
|
||||
case ("doi"): return "Dogri";
|
||||
case ("dra"): return "Dravidian (Other)";
|
||||
case ("dua"): return "Duala";
|
||||
case ("dut"): return "Dutch";
|
||||
case ("nla"): return "Dutch";
|
||||
case ("dum"): return "Dutch, Middle (ca. 1050-1350)";
|
||||
case ("dyu"): return "Dyula";
|
||||
case ("dzo"): return "Dzongkha";
|
||||
case ("efi"): return "Efik";
|
||||
case ("egy"): return "Egyptian (Ancient)";
|
||||
case ("eka"): return "Ekajuk";
|
||||
case ("elx"): return "Elamite";
|
||||
case ("eng"): return "English";
|
||||
case ("enm"): return "English, Middle (ca. 1100-1500)";
|
||||
case ("ang"): return "English, Old (ca. 450-1100)";
|
||||
case ("esk"): return "Eskimo (Other)";
|
||||
case ("epo"): return "Esperanto";
|
||||
case ("est"): return "Estonian";
|
||||
case ("ewe"): return "Ewe";
|
||||
case ("ewo"): return "Ewondo";
|
||||
case ("fan"): return "Fang";
|
||||
case ("fat"): return "Fanti";
|
||||
case ("fao"): return "Faroese";
|
||||
case ("fij"): return "Fijian";
|
||||
case ("fin"): return "Finnish";
|
||||
case ("fiu"): return "Finno-Ugrian (Other)";
|
||||
case ("fon"): return "Fon";
|
||||
case ("fra"): return "French";
|
||||
case ("fre"): return "French";
|
||||
case ("frm"): return "French, Middle (ca. 1400-1600)";
|
||||
case ("fro"): return "French, Old (842- ca. 1400)";
|
||||
case ("fry"): return "Frisian";
|
||||
case ("ful"): return "Fulah";
|
||||
case ("gaa"): return "Ga";
|
||||
case ("gae"): return "Gaelic (Scots)";
|
||||
case ("gdh"): return "Gaelic (Scots)";
|
||||
case ("glg"): return "Gallegan";
|
||||
case ("lug"): return "Ganda";
|
||||
case ("gay"): return "Gayo";
|
||||
case ("gez"): return "Geez";
|
||||
case ("geo"): return "Georgian";
|
||||
case ("kat"): return "Georgian";
|
||||
case ("deu"): return "German";
|
||||
case ("ger"): return "German";
|
||||
case ("gmh"): return "German, Middle High (ca. 1050-1500)";
|
||||
case ("goh"): return "German, Old High (ca. 750-1050)";
|
||||
case ("gem"): return "Germanic (Other)";
|
||||
case ("gil"): return "Gilbertese";
|
||||
case ("gon"): return "Gondi";
|
||||
case ("got"): return "Gothic";
|
||||
case ("grb"): return "Grebo";
|
||||
case ("grc"): return "Greek, Ancient (to 1453)";
|
||||
case ("ell"): return "Greek, Modern (1453-)";
|
||||
case ("gre"): return "Greek, Modern (1453-)";
|
||||
case ("kal"): return "Greenlandic";
|
||||
case ("grn"): return "Guarani";
|
||||
case ("guj"): return "Gujarati";
|
||||
case ("hai"): return "Haida";
|
||||
case ("hau"): return "Hausa";
|
||||
case ("haw"): return "Hawaiian";
|
||||
case ("heb"): return "Hebrew";
|
||||
case ("her"): return "Herero";
|
||||
case ("hil"): return "Hiligaynon";
|
||||
case ("him"): return "Himachali";
|
||||
case ("hin"): return "Hindi";
|
||||
case ("hmo"): return "Hiri Motu";
|
||||
case ("hun"): return "Hungarian";
|
||||
case ("hup"): return "Hupa";
|
||||
case ("iba"): return "Iban";
|
||||
case ("ice"): return "Icelandic";
|
||||
case ("ibo"): return "Igbo";
|
||||
case ("ijo"): return "Ijo";
|
||||
case ("ilo"): return "Iloko";
|
||||
case ("inc"): return "Indic (Other)";
|
||||
case ("ine"): return "Indo-European (Other)";
|
||||
case ("ind"): return "Indonesian";
|
||||
case ("ina"): return "Interlingua (International Auxiliary language Association)";
|
||||
// case ("ine"): return "Interlingue";
|
||||
case ("iku"): return "Inuktitut";
|
||||
case ("ipk"): return "Inupiak";
|
||||
case ("ira"): return "Iranian (Other)";
|
||||
case ("gai"): return "Irish";
|
||||
case ("iri"): return "Irish";
|
||||
case ("sga"): return "Irish, Old (to 900)";
|
||||
case ("mga"): return "Irish, Middle (900 - 1200)";
|
||||
case ("iro"): return "Iroquoian languages";
|
||||
case ("ita"): return "Italian";
|
||||
case ("jpn"): return "Japanese";
|
||||
case ("jav"): return "Javanese";
|
||||
case ("jaw"): return "Javanese";
|
||||
case ("jrb"): return "Judeo-Arabic";
|
||||
case ("jpr"): return "Judeo-Persian";
|
||||
case ("kab"): return "Kabyle";
|
||||
case ("kac"): return "Kachin";
|
||||
case ("kam"): return "Kamba";
|
||||
case ("kan"): return "Kannada";
|
||||
case ("kau"): return "Kanuri";
|
||||
case ("kaa"): return "Kara-Kalpak";
|
||||
case ("kar"): return "Karen";
|
||||
case ("kas"): return "Kashmiri";
|
||||
case ("kaw"): return "Kawi";
|
||||
case ("kaz"): return "Kazakh";
|
||||
case ("kha"): return "Khasi";
|
||||
case ("khm"): return "Khmer";
|
||||
case ("khi"): return "Khoisan (Other)";
|
||||
case ("kho"): return "Khotanese";
|
||||
case ("kik"): return "Kikuyu";
|
||||
case ("kin"): return "Kinyarwanda";
|
||||
case ("kir"): return "Kirghiz";
|
||||
case ("kom"): return "Komi";
|
||||
case ("kon"): return "Kongo";
|
||||
case ("kok"): return "Konkani";
|
||||
case ("kor"): return "Korean";
|
||||
case ("kpe"): return "Kpelle";
|
||||
case ("kro"): return "Kru";
|
||||
case ("kua"): return "Kuanyama";
|
||||
case ("kum"): return "Kumyk";
|
||||
case ("kur"): return "Kurdish";
|
||||
case ("kru"): return "Kurukh";
|
||||
case ("kus"): return "Kusaie";
|
||||
case ("kut"): return "Kutenai";
|
||||
case ("lad"): return "Ladino";
|
||||
case ("lah"): return "Lahnda";
|
||||
case ("lam"): return "Lamba";
|
||||
case ("oci"): return "Langue d'Oc (post 1500)";
|
||||
case ("lao"): return "Lao";
|
||||
case ("lat"): return "Latin";
|
||||
case ("lav"): return "Latvian";
|
||||
case ("ltz"): return "Letzeburgesch";
|
||||
case ("lez"): return "Lezghian";
|
||||
case ("lin"): return "Lingala";
|
||||
case ("lit"): return "Lithuanian";
|
||||
case ("loz"): return "Lozi";
|
||||
case ("lub"): return "Luba-Katanga";
|
||||
case ("lui"): return "Luiseno";
|
||||
case ("lun"): return "Lunda";
|
||||
case ("luo"): return "Luo (Kenya and Tanzania)";
|
||||
case ("mac"): return "Macedonian";
|
||||
case ("mad"): return "Madurese";
|
||||
case ("mag"): return "Magahi";
|
||||
case ("mai"): return "Maithili";
|
||||
case ("mak"): return "Makasar";
|
||||
case ("mlg"): return "Malagasy";
|
||||
case ("may"): return "Malay";
|
||||
case ("msa"): return "Malay";
|
||||
case ("mal"): return "Malayalam";
|
||||
case ("mlt"): return "Maltese";
|
||||
case ("man"): return "Mandingo";
|
||||
case ("mni"): return "Manipuri";
|
||||
case ("mno"): return "Manobo languages";
|
||||
case ("max"): return "Manx";
|
||||
case ("mao"): return "Maori";
|
||||
case ("mri"): return "Maori";
|
||||
case ("mar"): return "Marathi";
|
||||
case ("chm"): return "Mari";
|
||||
case ("mah"): return "Marshall";
|
||||
case ("mwr"): return "Marwari";
|
||||
case ("mas"): return "Masai";
|
||||
case ("myn"): return "Mayan languages";
|
||||
case ("men"): return "Mende";
|
||||
case ("mic"): return "Micmac";
|
||||
case ("min"): return "Minangkabau";
|
||||
case ("mis"): return "Miscellaneous (Other)";
|
||||
case ("moh"): return "Mohawk";
|
||||
case ("mol"): return "Moldavian";
|
||||
case ("mkh"): return "Mon-Kmer (Other)";
|
||||
case ("lol"): return "Mongo";
|
||||
case ("mon"): return "Mongolian";
|
||||
case ("mos"): return "Mossi";
|
||||
case ("mul"): return "Multiple languages";
|
||||
case ("mun"): return "Munda languages";
|
||||
case ("nau"): return "Nauru";
|
||||
case ("nav"): return "Navajo";
|
||||
case ("nde"): return "Ndebele, North";
|
||||
case ("nbl"): return "Ndebele, South";
|
||||
case ("ndo"): return "Ndongo";
|
||||
case ("nep"): return "Nepali";
|
||||
case ("new"): return "Newari";
|
||||
case ("nic"): return "Niger-Kordofanian (Other)";
|
||||
case ("ssa"): return "Nilo-Saharan (Other)";
|
||||
case ("niu"): return "Niuean";
|
||||
case ("non"): return "Norse, Old";
|
||||
case ("nai"): return "North American Indian (Other)";
|
||||
case ("nor"): return "Norwegian";
|
||||
case ("nob"): return "Norwegian (Bokmål)";
|
||||
case ("nno"): return "Norwegian (Nynorsk)";
|
||||
case ("nub"): return "Nubian languages";
|
||||
case ("nym"): return "Nyamwezi";
|
||||
case ("nya"): return "Nyanja";
|
||||
case ("nyn"): return "Nyankole";
|
||||
case ("nyo"): return "Nyoro";
|
||||
case ("nzi"): return "Nzima";
|
||||
case ("oji"): return "Ojibwa";
|
||||
case ("ori"): return "Oriya";
|
||||
case ("orm"): return "Oromo";
|
||||
case ("osa"): return "Osage";
|
||||
case ("oss"): return "Ossetic";
|
||||
case ("oto"): return "Otomian languages";
|
||||
case ("pal"): return "Pahlavi";
|
||||
case ("pau"): return "Palauan";
|
||||
case ("pli"): return "Pali";
|
||||
case ("pam"): return "Pampanga";
|
||||
case ("pag"): return "Pangasinan";
|
||||
case ("pan"): return "Panjabi";
|
||||
case ("pap"): return "Papiamento";
|
||||
case ("paa"): return "Papuan-Australian (Other)";
|
||||
case ("fas"): return "Persian";
|
||||
case ("per"): return "Persian";
|
||||
case ("peo"): return "Persian, Old (ca 600 - 400 B.C.)";
|
||||
case ("phn"): return "Phoenician";
|
||||
case ("pol"): return "Polish";
|
||||
case ("pon"): return "Ponape";
|
||||
case ("por"): return "Portuguese";
|
||||
case ("pra"): return "Prakrit languages";
|
||||
case ("pro"): return "Provencal, Old (to 1500)";
|
||||
case ("pus"): return "Pushto";
|
||||
case ("que"): return "Quechua";
|
||||
case ("roh"): return "Rhaeto-Romance";
|
||||
case ("raj"): return "Rajasthani";
|
||||
case ("rar"): return "Rarotongan";
|
||||
case ("roa"): return "Romance (Other)";
|
||||
case ("ron"): return "Romanian";
|
||||
case ("rum"): return "Romanian";
|
||||
case ("rom"): return "Romany";
|
||||
case ("run"): return "Rundi";
|
||||
case ("rus"): return "Russian";
|
||||
case ("sal"): return "Salishan languages";
|
||||
case ("sam"): return "Samaritan Aramaic";
|
||||
case ("smi"): return "Sami languages";
|
||||
case ("smo"): return "Samoan";
|
||||
case ("sad"): return "Sandawe";
|
||||
case ("sag"): return "Sango";
|
||||
case ("san"): return "Sanskrit";
|
||||
case ("srd"): return "Sardinian";
|
||||
case ("sco"): return "Scots";
|
||||
case ("sel"): return "Selkup";
|
||||
case ("sem"): return "Semitic (Other)";
|
||||
case ("srp"): return "Serbian";
|
||||
case ("scr"): return "Serbo-Croatian";
|
||||
case ("srr"): return "Serer";
|
||||
case ("shn"): return "Shan";
|
||||
case ("sna"): return "Shona";
|
||||
case ("sid"): return "Sidamo";
|
||||
case ("bla"): return "Siksika";
|
||||
case ("snd"): return "Sindhi";
|
||||
case ("sin"): return "Singhalese";
|
||||
case ("sit"): return "Sino-Tibetan (Other)";
|
||||
case ("sio"): return "Siouan languages";
|
||||
case ("sla"): return "Slavic (Other)";
|
||||
//case ("ssw"): return "Siswant";
|
||||
case ("slk"): return "Slovak";
|
||||
case ("slv"): return "Slovenian";
|
||||
case ("sog"): return "Sogdian";
|
||||
case ("som"): return "Somali";
|
||||
case ("son"): return "Songhai";
|
||||
case ("wen"): return "Sorbian languages";
|
||||
case ("nso"): return "Sotho, Northern";
|
||||
case ("sot"): return "Sotho, Southern";
|
||||
case ("sai"): return "South American Indian (Other)";
|
||||
case ("esl"): return "Spanish";
|
||||
case ("spa"): return "Spanish";
|
||||
case ("suk"): return "Sukuma";
|
||||
case ("sux"): return "Sumerian";
|
||||
case ("sun"): return "Sudanese";
|
||||
case ("sus"): return "Susu";
|
||||
case ("swa"): return "Swahili";
|
||||
case ("ssw"): return "Swazi";
|
||||
case ("sve"): return "Swedish";
|
||||
case ("swe"): return "Swedish";
|
||||
case ("syr"): return "Syriac";
|
||||
case ("tgl"): return "Tagalog";
|
||||
case ("tah"): return "Tahitian";
|
||||
case ("tgk"): return "Tajik";
|
||||
case ("tmh"): return "Tamashek";
|
||||
case ("tam"): return "Tamil";
|
||||
case ("tat"): return "Tatar";
|
||||
case ("tel"): return "Telugu";
|
||||
case ("ter"): return "Tereno";
|
||||
case ("tha"): return "Thai";
|
||||
case ("bod"): return "Tibetan";
|
||||
case ("tib"): return "Tibetan";
|
||||
case ("tig"): return "Tigre";
|
||||
case ("tir"): return "Tigrinya";
|
||||
case ("tem"): return "Timne";
|
||||
case ("tiv"): return "Tivi";
|
||||
case ("tli"): return "Tlingit";
|
||||
case ("tog"): return "Tonga (Nyasa)";
|
||||
case ("ton"): return "Tonga (Tonga Islands)";
|
||||
case ("tru"): return "Truk";
|
||||
case ("tsi"): return "Tsimshian";
|
||||
case ("tso"): return "Tsonga";
|
||||
case ("tsn"): return "Tswana";
|
||||
case ("tum"): return "Tumbuka";
|
||||
case ("tur"): return "Turkish";
|
||||
case ("ota"): return "Turkish, Ottoman (1500 - 1928)";
|
||||
case ("tuk"): return "Turkmen";
|
||||
case ("tyv"): return "Tuvinian";
|
||||
case ("twi"): return "Twi";
|
||||
case ("uga"): return "Ugaritic";
|
||||
case ("uig"): return "Uighur";
|
||||
case ("ukr"): return "Ukrainian";
|
||||
case ("umb"): return "Umbundu";
|
||||
case ("und"): return "Undetermined";
|
||||
case ("urd"): return "Urdu";
|
||||
case ("uzb"): return "Uzbek";
|
||||
case ("vai"): return "Vai";
|
||||
case ("ven"): return "Venda";
|
||||
case ("vie"): return "Vietnamese";
|
||||
case ("vol"): return "Volapük";
|
||||
case ("vot"): return "Votic";
|
||||
case ("wak"): return "Wakashan languages";
|
||||
case ("wal"): return "Walamo";
|
||||
case ("war"): return "Waray";
|
||||
case ("was"): return "Washo";
|
||||
case ("cym"): return "Welsh";
|
||||
case ("wel"): return "Welsh";
|
||||
case ("wol"): return "Wolof";
|
||||
case ("xho"): return "Xhosa";
|
||||
case ("sah"): return "Yakut";
|
||||
case ("yao"): return "Yao";
|
||||
case ("yap"): return "Yap";
|
||||
case ("yid"): return "Yiddish";
|
||||
case ("yor"): return "Yoruba";
|
||||
case ("zap"): return "Zapotec";
|
||||
case ("zen"): return "Zenaga";
|
||||
case ("zha"): return "Zhuang";
|
||||
case ("zul"): return "Zulu";
|
||||
case ("zun"): return "Zuni";
|
||||
}
|
||||
return "Any";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
70
libse/ContainerFormats/Mp4/Boxes/Mdia.cs
Normal file
70
libse/ContainerFormats/Mp4/Boxes/Mdia.cs
Normal file
@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.ContainerFormats.Mp4.Boxes
|
||||
{
|
||||
public class Mdia : Box
|
||||
{
|
||||
public Mdhd Mdhd;
|
||||
public Minf Minf;
|
||||
public readonly string HandlerType = null;
|
||||
public readonly string HandlerName = string.Empty;
|
||||
|
||||
public bool IsTextSubtitle
|
||||
{
|
||||
get { return HandlerType == "sbtl" || HandlerType == "text"; }
|
||||
}
|
||||
|
||||
public bool IsVobSubSubtitle
|
||||
{
|
||||
get { return HandlerType == "subp"; }
|
||||
}
|
||||
|
||||
public bool IsClosedCaption
|
||||
{
|
||||
get { return HandlerType == "clcp"; }
|
||||
}
|
||||
|
||||
public bool IsVideo
|
||||
{
|
||||
get { return HandlerType == "vide"; }
|
||||
}
|
||||
|
||||
public bool IsAudio
|
||||
{
|
||||
get { return HandlerType == "soun"; }
|
||||
}
|
||||
|
||||
public Mdia(FileStream fs, ulong maximumLength)
|
||||
{
|
||||
Position = (ulong)fs.Position;
|
||||
while (fs.Position < (long)maximumLength)
|
||||
{
|
||||
if (!InitializeSizeAndName(fs))
|
||||
return;
|
||||
|
||||
if (Name == "minf" && IsTextSubtitle || IsVobSubSubtitle || IsClosedCaption || IsVideo)
|
||||
{
|
||||
UInt32 timeScale = 90000;
|
||||
if (Mdhd != null)
|
||||
timeScale = Mdhd.TimeScale;
|
||||
Minf = new Minf(fs, Position, timeScale, HandlerType, this);
|
||||
}
|
||||
else if (Name == "hdlr")
|
||||
{
|
||||
Buffer = new byte[Size - 4];
|
||||
fs.Read(Buffer, 0, Buffer.Length);
|
||||
HandlerType = GetString(8, 4);
|
||||
if (Size > 25)
|
||||
HandlerName = GetString(24, Buffer.Length - (24 + 5)); // TODO: How to find this?
|
||||
}
|
||||
else if (Name == "mdhd")
|
||||
{
|
||||
Mdhd = new Mdhd(fs, Size);
|
||||
}
|
||||
fs.Seek((long)Position, SeekOrigin.Begin);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
27
libse/ContainerFormats/Mp4/Boxes/Minf.cs
Normal file
27
libse/ContainerFormats/Mp4/Boxes/Minf.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.ContainerFormats.Mp4.Boxes
|
||||
{
|
||||
public class Minf : Box
|
||||
{
|
||||
|
||||
public Stbl Stbl;
|
||||
|
||||
public Minf(FileStream fs, ulong maximumLength, UInt32 timeScale, string handlerType, Mdia mdia)
|
||||
{
|
||||
Position = (ulong)fs.Position;
|
||||
while (fs.Position < (long)maximumLength)
|
||||
{
|
||||
if (!InitializeSizeAndName(fs))
|
||||
return;
|
||||
|
||||
if (Name == "stbl")
|
||||
Stbl = new Stbl(fs, Position, timeScale, handlerType, mdia);
|
||||
|
||||
fs.Seek((long)Position, SeekOrigin.Begin);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
29
libse/ContainerFormats/Mp4/Boxes/Moov.cs
Normal file
29
libse/ContainerFormats/Mp4/Boxes/Moov.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.ContainerFormats.Mp4.Boxes
|
||||
{
|
||||
public class Moov : Box
|
||||
{
|
||||
public Mvhd Mvhd;
|
||||
public List<Trak> Tracks;
|
||||
|
||||
public Moov(FileStream fs, ulong maximumLength)
|
||||
{
|
||||
Tracks = new List<Trak>();
|
||||
Position = (ulong)fs.Position;
|
||||
while (fs.Position < (long)maximumLength)
|
||||
{
|
||||
if (!InitializeSizeAndName(fs))
|
||||
return;
|
||||
|
||||
if (Name == "trak")
|
||||
Tracks.Add(new Trak(fs, Position));
|
||||
else if (Name == "mvhd")
|
||||
Mvhd = new Mvhd(fs);
|
||||
|
||||
fs.Seek((long)Position, SeekOrigin.Begin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
25
libse/ContainerFormats/Mp4/Boxes/Mvhd.cs
Normal file
25
libse/ContainerFormats/Mp4/Boxes/Mvhd.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.ContainerFormats.Mp4.Boxes
|
||||
{
|
||||
public class Mvhd : Box
|
||||
{
|
||||
public readonly uint CreationTime;
|
||||
public readonly uint ModificationTime;
|
||||
public readonly uint Duration;
|
||||
public readonly uint TimeScale;
|
||||
|
||||
public Mvhd(FileStream fs)
|
||||
{
|
||||
Buffer = new byte[20];
|
||||
int bytesRead = fs.Read(Buffer, 0, Buffer.Length);
|
||||
if (bytesRead < Buffer.Length)
|
||||
return;
|
||||
|
||||
CreationTime = GetUInt(4);
|
||||
ModificationTime = GetUInt(8);
|
||||
TimeScale = GetUInt(12);
|
||||
Duration = GetUInt(16);
|
||||
}
|
||||
}
|
||||
}
|
201
libse/ContainerFormats/Mp4/Boxes/Stbl.cs
Normal file
201
libse/ContainerFormats/Mp4/Boxes/Stbl.cs
Normal file
@ -0,0 +1,201 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Nikse.Core;
|
||||
using Nikse.SubtitleEdit.Core.SubtitleFormats;
|
||||
using Nikse.SubtitleEdit.Core.VobSub;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.ContainerFormats.Mp4.Boxes
|
||||
{
|
||||
public class Stbl : Box
|
||||
{
|
||||
public List<string> Texts = new List<string>();
|
||||
public List<SubPicture> SubPictures = new List<SubPicture>();
|
||||
public List<double> StartTimeCodes = new List<double>();
|
||||
public List<double> EndTimeCodes = new List<double>();
|
||||
public ulong StszSampleCount = 0;
|
||||
private Mdia _mdia;
|
||||
|
||||
public Stbl(FileStream fs, ulong maximumLength, UInt32 timeScale, string handlerType, Mdia mdia)
|
||||
{
|
||||
_mdia = mdia;
|
||||
Position = (ulong)fs.Position;
|
||||
while (fs.Position < (long)maximumLength)
|
||||
{
|
||||
if (!InitializeSizeAndName(fs))
|
||||
return;
|
||||
|
||||
if (Name == "stco") // 32-bit - chunk offset
|
||||
{
|
||||
Buffer = new byte[Size - 4];
|
||||
fs.Read(Buffer, 0, Buffer.Length);
|
||||
int version = Buffer[0];
|
||||
uint totalEntries = GetUInt(4);
|
||||
|
||||
uint lastOffset = 0;
|
||||
for (int i = 0; i < totalEntries; i++)
|
||||
{
|
||||
uint offset = GetUInt(8 + i * 4);
|
||||
if (lastOffset + 5 < offset)
|
||||
ReadText(fs, offset, handlerType);
|
||||
lastOffset = offset;
|
||||
}
|
||||
}
|
||||
else if (Name == "co64") // 64-bit
|
||||
{
|
||||
Buffer = new byte[Size - 4];
|
||||
fs.Read(Buffer, 0, Buffer.Length);
|
||||
int version = Buffer[0];
|
||||
uint totalEntries = GetUInt(4);
|
||||
|
||||
ulong lastOffset = 0;
|
||||
for (int i = 0; i < totalEntries; i++)
|
||||
{
|
||||
ulong offset = GetUInt64(8 + i * 8);
|
||||
if (lastOffset + 8 < offset)
|
||||
ReadText(fs, offset, handlerType);
|
||||
lastOffset = offset;
|
||||
}
|
||||
}
|
||||
else if (Name == "stsz") // sample sizes
|
||||
{
|
||||
Buffer = new byte[Size - 4];
|
||||
fs.Read(Buffer, 0, Buffer.Length);
|
||||
int version = Buffer[0];
|
||||
uint uniformSizeOfEachSample = GetUInt(4);
|
||||
uint numberOfSampleSizes = GetUInt(8);
|
||||
StszSampleCount = numberOfSampleSizes;
|
||||
for (int i = 0; i < numberOfSampleSizes; i++)
|
||||
{
|
||||
if (12 + i * 4 + 4 < Buffer.Length)
|
||||
{
|
||||
uint sampleSize = GetUInt(12 + i * 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Name == "stts") // sample table time to sample map
|
||||
{
|
||||
//https://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-SW1
|
||||
|
||||
Buffer = new byte[Size - 4];
|
||||
fs.Read(Buffer, 0, Buffer.Length);
|
||||
int version = Buffer[0];
|
||||
uint numberOfSampleTimes = GetUInt(4);
|
||||
double totalTime = 0;
|
||||
if (_mdia.IsClosedCaption)
|
||||
{
|
||||
for (int i = 0; i < numberOfSampleTimes; i++)
|
||||
{
|
||||
uint sampleCount = GetUInt(8 + i * 8);
|
||||
uint sampleDelta = GetUInt(12 + i * 8);
|
||||
for (int j = 0; j < sampleCount; j++)
|
||||
{
|
||||
totalTime += sampleDelta / (double)timeScale;
|
||||
if (StartTimeCodes.Count > 0)
|
||||
EndTimeCodes[EndTimeCodes.Count - 1] = totalTime - 0.001;
|
||||
StartTimeCodes.Add(totalTime);
|
||||
EndTimeCodes.Add(totalTime + 2.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < numberOfSampleTimes; i++)
|
||||
{
|
||||
uint sampleCount = GetUInt(8 + i * 8);
|
||||
uint sampleDelta = GetUInt(12 + i * 8);
|
||||
totalTime += sampleDelta / (double)timeScale;
|
||||
if (StartTimeCodes.Count <= EndTimeCodes.Count)
|
||||
StartTimeCodes.Add(totalTime);
|
||||
else
|
||||
EndTimeCodes.Add(totalTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Name == "stsc") // sample table sample to chunk map
|
||||
{
|
||||
Buffer = new byte[Size - 4];
|
||||
fs.Read(Buffer, 0, Buffer.Length);
|
||||
int version = Buffer[0];
|
||||
uint numberOfSampleTimes = GetUInt(4);
|
||||
for (int i = 0; i < numberOfSampleTimes; i++)
|
||||
{
|
||||
if (16 + i * 12 + 4 < Buffer.Length)
|
||||
{
|
||||
uint firstChunk = GetUInt(8 + i * 12);
|
||||
uint samplesPerChunk = GetUInt(12 + i * 12);
|
||||
uint sampleDescriptionIndex = GetUInt(16 + i * 12);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fs.Seek((long)Position, SeekOrigin.Begin);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadText(FileStream fs, ulong offset, string handlerType)
|
||||
{
|
||||
fs.Seek((long)offset, SeekOrigin.Begin);
|
||||
var data = new byte[4];
|
||||
fs.Read(data, 0, 2);
|
||||
uint textSize = (uint)GetWord(data, 0);
|
||||
|
||||
if (handlerType == "subp") // VobSub created with Mp4Box
|
||||
{
|
||||
if (textSize > 100)
|
||||
{
|
||||
fs.Seek((long)offset, SeekOrigin.Begin);
|
||||
data = new byte[textSize + 2];
|
||||
fs.Read(data, 0, data.Length);
|
||||
SubPictures.Add(new SubPicture(data)); // TODO: Where is palette?
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (textSize == 0)
|
||||
{
|
||||
fs.Read(data, 2, 2);
|
||||
textSize = GetUInt(data, 0); // don't get it exactly - seems like mp4box sometimes uses 2 bytes length field (first text record only)... handbrake uses 4 bytes
|
||||
}
|
||||
if (textSize > 0 && textSize < 500)
|
||||
{
|
||||
data = new byte[textSize];
|
||||
fs.Read(data, 0, data.Length);
|
||||
string text = GetString(data, 0, (int)textSize).TrimEnd();
|
||||
|
||||
if (_mdia.IsClosedCaption)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
for (int j = 8; j < data.Length - 3; j++)
|
||||
{
|
||||
string h = data[j].ToString("X2").ToLower();
|
||||
if (h.Length < 2)
|
||||
h = "0" + h;
|
||||
sb.Append(h);
|
||||
if (j % 2 == 1)
|
||||
sb.Append(' ');
|
||||
}
|
||||
string hex = sb.ToString();
|
||||
int errorCount = 0;
|
||||
text = ScenaristClosedCaptions.GetSccText(hex, ref errorCount);
|
||||
if (text.StartsWith('n') && text.Length > 1)
|
||||
text = "<i>" + text.Substring(1) + "</i>";
|
||||
if (text.StartsWith("-n"))
|
||||
text = text.Remove(0, 2);
|
||||
if (text.StartsWith("-N"))
|
||||
text = text.Remove(0, 2);
|
||||
if (text.StartsWith('-') && !text.Contains(Environment.NewLine + "-"))
|
||||
text = text.Remove(0, 1);
|
||||
}
|
||||
Texts.Add(text.Replace(Environment.NewLine, "\n").Replace("\n", Environment.NewLine));
|
||||
}
|
||||
else
|
||||
{
|
||||
Texts.Add(string.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
41
libse/ContainerFormats/Mp4/Boxes/Tkhd.cs
Normal file
41
libse/ContainerFormats/Mp4/Boxes/Tkhd.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.ContainerFormats.Mp4.Boxes
|
||||
{
|
||||
public class Tkhd : Box
|
||||
{
|
||||
public readonly uint TrackId;
|
||||
public readonly ulong Duration;
|
||||
public readonly uint Width;
|
||||
public readonly uint Height;
|
||||
|
||||
public Tkhd(FileStream fs)
|
||||
{
|
||||
Buffer = new byte[84];
|
||||
int bytesRead = fs.Read(Buffer, 0, Buffer.Length);
|
||||
if (bytesRead < Buffer.Length)
|
||||
return;
|
||||
|
||||
int version = Buffer[0];
|
||||
int addToIndex64Bit = 0;
|
||||
if (version == 1)
|
||||
addToIndex64Bit = 8;
|
||||
|
||||
TrackId = GetUInt(12 + addToIndex64Bit);
|
||||
if (version == 1)
|
||||
{
|
||||
Duration = GetUInt64(20 + addToIndex64Bit);
|
||||
addToIndex64Bit += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
Duration = GetUInt(20 + addToIndex64Bit);
|
||||
}
|
||||
|
||||
Width = (uint)GetWord(76 + addToIndex64Bit); // skip decimals
|
||||
Height = (uint)GetWord(80 + addToIndex64Bit); // skip decimals
|
||||
//System.Windows.Forms.MessageBox.Show("Width: " + GetWord(76 + addToIndex64Bit).ToString() + "." + GetWord(78 + addToIndex64Bit).ToString());
|
||||
//System.Windows.Forms.MessageBox.Show("Height: " + GetWord(80 + addToIndex64Bit).ToString() + "." + GetWord(82 + addToIndex64Bit).ToString());
|
||||
}
|
||||
}
|
||||
}
|
29
libse/ContainerFormats/Mp4/Boxes/Trak.cs
Normal file
29
libse/ContainerFormats/Mp4/Boxes/Trak.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.ContainerFormats.Mp4.Boxes
|
||||
{
|
||||
public class Trak : Box
|
||||
{
|
||||
|
||||
public Mdia Mdia;
|
||||
public Tkhd Tkhd;
|
||||
|
||||
public Trak(FileStream fs, ulong maximumLength)
|
||||
{
|
||||
Position = (ulong)fs.Position;
|
||||
while (fs.Position < (long)maximumLength)
|
||||
{
|
||||
if (!InitializeSizeAndName(fs))
|
||||
return;
|
||||
|
||||
if (Name == "mdia")
|
||||
Mdia = new Mdia(fs, Position);
|
||||
else if (Name == "tkhd")
|
||||
Tkhd = new Tkhd(fs);
|
||||
|
||||
fs.Seek((long)Position, SeekOrigin.Begin);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
168
libse/ContainerFormats/Mp4/Mp4Parser.cs
Normal file
168
libse/ContainerFormats/Mp4/Mp4Parser.cs
Normal file
@ -0,0 +1,168 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Nikse.SubtitleEdit.Core.ContainerFormats.Mp4.Boxes;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.ContainerFormats.Mp4
|
||||
{
|
||||
/// <summary>
|
||||
/// http://wiki.multimedia.cx/index.php?title=QuickTime_container
|
||||
/// </summary>
|
||||
public class MP4Parser : Box
|
||||
{
|
||||
public string FileName { get; private set; }
|
||||
public Moov Moov { get; private set; }
|
||||
|
||||
public List<Trak> GetSubtitleTracks()
|
||||
{
|
||||
var list = new List<Trak>();
|
||||
if (Moov != null && Moov.Tracks != null)
|
||||
{
|
||||
foreach (var trak in Moov.Tracks)
|
||||
{
|
||||
if (trak.Mdia != null && (trak.Mdia.IsTextSubtitle || trak.Mdia.IsVobSubSubtitle || trak.Mdia.IsClosedCaption) && trak.Mdia.Minf != null && trak.Mdia.Minf.Stbl != null)
|
||||
{
|
||||
list.Add(trak);
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public List<Trak> GetAudioTracks()
|
||||
{
|
||||
var list = new List<Trak>();
|
||||
if (Moov != null && Moov.Tracks != null)
|
||||
{
|
||||
foreach (var trak in Moov.Tracks)
|
||||
{
|
||||
if (trak.Mdia != null && trak.Mdia.IsAudio)
|
||||
{
|
||||
list.Add(trak);
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public List<Trak> GetVideoTracks()
|
||||
{
|
||||
var list = new List<Trak>();
|
||||
if (Moov != null && Moov.Tracks != null)
|
||||
{
|
||||
foreach (var trak in Moov.Tracks)
|
||||
{
|
||||
if (trak.Mdia != null && trak.Mdia.IsVideo)
|
||||
{
|
||||
list.Add(trak);
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public TimeSpan Duration
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Moov != null && Moov.Mvhd != null && Moov.Mvhd.TimeScale > 0)
|
||||
return TimeSpan.FromSeconds((double)Moov.Mvhd.Duration / Moov.Mvhd.TimeScale);
|
||||
return new TimeSpan();
|
||||
}
|
||||
}
|
||||
|
||||
public DateTime CreationDate
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Moov != null && Moov.Mvhd != null && Moov.Mvhd.TimeScale > 0)
|
||||
return new DateTime(1904, 1, 1, 0, 0, 0, DateTimeKind.Utc).Add(TimeSpan.FromSeconds(Moov.Mvhd.CreationTime));
|
||||
return DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolution of first video track. If not present returns 0.0
|
||||
/// </summary>
|
||||
public System.Drawing.Point VideoResolution
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Moov != null && Moov.Tracks != null)
|
||||
{
|
||||
foreach (var trak in Moov.Tracks)
|
||||
{
|
||||
if (trak != null && trak.Mdia != null && trak.Tkhd != null)
|
||||
{
|
||||
if (trak.Mdia.IsVideo)
|
||||
return new System.Drawing.Point((int)trak.Tkhd.Width, (int)trak.Tkhd.Height);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new System.Drawing.Point(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public MP4Parser(string fileName)
|
||||
{
|
||||
FileName = fileName;
|
||||
using (var fs = new FileStream(FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
{
|
||||
ParseMp4(fs);
|
||||
fs.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public MP4Parser(FileStream fs)
|
||||
{
|
||||
FileName = null;
|
||||
ParseMp4(fs);
|
||||
}
|
||||
|
||||
private void ParseMp4(FileStream fs)
|
||||
{
|
||||
int count = 0;
|
||||
Position = 0;
|
||||
fs.Seek(0, SeekOrigin.Begin);
|
||||
bool moreBytes = true;
|
||||
while (moreBytes)
|
||||
{
|
||||
moreBytes = InitializeSizeAndName(fs);
|
||||
if (Size < 8)
|
||||
return;
|
||||
|
||||
if (Name == "moov" && Moov == null)
|
||||
Moov = new Moov(fs, Position); // only scan first "moov" element
|
||||
|
||||
count++;
|
||||
if (count > 100)
|
||||
break;
|
||||
|
||||
if (Position > (ulong)fs.Length)
|
||||
break;
|
||||
fs.Seek((long)Position, SeekOrigin.Begin);
|
||||
}
|
||||
fs.Close();
|
||||
}
|
||||
|
||||
internal double FrameRate
|
||||
{
|
||||
get
|
||||
{
|
||||
// Formula: moov.mdia.stbl.stsz.samplecount / (moov.trak.tkhd.duration / moov.mvhd.timescale) - http://www.w3.org/2008/WebVideo/Annotations/drafts/ontology10/CR/test.php?table=containerMPEG4
|
||||
if (Moov != null && Moov.Mvhd != null && Moov.Mvhd.TimeScale > 0)
|
||||
{
|
||||
var videoTracks = GetVideoTracks();
|
||||
if (videoTracks.Count > 0 && videoTracks[0].Tkhd != null && videoTracks[0].Mdia != null && videoTracks[0].Mdia.Minf != null && videoTracks[0].Mdia.Minf.Stbl != null)
|
||||
{
|
||||
double duration = videoTracks[0].Tkhd.Duration;
|
||||
double sampleCount = videoTracks[0].Mdia.Minf.Stbl.StszSampleCount;
|
||||
return sampleCount / (duration / Moov.Mvhd.TimeScale);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
452
libse/ContainerFormats/RiffDecodeHeader.cs
Normal file
452
libse/ContainerFormats/RiffDecodeHeader.cs
Normal file
@ -0,0 +1,452 @@
|
||||
// (c) Giora Tamir (giora@gtamir.com), 2005
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using Nikse.Core;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.ContainerFormats
|
||||
{
|
||||
public class RiffDecodeHeader
|
||||
{
|
||||
|
||||
#region private members
|
||||
|
||||
private RiffParser m_parser;
|
||||
|
||||
private double m_frameRate;
|
||||
private int m_maxBitRate;
|
||||
private int m_totalFrames;
|
||||
private int m_numStreams;
|
||||
private int m_width;
|
||||
private int m_height;
|
||||
|
||||
private string m_isft;
|
||||
|
||||
private double m_vidDataRate;
|
||||
private string m_vidHandler;
|
||||
private double m_audDataRate;
|
||||
private string m_audHandler;
|
||||
|
||||
private int m_numChannels;
|
||||
private int m_samplesPerSec;
|
||||
private int m_bitsPerSec;
|
||||
private int m_bitsPerSample;
|
||||
|
||||
#endregion private members
|
||||
|
||||
#region public members
|
||||
|
||||
/// <summary>
|
||||
/// Access the internal parser object
|
||||
/// </summary>
|
||||
public RiffParser Parser
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_parser;
|
||||
}
|
||||
}
|
||||
|
||||
public double FrameRate
|
||||
{
|
||||
get
|
||||
{
|
||||
double rate = 0.0;
|
||||
if (m_frameRate > 0.0)
|
||||
rate = 1000000.0 / m_frameRate;
|
||||
return rate;
|
||||
}
|
||||
}
|
||||
|
||||
public string MaxBitRate
|
||||
{
|
||||
get
|
||||
{
|
||||
return String.Format("{0:N} Kb/Sec", m_maxBitRate / 128);
|
||||
}
|
||||
}
|
||||
|
||||
public int TotalFrames
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_totalFrames;
|
||||
}
|
||||
}
|
||||
|
||||
public double TotalMilliseconds
|
||||
{
|
||||
get
|
||||
{
|
||||
double totalTime = 0.0;
|
||||
if (m_frameRate > 0.0)
|
||||
{
|
||||
totalTime = m_totalFrames * m_frameRate / TimeCode.BaseUnit;
|
||||
}
|
||||
return totalTime;
|
||||
}
|
||||
}
|
||||
|
||||
public string NumStreams
|
||||
{
|
||||
get
|
||||
{
|
||||
return String.Format("Streams in file: {0:G}", m_numStreams);
|
||||
}
|
||||
}
|
||||
|
||||
public string FrameSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return String.Format("{0:G} x {1:G} pixels per frame", m_width, m_height);
|
||||
}
|
||||
}
|
||||
|
||||
public int Width
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_width;
|
||||
}
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_height;
|
||||
}
|
||||
}
|
||||
|
||||
public string VideoDataRate
|
||||
{
|
||||
get
|
||||
{
|
||||
return String.Format("Video rate {0:N2} frames/Sec", m_vidDataRate);
|
||||
}
|
||||
}
|
||||
|
||||
public string AudioDataRate
|
||||
{
|
||||
get
|
||||
{
|
||||
return String.Format("Audio rate {0:N2} Kb/Sec", m_audDataRate / TimeCode.BaseUnit);
|
||||
}
|
||||
}
|
||||
|
||||
public string VideoHandler
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_vidHandler;
|
||||
}
|
||||
}
|
||||
|
||||
public string AudioHandler
|
||||
{
|
||||
get
|
||||
{
|
||||
return String.Format("Audio handler 4CC code: {0}", m_audHandler);
|
||||
}
|
||||
}
|
||||
|
||||
public string ISFT
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_isft;
|
||||
}
|
||||
}
|
||||
|
||||
public string NumChannels
|
||||
{
|
||||
get
|
||||
{
|
||||
return String.Format("Audio channels: {0}", m_numChannels);
|
||||
}
|
||||
}
|
||||
|
||||
public string SamplesPerSec
|
||||
{
|
||||
get
|
||||
{
|
||||
return String.Format("Audio rate: {0:N0} Samples/Sec", m_samplesPerSec);
|
||||
}
|
||||
}
|
||||
|
||||
public string BitsPerSec
|
||||
{
|
||||
get
|
||||
{
|
||||
return String.Format("Audio rate: {0:N0} Bytes/Sec", m_bitsPerSec);
|
||||
}
|
||||
}
|
||||
|
||||
public string BitsPerSample
|
||||
{
|
||||
get
|
||||
{
|
||||
return String.Format("Audio data: {0:N0} bits/Sample", m_bitsPerSample);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion public members
|
||||
|
||||
#region Constructor
|
||||
|
||||
public RiffDecodeHeader(RiffParser rp)
|
||||
{
|
||||
m_parser = rp;
|
||||
}
|
||||
|
||||
private void Clear()
|
||||
{
|
||||
m_frameRate = 0;
|
||||
m_height = 0;
|
||||
m_maxBitRate = 0;
|
||||
m_numStreams = 0;
|
||||
m_totalFrames = 0;
|
||||
m_width = 0;
|
||||
|
||||
m_isft = String.Empty;
|
||||
|
||||
m_vidDataRate = 0;
|
||||
m_audDataRate = 0;
|
||||
m_vidHandler = String.Empty;
|
||||
m_audHandler = String.Empty;
|
||||
|
||||
m_numChannels = 0;
|
||||
m_samplesPerSec = 0;
|
||||
m_bitsPerSample = 0;
|
||||
m_bitsPerSec = 0;
|
||||
}
|
||||
|
||||
#endregion Constructor
|
||||
|
||||
#region Default element processing
|
||||
|
||||
/// <summary>
|
||||
/// Default list element handler - skip the entire list
|
||||
/// </summary>
|
||||
/// <param name="rp"></param>
|
||||
/// <param name="FourCC"></param>
|
||||
/// <param name="length"></param>
|
||||
private void ProcessList(RiffParser rp, int FourCC, int length)
|
||||
{
|
||||
rp.SkipData(length);
|
||||
}
|
||||
|
||||
#endregion Default element processing
|
||||
|
||||
#region Decode AVI
|
||||
|
||||
/// <summary>
|
||||
/// Handle chunk elements found in the AVI file. Ignores unknown chunks and
|
||||
/// </summary>
|
||||
/// <param name="rp"></param>
|
||||
/// <param name="FourCC"></param>
|
||||
/// <param name="unpaddedLength"></param>
|
||||
/// <param name="paddedLength"></param>
|
||||
private void ProcessAVIChunk(RiffParser rp, int FourCC, int unpaddedLength, int paddedLength)
|
||||
{
|
||||
if (AviRiffData.ckidMainAVIHeader == FourCC)
|
||||
{
|
||||
// Main AVI header
|
||||
DecodeAVIHeader(rp, paddedLength);
|
||||
}
|
||||
else if (AviRiffData.ckidAVIStreamHeader == FourCC)
|
||||
{
|
||||
// Stream header
|
||||
DecodeAVIStream(rp, paddedLength);
|
||||
}
|
||||
else if (AviRiffData.ckidAVIISFT == FourCC)
|
||||
{
|
||||
Byte[] ba = new byte[paddedLength];
|
||||
rp.ReadData(ba, 0, paddedLength);
|
||||
StringBuilder sb = new StringBuilder(unpaddedLength);
|
||||
for (int i = 0; i < unpaddedLength; ++i)
|
||||
{
|
||||
if (0 != ba[i]) sb.Append((char)ba[i]);
|
||||
}
|
||||
|
||||
m_isft = sb.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unknon chunk - skip
|
||||
rp.SkipData(paddedLength);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle List elements found in the AVI file. Ignores unknown lists and recursively looks
|
||||
/// at the content of known lists.
|
||||
/// </summary>
|
||||
/// <param name="rp"></param>
|
||||
/// <param name="FourCC"></param>
|
||||
/// <param name="length"></param>
|
||||
private void ProcessAVIList(RiffParser rp, int FourCC, int length)
|
||||
{
|
||||
RiffParser.ProcessChunkElement pac = ProcessAVIChunk;
|
||||
RiffParser.ProcessListElement pal = ProcessAVIList;
|
||||
|
||||
// Is this the header?
|
||||
if ((AviRiffData.ckidAVIHeaderList == FourCC)
|
||||
|| (AviRiffData.ckidAVIStreamList == FourCC)
|
||||
|| (AviRiffData.ckidINFOList == FourCC))
|
||||
{
|
||||
while (length > 0)
|
||||
{
|
||||
if (false == rp.ReadElement(ref length, pac, pal)) break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unknown lists - ignore
|
||||
rp.SkipData(length);
|
||||
}
|
||||
}
|
||||
|
||||
public void ProcessMainAVI()
|
||||
{
|
||||
Clear();
|
||||
int length = Parser.DataSize;
|
||||
|
||||
RiffParser.ProcessChunkElement pdc = ProcessAVIChunk;
|
||||
RiffParser.ProcessListElement pal = ProcessAVIList;
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
if (false == Parser.ReadElement(ref length, pdc, pal)) break;
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void DecodeAVIHeader(RiffParser rp, int length)
|
||||
{
|
||||
//if (length < sizeof(AVIMAINHEADER))
|
||||
//{
|
||||
// throw new RiffParserException(String.Format("Header size mismatch. Needed {0} but only have {1}",
|
||||
// sizeof(AVIMAINHEADER), length));
|
||||
//}
|
||||
|
||||
byte[] ba = new byte[length];
|
||||
|
||||
if (rp.ReadData(ba, 0, length) != length)
|
||||
{
|
||||
throw new RiffParserException("Problem reading AVI header.");
|
||||
}
|
||||
|
||||
fixed (Byte* bp = &ba[0])
|
||||
{
|
||||
AVIMAINHEADER* avi = (AVIMAINHEADER*)bp;
|
||||
m_frameRate = avi->dwMicroSecPerFrame;
|
||||
m_height = avi->dwHeight;
|
||||
m_maxBitRate = avi->dwMaxBytesPerSec;
|
||||
m_numStreams = avi->dwStreams;
|
||||
m_totalFrames = avi->dwTotalFrames;
|
||||
m_width = avi->dwWidth;
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void DecodeAVIStream(RiffParser rp, int length)
|
||||
{
|
||||
byte[] ba = new byte[length];
|
||||
|
||||
if (rp.ReadData(ba, 0, length) != length)
|
||||
{
|
||||
throw new RiffParserException("Problem reading AVI header.");
|
||||
}
|
||||
|
||||
fixed (Byte* bp = &ba[0])
|
||||
{
|
||||
AVISTREAMHEADER* avi = (AVISTREAMHEADER*)bp;
|
||||
|
||||
if (AviRiffData.streamtypeVIDEO == avi->fccType)
|
||||
{
|
||||
m_vidHandler = RiffParser.FromFourCC(avi->fccHandler);
|
||||
if (avi->dwScale > 0)
|
||||
{
|
||||
m_vidDataRate = (double)avi->dwRate / (double)avi->dwScale;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_vidDataRate = 0.0;
|
||||
}
|
||||
}
|
||||
else if (AviRiffData.streamtypeAUDIO == avi->fccType)
|
||||
{
|
||||
if (AviRiffData.ckidMP3 == avi->fccHandler)
|
||||
{
|
||||
m_audHandler = "MP3";
|
||||
}
|
||||
else
|
||||
{
|
||||
m_audHandler = RiffParser.FromFourCC(avi->fccHandler);
|
||||
}
|
||||
if (avi->dwScale > 0)
|
||||
{
|
||||
m_audDataRate = 8.0 * (double)avi->dwRate / (double)avi->dwScale;
|
||||
if (avi->dwSampleSize > 0)
|
||||
{
|
||||
m_audDataRate /= (double)avi->dwSampleSize;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_audDataRate = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Decode AVI
|
||||
|
||||
#region WAVE processing
|
||||
|
||||
private void ProcessWaveChunk(RiffParser rp, int FourCC, int unpaddedLength, int length)
|
||||
{
|
||||
// Is this a 'fmt' chunk?
|
||||
if (AviRiffData.ckidWaveFMT == FourCC)
|
||||
{
|
||||
DecodeWave(rp, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
rp.SkipData(length);
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void DecodeWave(RiffParser rp, int length)
|
||||
{
|
||||
byte[] ba = new byte[length];
|
||||
rp.ReadData(ba, 0, length);
|
||||
|
||||
fixed (byte* bp = &ba[0])
|
||||
{
|
||||
WAVEFORMATEX* wave = (WAVEFORMATEX*)bp;
|
||||
m_numChannels = wave->nChannels;
|
||||
m_bitsPerSec = wave->nAvgBytesPerSec;
|
||||
m_bitsPerSample = wave->wBitsPerSample;
|
||||
m_samplesPerSec = wave->nSamplesPerSec;
|
||||
}
|
||||
}
|
||||
|
||||
public void ProcessMainWAVE()
|
||||
{
|
||||
Clear();
|
||||
int length = Parser.DataSize;
|
||||
|
||||
RiffParser.ProcessChunkElement pdc = ProcessWaveChunk;
|
||||
RiffParser.ProcessListElement pal = ProcessList;
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
if (false == Parser.ReadElement(ref length, pdc, pal)) break;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion WAVE processing
|
||||
|
||||
}
|
||||
}
|
492
libse/ContainerFormats/RiffParser.cs
Normal file
492
libse/ContainerFormats/RiffParser.cs
Normal file
@ -0,0 +1,492 @@
|
||||
// (c) Giora Tamir (giora@gtamir.com), 2005
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.ContainerFormats
|
||||
{
|
||||
#region RiffParserException
|
||||
|
||||
[Serializable]
|
||||
public class RiffParserException : ApplicationException
|
||||
{
|
||||
public RiffParserException()
|
||||
{
|
||||
}
|
||||
|
||||
public RiffParserException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public RiffParserException(string message, Exception inner)
|
||||
: base(message, inner)
|
||||
{
|
||||
}
|
||||
|
||||
public RiffParserException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#endregion RiffParserException
|
||||
|
||||
public class RiffParser : IDisposable
|
||||
{
|
||||
#region CONSTANTS
|
||||
|
||||
public const int DWORDSIZE = 4;
|
||||
public const int TWODWORDSSIZE = 8;
|
||||
public const string RIFF4CC = "RIFF";
|
||||
public const string RIFX4CC = "RIFX";
|
||||
public const string LIST4CC = "LIST";
|
||||
|
||||
// Known file types
|
||||
public static readonly int ckidAVI = ToFourCC("AVI ");
|
||||
public static readonly int ckidWAV = ToFourCC("WAVE");
|
||||
public static readonly int ckidRMID = ToFourCC("RMID");
|
||||
|
||||
#endregion CONSTANTS
|
||||
|
||||
#region private members
|
||||
|
||||
private string m_filename;
|
||||
private string m_shortname;
|
||||
private long m_filesize;
|
||||
private int m_datasize;
|
||||
private FileStream m_stream;
|
||||
private int m_fileriff;
|
||||
private int m_filetype;
|
||||
|
||||
// For non-thread-safe memory optimization
|
||||
private byte[] m_eightBytes = new byte[TWODWORDSSIZE];
|
||||
private byte[] m_fourBytes = new byte[DWORDSIZE];
|
||||
|
||||
#endregion private members
|
||||
|
||||
#region Delegates
|
||||
|
||||
/// <summary>
|
||||
/// Method to be called when a list element is found
|
||||
/// </summary>
|
||||
/// <param name="FourCCType"></param>
|
||||
/// <param name="length"></param>
|
||||
public delegate void ProcessListElement(RiffParser rp, int FourCCType, int length);
|
||||
|
||||
/// <summary>
|
||||
/// Method to be called when a chunk element is found
|
||||
/// </summary>
|
||||
/// <param name="FourCCType"></param>
|
||||
/// <param name="unpaddedLength"></param>
|
||||
/// <param name="paddedLength"></param>
|
||||
public delegate void ProcessChunkElement(RiffParser rp, int FourCCType, int unpaddedLength, int paddedLength);
|
||||
|
||||
#endregion Delegates
|
||||
|
||||
#region public Members
|
||||
|
||||
/// <summary>
|
||||
/// RIFF data segment size
|
||||
/// </summary>
|
||||
public int DataSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_datasize;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Current file name
|
||||
/// </summary>
|
||||
public string FileName
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_filename;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Current short (name only) file name
|
||||
/// </summary>
|
||||
public string ShortName
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_shortname;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the general file type (RIFF or RIFX);
|
||||
/// </summary>
|
||||
public int FileRiff
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_fileriff;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the specific file type (AVI/WAV...)
|
||||
/// </summary>
|
||||
public int FileType
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_filetype;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion public Members
|
||||
|
||||
/// <summary>
|
||||
/// Determine if the file is a valid RIFF file
|
||||
/// </summary>
|
||||
/// <param name="filename">File to examine</param>
|
||||
/// <returns>True if file is a RIFF file</returns>
|
||||
public void OpenFile(string filename)
|
||||
{
|
||||
// Sanity check
|
||||
if (null != m_stream)
|
||||
{
|
||||
throw new RiffParserException("RIFF file already open " + FileName);
|
||||
}
|
||||
|
||||
bool errorOccured = false;
|
||||
|
||||
// Opening a new file
|
||||
try
|
||||
{
|
||||
FileInfo fi = new FileInfo(filename);
|
||||
m_filename = fi.FullName;
|
||||
m_shortname = fi.Name;
|
||||
m_filesize = fi.Length;
|
||||
fi = null;
|
||||
|
||||
//Console.WriteLine(ShortName + " is a valid file.");
|
||||
|
||||
// Read the RIFF header
|
||||
m_stream = new FileStream(m_filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
int FourCC;
|
||||
int datasize;
|
||||
int fileType;
|
||||
|
||||
ReadTwoInts(out FourCC, out datasize);
|
||||
ReadOneInt(out fileType);
|
||||
|
||||
m_fileriff = FourCC;
|
||||
m_filetype = fileType;
|
||||
|
||||
// Check for a valid RIFF header
|
||||
string riff = FromFourCC(FourCC);
|
||||
if (riff == RIFF4CC || riff == RIFX4CC)
|
||||
{
|
||||
// Good header. Check size
|
||||
//Console.WriteLine(ShortName + " has a valid type \"" + riff + "\"");
|
||||
//Console.WriteLine(ShortName + " has a specific type of \"" + FromFourCC(fileType) + "\"");
|
||||
|
||||
m_datasize = datasize;
|
||||
if (m_filesize >= m_datasize + TWODWORDSSIZE)
|
||||
{
|
||||
//Console.WriteLine(ShortName + " has a valid size");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_stream.Close(); m_stream = null;
|
||||
throw new RiffParserException("Error. Truncated file " + FileName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_stream.Close();
|
||||
m_stream.Dispose();
|
||||
m_stream = null;
|
||||
throw new RiffParserException("Error. Not a valid RIFF file " + FileName);
|
||||
}
|
||||
}
|
||||
catch (RiffParserException)
|
||||
{
|
||||
errorOccured = true;
|
||||
throw;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
errorOccured = true;
|
||||
throw new RiffParserException("Error. Problem reading file " + FileName, exception);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (errorOccured && (null != m_stream))
|
||||
{
|
||||
m_stream.Close();
|
||||
m_stream.Dispose();
|
||||
m_stream = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read the next RIFF element invoking the correct delegate.
|
||||
/// Returns true if an element can be read
|
||||
/// </summary>
|
||||
/// <param name="bytesleft">Reference to number of bytes left in the current list</param>
|
||||
/// <param name="chunk">Method to invoke if a chunk is found</param>
|
||||
/// <param name="list">Method to invoke if a list is found</param>
|
||||
/// <returns></returns>
|
||||
public bool ReadElement(ref int bytesleft, ProcessChunkElement chunk, ProcessListElement list)
|
||||
{
|
||||
// Are we done?
|
||||
if (TWODWORDSSIZE > bytesleft)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//Console.WriteLine(m_stream.Position.ToString() + ", " + bytesleft.ToString());
|
||||
|
||||
// We have enough bytes, read
|
||||
int FourCC;
|
||||
int size;
|
||||
|
||||
ReadTwoInts(out FourCC, out size);
|
||||
|
||||
// Reduce bytes left
|
||||
bytesleft -= TWODWORDSSIZE;
|
||||
|
||||
// Do we have enough bytes?
|
||||
if (bytesleft < size)
|
||||
{
|
||||
// Skip the bad data and throw an exception
|
||||
SkipData(bytesleft);
|
||||
bytesleft = 0;
|
||||
throw new RiffParserException("Element size mismatch for element " + FromFourCC(FourCC)
|
||||
+ " need " + size + " but have only " + bytesleft);
|
||||
}
|
||||
|
||||
// Examine the element, is it a list or a chunk
|
||||
string type = FromFourCC(FourCC);
|
||||
if (type == LIST4CC)
|
||||
{
|
||||
// We have a list
|
||||
ReadOneInt(out FourCC);
|
||||
|
||||
if (null == list)
|
||||
{
|
||||
SkipData(size - 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invoke the list method
|
||||
list(this, FourCC, size - 4);
|
||||
}
|
||||
|
||||
// Adjust size
|
||||
bytesleft -= size;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Calculated padded size - padded to WORD boundary
|
||||
int paddedSize = size;
|
||||
if (0 != (size & 1)) ++paddedSize;
|
||||
|
||||
if (null == chunk)
|
||||
{
|
||||
SkipData(paddedSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
chunk(this, FourCC, size, paddedSize);
|
||||
}
|
||||
|
||||
// Adjust size
|
||||
bytesleft -= paddedSize;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#region Stream access
|
||||
|
||||
/// <summary>
|
||||
/// Non-thread-safe method to read two ints from the stream
|
||||
/// </summary>
|
||||
/// <param name="FourCC">Output FourCC int</param>
|
||||
/// <param name="size">Output chunk/list size</param>
|
||||
public unsafe void ReadTwoInts(out int FourCC, out int size)
|
||||
{
|
||||
try
|
||||
{
|
||||
int readsize = m_stream.Read(m_eightBytes, 0, TWODWORDSSIZE);
|
||||
|
||||
if (TWODWORDSSIZE != readsize)
|
||||
{
|
||||
throw new RiffParserException("Unable to read. Corrupt RIFF file " + FileName);
|
||||
}
|
||||
|
||||
fixed (byte* bp = &m_eightBytes[0])
|
||||
{
|
||||
FourCC = *((int*)bp);
|
||||
size = *((int*)(bp + DWORDSIZE));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new RiffParserException("Problem accessing RIFF file " + FileName, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Non-thread-safe read a single int from the stream
|
||||
/// </summary>
|
||||
/// <param name="FourCC">Output int</param>
|
||||
public unsafe void ReadOneInt(out int FourCC)
|
||||
{
|
||||
try
|
||||
{
|
||||
int readsize = m_stream.Read(m_fourBytes, 0, DWORDSIZE);
|
||||
|
||||
if (DWORDSIZE != readsize)
|
||||
{
|
||||
throw new RiffParserException("Unable to read. Corrupt RIFF file " + FileName);
|
||||
}
|
||||
|
||||
fixed (byte* bp = &m_fourBytes[0])
|
||||
{
|
||||
FourCC = *((int*)bp);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new RiffParserException("Problem accessing RIFF file " + FileName, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Skip the specified number of bytes
|
||||
/// </summary>
|
||||
/// <param name="skipBytes">Number of bytes to skip</param>
|
||||
public void SkipData(int skipBytes)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_stream.Seek(skipBytes, SeekOrigin.Current);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new RiffParserException("Problem seeking in file " + FileName, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read the specified length into the byte array at the specified
|
||||
/// offset in the array
|
||||
/// </summary>
|
||||
/// <param name="data">Array of bytes to read into</param>
|
||||
/// <param name="offset">Offset in the array to start from</param>
|
||||
/// <param name="length">Number of bytes to read</param>
|
||||
/// <returns>Number of bytes actually read</returns>
|
||||
public int ReadData(Byte[] data, int offset, int length)
|
||||
{
|
||||
try
|
||||
{
|
||||
return m_stream.Read(data, offset, length);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new RiffParserException("Problem reading data in file " + FileName, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close the RIFF file
|
||||
/// </summary>
|
||||
public void CloseFile()
|
||||
{
|
||||
if (null != m_stream)
|
||||
{
|
||||
m_stream.Close();
|
||||
m_stream = null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Stream access
|
||||
|
||||
#region FourCC conversion methods
|
||||
|
||||
public static string FromFourCC(int FourCC)
|
||||
{
|
||||
char[] chars = new char[4];
|
||||
chars[0] = (char)(FourCC & 0xFF);
|
||||
chars[1] = (char)((FourCC >> 8) & 0xFF);
|
||||
chars[2] = (char)((FourCC >> 16) & 0xFF);
|
||||
chars[3] = (char)((FourCC >> 24) & 0xFF);
|
||||
|
||||
return new string(chars);
|
||||
}
|
||||
|
||||
public static int ToFourCC(string FourCC)
|
||||
{
|
||||
if (FourCC.Length != 4)
|
||||
{
|
||||
throw new Exception("FourCC strings must be 4 characters long " + FourCC);
|
||||
}
|
||||
|
||||
int result = ((int)FourCC[3]) << 24
|
||||
| ((int)FourCC[2]) << 16
|
||||
| ((int)FourCC[1]) << 8
|
||||
| ((int)FourCC[0]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int ToFourCC(char[] FourCC)
|
||||
{
|
||||
if (FourCC.Length != 4)
|
||||
{
|
||||
throw new Exception("FourCC char arrays must be 4 characters long " + new string(FourCC));
|
||||
}
|
||||
|
||||
int result = ((int)FourCC[3]) << 24
|
||||
| ((int)FourCC[2]) << 16
|
||||
| ((int)FourCC[1]) << 8
|
||||
| ((int)FourCC[0]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int ToFourCC(char c0, char c1, char c2, char c3)
|
||||
{
|
||||
int result = ((int)c3) << 24
|
||||
| ((int)c2) << 16
|
||||
| ((int)c1) << 8
|
||||
| ((int)c0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion FourCC conversion methods
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (m_stream != null)
|
||||
{
|
||||
m_stream.Dispose();
|
||||
m_stream = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
474
libse/DetectEncoding/EncodingTools.cs
Normal file
474
libse/DetectEncoding/EncodingTools.cs
Normal file
@ -0,0 +1,474 @@
|
||||
// Ripped from http://www.codeproject.com/KB/recipes/DetectEncoding.aspx
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Nikse.SubtitleEdit.Core.DetectEncoding.Multilang;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding
|
||||
{
|
||||
public static class EncodingTools
|
||||
{
|
||||
// this only contains ascii, default windows code page and unicode
|
||||
private static int[] PreferredEncodingsForStream;
|
||||
|
||||
// this contains all codepages, sorted by preference and byte usage
|
||||
private static int[] PreferredEncodings;
|
||||
|
||||
/// <summary>
|
||||
/// Static constructor that fills the default preferred codepages
|
||||
/// </summary>
|
||||
static EncodingTools()
|
||||
{
|
||||
List<int> streamEcodings = new List<int>();
|
||||
List<int> allEncodings = new List<int>();
|
||||
List<int> mimeEcodings = new List<int>();
|
||||
|
||||
// asscii - most simple so put it in first place...
|
||||
streamEcodings.Add(Encoding.ASCII.CodePage);
|
||||
mimeEcodings.Add(Encoding.ASCII.CodePage);
|
||||
allEncodings.Add(Encoding.ASCII.CodePage);
|
||||
|
||||
// add default 2nd for all encodings
|
||||
allEncodings.Add(Encoding.Default.CodePage);
|
||||
// default is single byte?
|
||||
if (Encoding.Default.IsSingleByte)
|
||||
{
|
||||
// put it in second place
|
||||
streamEcodings.Add(Encoding.Default.CodePage);
|
||||
mimeEcodings.Add(Encoding.Default.CodePage);
|
||||
}
|
||||
|
||||
// prefer JIS over JIS-SHIFT (JIS is detected better than JIS-SHIFT)
|
||||
// this one does include cyrilic (strange but true)
|
||||
allEncodings.Add(50220);
|
||||
mimeEcodings.Add(50220);
|
||||
|
||||
// always allow unicode flavours for streams (they all have a preamble)
|
||||
streamEcodings.Add(Encoding.Unicode.CodePage);
|
||||
foreach (EncodingInfo enc in Encoding.GetEncodings())
|
||||
{
|
||||
if (!streamEcodings.Contains(enc.CodePage))
|
||||
{
|
||||
Encoding encoding = Encoding.GetEncoding(enc.CodePage);
|
||||
if (encoding.GetPreamble().Length > 0)
|
||||
streamEcodings.Add(enc.CodePage);
|
||||
}
|
||||
}
|
||||
|
||||
// stream is done here
|
||||
PreferredEncodingsForStream = streamEcodings.ToArray();
|
||||
|
||||
// all singlebyte encodings
|
||||
foreach (EncodingInfo enc in Encoding.GetEncodings())
|
||||
{
|
||||
if (!enc.GetEncoding().IsSingleByte)
|
||||
continue;
|
||||
|
||||
if (!allEncodings.Contains(enc.CodePage))
|
||||
allEncodings.Add(enc.CodePage);
|
||||
|
||||
// only add iso and IBM encodings to mime encodings
|
||||
if (enc.CodePage <= 1258)
|
||||
{
|
||||
mimeEcodings.Add(enc.CodePage);
|
||||
}
|
||||
}
|
||||
|
||||
// add the rest (multibyte)
|
||||
foreach (EncodingInfo enc in Encoding.GetEncodings())
|
||||
{
|
||||
if (!enc.GetEncoding().IsSingleByte)
|
||||
{
|
||||
if (!allEncodings.Contains(enc.CodePage))
|
||||
allEncodings.Add(enc.CodePage);
|
||||
|
||||
// only add iso and IBM encodings to mime encodings
|
||||
if (enc.CodePage <= 1258)
|
||||
{
|
||||
mimeEcodings.Add(enc.CodePage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add unicodes
|
||||
mimeEcodings.Add(Encoding.Unicode.CodePage);
|
||||
|
||||
PreferredEncodings = mimeEcodings.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the best Encoding for usage in mime encodings
|
||||
/// </summary>
|
||||
/// <param name="input">text to detect</param>
|
||||
/// <returns>the suggested encoding</returns>
|
||||
public static Encoding GetMostEfficientEncoding(string input)
|
||||
{
|
||||
return GetMostEfficientEncoding(input, PreferredEncodings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the best ISO Encoding for usage in a stream
|
||||
/// </summary>
|
||||
/// <param name="input">text to detect</param>
|
||||
/// <returns>the suggested encoding</returns>
|
||||
public static Encoding GetMostEfficientEncodingForStream(string input)
|
||||
{
|
||||
return GetMostEfficientEncoding(input, PreferredEncodingsForStream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the best fitting encoding from a list of possible encodings
|
||||
/// </summary>
|
||||
/// <param name="input">text to detect</param>
|
||||
/// <param name="preferredEncodings">an array of codepages</param>
|
||||
/// <returns>the suggested encoding</returns>
|
||||
public static Encoding GetMostEfficientEncoding(string input, int[] preferredEncodings)
|
||||
{
|
||||
Encoding enc = DetectOutgoingEncoding(input, preferredEncodings, true);
|
||||
// unicode.. hmmm... check for smallest encoding
|
||||
if (enc.CodePage == Encoding.Unicode.CodePage)
|
||||
{
|
||||
int byteCount = Encoding.UTF7.GetByteCount(input);
|
||||
enc = Encoding.UTF7;
|
||||
int bestByteCount = byteCount;
|
||||
|
||||
// utf8 smaller?
|
||||
byteCount = Encoding.UTF8.GetByteCount(input);
|
||||
if (byteCount < bestByteCount)
|
||||
{
|
||||
enc = Encoding.UTF8;
|
||||
bestByteCount = byteCount;
|
||||
}
|
||||
|
||||
// unicode smaller?
|
||||
byteCount = Encoding.Unicode.GetByteCount(input);
|
||||
if (byteCount < bestByteCount)
|
||||
{
|
||||
enc = Encoding.Unicode;
|
||||
bestByteCount = byteCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
return enc;
|
||||
}
|
||||
|
||||
public static Encoding DetectOutgoingEncoding(string input)
|
||||
{
|
||||
return DetectOutgoingEncoding(input, PreferredEncodings, true);
|
||||
}
|
||||
|
||||
public static Encoding DetectOutgoingStreamEncoding(string input)
|
||||
{
|
||||
return DetectOutgoingEncoding(input, PreferredEncodingsForStream, true);
|
||||
}
|
||||
|
||||
public static Encoding[] DetectOutgoingEncodings(string input)
|
||||
{
|
||||
return DetectOutgoingEncodings(input, PreferredEncodings, true);
|
||||
}
|
||||
|
||||
public static Encoding[] DetectOutgoingStreamEncodings(string input)
|
||||
{
|
||||
return DetectOutgoingEncodings(input, PreferredEncodingsForStream, true);
|
||||
}
|
||||
|
||||
private static Encoding DetectOutgoingEncoding(string input, int[] preferredEncodings, bool preserveOrder)
|
||||
{
|
||||
if (input == null)
|
||||
throw new ArgumentNullException("input");
|
||||
|
||||
// empty strings can always be encoded as ASCII
|
||||
if (input.Length == 0)
|
||||
return Encoding.ASCII;
|
||||
|
||||
Encoding result = Encoding.ASCII;
|
||||
|
||||
// get the IMultiLanguage3 interface
|
||||
IMultiLanguage3 multilang3 = new CMultiLanguageClass();
|
||||
if (multilang3 == null)
|
||||
throw new COMException("Failed to get IMultilang3");
|
||||
try
|
||||
{
|
||||
int[] resultCodePages = new int[preferredEncodings != null ? preferredEncodings.Length : Encoding.GetEncodings().Length];
|
||||
uint detectedCodepages = (uint)resultCodePages.Length;
|
||||
ushort specialChar = (ushort)'?';
|
||||
|
||||
// get unmanaged arrays
|
||||
IntPtr pPrefEncs = preferredEncodings == null ? IntPtr.Zero : Marshal.AllocCoTaskMem(sizeof(uint) * preferredEncodings.Length);
|
||||
IntPtr pDetectedEncs = Marshal.AllocCoTaskMem(sizeof(uint) * resultCodePages.Length);
|
||||
|
||||
try
|
||||
{
|
||||
if (preferredEncodings != null)
|
||||
Marshal.Copy(preferredEncodings, 0, pPrefEncs, preferredEncodings.Length);
|
||||
|
||||
Marshal.Copy(resultCodePages, 0, pDetectedEncs, resultCodePages.Length);
|
||||
|
||||
MLCPF options = MLCPF.MLDETECTF_VALID_NLS;
|
||||
if (preserveOrder)
|
||||
options |= MLCPF.MLDETECTF_PRESERVE_ORDER;
|
||||
|
||||
if (preferredEncodings != null)
|
||||
options |= MLCPF.MLDETECTF_PREFERRED_ONLY;
|
||||
|
||||
multilang3.DetectOutboundCodePage(options,
|
||||
input, (uint)input.Length,
|
||||
pPrefEncs, (uint)(preferredEncodings == null ? 0 : preferredEncodings.Length),
|
||||
|
||||
pDetectedEncs, ref detectedCodepages,
|
||||
ref specialChar);
|
||||
|
||||
// get result
|
||||
if (detectedCodepages > 0)
|
||||
{
|
||||
int[] theResult = new int[detectedCodepages];
|
||||
Marshal.Copy(pDetectedEncs, theResult, 0, theResult.Length);
|
||||
result = Encoding.GetEncoding(theResult[0]);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (pPrefEncs != IntPtr.Zero)
|
||||
Marshal.FreeCoTaskMem(pPrefEncs);
|
||||
Marshal.FreeCoTaskMem(pDetectedEncs);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FinalReleaseComObject(multilang3);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Encoding[] DetectOutgoingEncodings(string input, int[] preferredEncodings, bool preserveOrder)
|
||||
{
|
||||
if (input == null)
|
||||
throw new ArgumentNullException("input");
|
||||
|
||||
// empty strings can always be encoded as ASCII
|
||||
if (input.Length == 0)
|
||||
return new Encoding[] { Encoding.ASCII };
|
||||
|
||||
List<Encoding> result = new List<Encoding>();
|
||||
|
||||
// get the IMultiLanguage3 interface
|
||||
IMultiLanguage3 multilang3 = new CMultiLanguageClass();
|
||||
if (multilang3 == null)
|
||||
throw new COMException("Failed to get IMultilang3");
|
||||
try
|
||||
{
|
||||
int[] resultCodePages = new int[preferredEncodings.Length];
|
||||
uint detectedCodepages = (uint)resultCodePages.Length;
|
||||
ushort specialChar = (ushort)'?';
|
||||
|
||||
// get unmanaged arrays
|
||||
IntPtr pPrefEncs = Marshal.AllocCoTaskMem(sizeof(uint) * preferredEncodings.Length);
|
||||
IntPtr pDetectedEncs = Marshal.AllocCoTaskMem(sizeof(uint) * resultCodePages.Length);
|
||||
|
||||
try
|
||||
{
|
||||
Marshal.Copy(preferredEncodings, 0, pPrefEncs, preferredEncodings.Length);
|
||||
|
||||
Marshal.Copy(resultCodePages, 0, pDetectedEncs, resultCodePages.Length);
|
||||
|
||||
MLCPF options = MLCPF.MLDETECTF_VALID_NLS | MLCPF.MLDETECTF_PREFERRED_ONLY;
|
||||
if (preserveOrder)
|
||||
options |= MLCPF.MLDETECTF_PRESERVE_ORDER;
|
||||
|
||||
options |= MLCPF.MLDETECTF_PREFERRED_ONLY;
|
||||
|
||||
// finally... call to DetectOutboundCodePage
|
||||
multilang3.DetectOutboundCodePage(options,
|
||||
input, (uint)input.Length,
|
||||
pPrefEncs, (uint)preferredEncodings.Length,
|
||||
pDetectedEncs, ref detectedCodepages,
|
||||
ref specialChar);
|
||||
|
||||
// get result
|
||||
if (detectedCodepages > 0)
|
||||
{
|
||||
int[] theResult = new int[detectedCodepages];
|
||||
Marshal.Copy(pDetectedEncs, theResult, 0, theResult.Length);
|
||||
|
||||
// get the encodings for the codepages
|
||||
for (int i = 0; i < detectedCodepages; i++)
|
||||
result.Add(Encoding.GetEncoding(theResult[i]));
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (pPrefEncs != IntPtr.Zero)
|
||||
Marshal.FreeCoTaskMem(pPrefEncs);
|
||||
Marshal.FreeCoTaskMem(pDetectedEncs);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FinalReleaseComObject(multilang3);
|
||||
}
|
||||
// nothing found
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Detect the most probable codepage from an byte array
|
||||
/// </summary>
|
||||
/// <param name="input">array containing the raw data</param>
|
||||
/// <returns>the detected encoding or the default encoding if the detection failed</returns>
|
||||
public static Encoding DetectInputCodepage(byte[] input)
|
||||
{
|
||||
try
|
||||
{
|
||||
Encoding[] detected = DetectInputCodepages(input, 1);
|
||||
|
||||
if (detected.Length > 0)
|
||||
return detected[0];
|
||||
return Encoding.Default;
|
||||
}
|
||||
catch (COMException)
|
||||
{
|
||||
// return default codepage on error
|
||||
return Encoding.Default;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rerurns up to maxEncodings codpages that are assumed to be apropriate
|
||||
/// </summary>
|
||||
/// <param name="input">array containing the raw data</param>
|
||||
/// <param name="maxEncodings">maxiumum number of encodings to detect</param>
|
||||
/// <returns>an array of Encoding with assumed encodings</returns>
|
||||
public static Encoding[] DetectInputCodepages(byte[] input, int maxEncodings)
|
||||
{
|
||||
if (maxEncodings < 1)
|
||||
throw new ArgumentOutOfRangeException("maxEncodings", "at least one encoding must be returned");
|
||||
|
||||
if (input == null)
|
||||
throw new ArgumentNullException("input");
|
||||
|
||||
// empty strings can always be encoded as ASCII
|
||||
if (input.Length == 0)
|
||||
return new Encoding[] { Encoding.ASCII };
|
||||
|
||||
// expand the string to be at least 256 bytes
|
||||
if (input.Length < 256)
|
||||
{
|
||||
byte[] newInput = new byte[256];
|
||||
int steps = 256 / input.Length;
|
||||
for (int i = 0; i < steps; i++)
|
||||
Array.Copy(input, 0, newInput, input.Length * i, input.Length);
|
||||
|
||||
int rest = 256 % input.Length;
|
||||
if (rest > 0)
|
||||
Array.Copy(input, 0, newInput, steps * input.Length, rest);
|
||||
input = newInput;
|
||||
}
|
||||
|
||||
List<Encoding> result = new List<Encoding>();
|
||||
|
||||
// get the IMultiLanguage" interface
|
||||
IMultiLanguage2 multilang2 = new CMultiLanguageClass();
|
||||
if (multilang2 == null)
|
||||
throw new COMException("Failed to get IMultilang2");
|
||||
try
|
||||
{
|
||||
DetectEncodingInfo[] detectedEncdings = new DetectEncodingInfo[maxEncodings];
|
||||
|
||||
int scores = detectedEncdings.Length;
|
||||
int srcLen = input.Length;
|
||||
|
||||
// setup options (none)
|
||||
const MLDETECTCP options = MLDETECTCP.MLDETECTCP_NONE;
|
||||
|
||||
// finally... call to DetectInputCodepage
|
||||
multilang2.DetectInputCodepage(options, 0,
|
||||
ref input[0], ref srcLen, ref detectedEncdings[0], ref scores);
|
||||
|
||||
// get result
|
||||
if (scores > 0)
|
||||
{
|
||||
for (int i = 0; i < scores; i++)
|
||||
{
|
||||
// add the result
|
||||
result.Add(Encoding.GetEncoding((int)detectedEncdings[i].nCodePage));
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FinalReleaseComObject(multilang2);
|
||||
}
|
||||
// nothing found
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a text file and returns the content
|
||||
/// encoded in the most probable encoding
|
||||
/// </summary>
|
||||
/// <param name="path">path to the souce file</param>
|
||||
/// <returns>the text content of the file</returns>
|
||||
public static string ReadTextFile(string path)
|
||||
{
|
||||
if (path == null)
|
||||
throw new ArgumentNullException("path");
|
||||
|
||||
using (Stream fs = File.Open(path, FileMode.Open))
|
||||
{
|
||||
byte[] rawData = new byte[fs.Length];
|
||||
Encoding enc = DetectInputCodepage(rawData);
|
||||
return enc.GetString(rawData);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a stream reader for the given
|
||||
/// text file with the best encoding applied
|
||||
/// </summary>
|
||||
/// <param name="path">path to the file</param>
|
||||
/// <returns>a StreamReader for the file</returns>
|
||||
public static StreamReader OpenTextFile(string path)
|
||||
{
|
||||
if (path == null)
|
||||
throw new ArgumentNullException("path");
|
||||
return OpenTextStream(File.Open(path, FileMode.Open));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a stream reader from a stream and detects
|
||||
/// the encoding form the first bytes in the stream
|
||||
/// </summary>
|
||||
/// <param name="stream">a stream to wrap</param>
|
||||
/// <returns>the newly created StreamReader</returns>
|
||||
public static StreamReader OpenTextStream(Stream stream)
|
||||
{
|
||||
// check stream parameter
|
||||
if (stream == null)
|
||||
throw new ArgumentNullException("stream");
|
||||
if (!stream.CanSeek)
|
||||
throw new ArgumentException("the stream must support seek operations", "stream");
|
||||
|
||||
// assume default encoding at first place
|
||||
Encoding detectedEncoding = Encoding.Default;
|
||||
|
||||
// seek to stream start
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
// buffer for preamble and up to 512b sample text for dection
|
||||
byte[] buf = new byte[System.Math.Min(stream.Length, 512)];
|
||||
|
||||
stream.Read(buf, 0, buf.Length);
|
||||
detectedEncoding = DetectInputCodepage(buf);
|
||||
// seek back to stream start
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
return new StreamReader(stream, detectedEncoding);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
9
libse/DetectEncoding/Multilang/CMLangConvertCharset.cs
Normal file
9
libse/DetectEncoding/Multilang/CMLangConvertCharset.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[ComImport, Guid("D66D6F98-CDAA-11D0-B822-00C04FC9B31F"), CoClass(typeof(CMLangConvertCharsetClass))]
|
||||
public interface ICMLangConvertCharset : IMLangConvertCharset
|
||||
{
|
||||
}
|
||||
}
|
24
libse/DetectEncoding/Multilang/CMLangConvertCharsetClass.cs
Normal file
24
libse/DetectEncoding/Multilang/CMLangConvertCharsetClass.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[ComImport, ClassInterface((short)0), TypeLibType((short)2), Guid("D66D6F99-CDAA-11D0-B822-00C04FC9B31F")]
|
||||
public class CMLangConvertCharsetClass : ICMLangConvertCharset
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void DoConversion([In] ref byte pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref byte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void DoConversionFromUnicode([In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref sbyte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void DoConversionToUnicode([In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref ushort pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetDestinationCodePage(out uint puiDstCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetProperty(out uint pdwProperty);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetSourceCodePage(out uint puiSrcCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void Initialize([In] uint uiSrcCodePage, [In] uint uiDstCodePage, [In] uint dwProperty);
|
||||
}
|
||||
}
|
9
libse/DetectEncoding/Multilang/CMLangString.cs
Normal file
9
libse/DetectEncoding/Multilang/CMLangString.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[ComImport, CoClass(typeof(CMLangStringClass)), Guid("C04D65CE-B70D-11D0-B188-00AA0038C969")]
|
||||
public interface ICMLangString : IMLangString
|
||||
{
|
||||
}
|
||||
}
|
67
libse/DetectEncoding/Multilang/CMLangStringClass.cs
Normal file
67
libse/DetectEncoding/Multilang/CMLangStringClass.cs
Normal file
@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[ComImport, Guid("C04D65CF-B70D-11D0-B188-00AA0038C969"), ComConversionLoss, ClassInterface((short)0), TypeLibType((short)2)]
|
||||
public class CMLangStringClass : ICMLangString, IMLangStringWStr, IMLangStringAStr
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetAStr([In] int lSrcPos, [In] int lSrcLen, [In] uint uCodePageIn, out uint puCodePageOut, out sbyte pszDest, [In] int cchDest, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern int GetLength();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetLocale([In] int lSrcPos, [In] int lSrcMaxLen, out uint plocale, out int plLocalePos, out int plLocaleLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetMLStr([In] int lSrcPos, [In] int lSrcLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter, [In] uint dwClsContext, [In] ref Guid piid, [MarshalAs(UnmanagedType.IUnknown)] out object ppDestMLStr, out int plDestPos, out int plDestLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetStrBufA([In] int lSrcPos, [In] int lSrcMaxLen, out uint puDestCodePage, [MarshalAs(UnmanagedType.Interface)] out IMLangStringBufA ppDestBuf, out int plDestLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetStrBufW([In] int lSrcPos, [In] int lSrcMaxLen, [MarshalAs(UnmanagedType.Interface)] out IMLangStringBufW ppDestBuf, out int plDestLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetWStr([In] int lSrcPos, [In] int lSrcLen, out ushort pszDest, [In] int cchDest, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern int IMLangStringAStrGetLength();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangStringAStrGetLocale([In] int lSrcPos, [In] int lSrcMaxLen, out uint plocale, out int plLocalePos, out int plLocaleLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangStringAStrGetMLStr([In] int lSrcPos, [In] int lSrcLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter, [In] uint dwClsContext, [In] ref Guid piid, [MarshalAs(UnmanagedType.IUnknown)] out object ppDestMLStr, out int plDestPos, out int plDestLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangStringAStrSetLocale([In] int lDestPos, [In] int lDestLen, [In] uint locale);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangStringAStrSetMLStr([In] int lDestPos, [In] int lDestLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pSrcMLStr, [In] int lSrcPos, [In] int lSrcLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangStringAStrSync([In] int fNoAccess);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern int IMLangStringWStrGetLength();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangStringWStrGetMLStr([In] int lSrcPos, [In] int lSrcLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter, [In] uint dwClsContext, [In] ref Guid piid, [MarshalAs(UnmanagedType.IUnknown)] out object ppDestMLStr, out int plDestPos, out int plDestLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangStringWStrSetMLStr([In] int lDestPos, [In] int lDestLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pSrcMLStr, [In] int lSrcPos, [In] int lSrcLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangStringWStrSync([In] int fNoAccess);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void LockAStr([In] int lSrcPos, [In] int lSrcLen, [In] int lFlags, [In] uint uCodePageIn, [In] int cchRequest, out uint puCodePageOut, [Out] IntPtr ppszDest, out int pcchDest, out int plDestLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void LockWStr([In] int lSrcPos, [In] int lSrcLen, [In] int lFlags, [In] int cchRequest, [Out] IntPtr ppszDest, out int pcchDest, out int plDestLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void SetAStr([In] int lDestPos, [In] int lDestLen, [In] uint uCodePage, [In] ref sbyte pszSrc, [In] int cchSrc, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void SetLocale([In] int lDestPos, [In] int lDestLen, [In] uint locale);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void SetMLStr([In] int lDestPos, [In] int lDestLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pSrcMLStr, [In] int lSrcPos, [In] int lSrcLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void SetStrBufA([In] int lDestPos, [In] int lDestLen, [In] uint uCodePage, [In, MarshalAs(UnmanagedType.Interface)] IMLangStringBufA pSrcBuf, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void SetStrBufW([In] int lDestPos, [In] int lDestLen, [In, MarshalAs(UnmanagedType.Interface)] IMLangStringBufW pSrcBuf, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void SetWStr([In] int lDestPos, [In] int lDestLen, [In] ref ushort pszSrc, [In] int cchSrc, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void Sync([In] int fNoAccess);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void UnlockAStr([In] ref sbyte pszSrc, [In] int cchSrc, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void UnlockWStr([In] ref ushort pszSrc, [In] int cchSrc, out int pcchActual, out int plActualLen);
|
||||
}
|
||||
}
|
9
libse/DetectEncoding/Multilang/CMultiLanguage.cs
Normal file
9
libse/DetectEncoding/Multilang/CMultiLanguage.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[ComImport, Guid("275C23E1-3747-11D0-9FEA-00AA003F8646"), CoClass(typeof(CMultiLanguageClass))]
|
||||
public interface ICMultiLanguage : IMultiLanguage
|
||||
{
|
||||
}
|
||||
}
|
217
libse/DetectEncoding/Multilang/CMultiLanguageClass.cs
Normal file
217
libse/DetectEncoding/Multilang/CMultiLanguageClass.cs
Normal file
@ -0,0 +1,217 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[ComImport, TypeLibType((short)2), ClassInterface((short)0), Guid("275C23E2-3747-11D0-9FEA-00AA003F8646")]
|
||||
public class CMultiLanguageClass : ICMultiLanguage, IMLangFontLink, IMLangLineBreakConsole, IMLangFontLink2, IMultiLanguage3
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void BreakLineA([In] uint locale, [In] uint uCodePage, [In] ref sbyte pszSrc, [In] int cchSrc, [In] int cMaxColumns, out int pcchLine, out int pcchSkip);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void BreakLineML([In, MarshalAs(UnmanagedType.Interface)] ICMLangString pSrcMLStr, [In] int lSrcPos, [In] int lSrcLen, [In] int cMinColumns, [In] int cMaxColumns, out int plLineLen, out int plSkipLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void BreakLineW([In] uint locale, [In] ref ushort pszSrc, [In] int cchSrc, [In] int cMaxColumns, out int pcchLine, out int pcchSkip);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void CodePagesToCodePage([In] uint dwCodePages, [In] uint uDefaultCodePage, out uint puCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void CodePageToCodePages([In] uint uCodePage, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void CodePageToScriptID([In] uint uiCodePage, out byte pSid);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void ConvertString([In, Out] ref uint pdwMode, [In] uint dwSrcEncoding, [In] uint dwDstEncoding, [In] ref byte pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref byte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void ConvertStringFromUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref sbyte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void ConvertStringFromUnicodeEx([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref sbyte pDstStr, [In, Out] ref uint pcDstSize, [In] uint dwFlag, [In] ref ushort lpFallBack);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void ConvertStringInIStream([In, Out] ref uint pdwMode, [In] uint dwFlag, [In] ref ushort lpFallBack, [In] uint dwSrcEncoding, [In] uint dwDstEncoding, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmIn, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmOut);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void ConvertStringReset();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void ConvertStringToUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref ushort pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void ConvertStringToUnicodeEx([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref ushort pDstStr, [In, Out] ref uint pcDstSize, [In] uint dwFlag, [In] ref ushort lpFallBack);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void CreateConvertCharset([In] uint uiSrcCodePage, [In] uint uiDstCodePage, [In] uint dwProperty, [MarshalAs(UnmanagedType.Interface)] out ICMLangConvertCharset ppMLangConvertCharset);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void DetectCodepageInIStream([In] MLDETECTCP flags,
|
||||
[In] uint dwPrefWinCodePage,
|
||||
[In, MarshalAs(UnmanagedType.Interface)] IStream pstmIn,
|
||||
[In, Out] ref DetectEncodingInfo lpEncoding,
|
||||
[In, Out] ref int pnScores);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void DetectInputCodepage([In] MLDETECTCP flags, [In] uint dwPrefWinCodePage,
|
||||
[In] ref byte pSrcStr, [In, Out] ref int pcSrcSize,
|
||||
[In, Out] ref DetectEncodingInfo lpEncoding,
|
||||
[In, Out] ref int pnScores);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void DetectOutboundCodePage([In] MLCPF dwFlags, [In, MarshalAs(UnmanagedType.LPWStr)] string lpWideCharStr, [In] uint cchWideChar,
|
||||
[In] IntPtr puiPreferredCodePages, [In] uint nPreferredCodePages, [In] IntPtr puiDetectedCodePages, [In, Out] ref uint pnDetectedCodePages, [In] ref ushort lpSpecialChar);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void DetectOutboundCodePageInIStream([In] uint dwFlags, [In, MarshalAs(UnmanagedType.Interface)] IStream pStrIn, [In] ref uint puiPreferredCodePages, [In] uint nPreferredCodePages, [In] ref uint puiDetectedCodePages, [In, Out] ref uint pnDetectedCodePages, [In] ref ushort lpSpecialChar);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void EnumCodePages([In] uint grfFlags, [MarshalAs(UnmanagedType.Interface)] out IEnumCodePage ppEnumCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void EnumCodePages([In] uint grfFlags, [In] ushort langId, [MarshalAs(UnmanagedType.Interface)] out IEnumCodePage ppEnumCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void EnumRfc1766([MarshalAs(UnmanagedType.Interface)] out IEnumRfc1766 ppEnumRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void EnumRfc1766([In] ushort langId, [MarshalAs(UnmanagedType.Interface)] out IEnumRfc1766 ppEnumRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void EnumScripts([In] uint dwFlags, [In] ushort langId, [MarshalAs(UnmanagedType.Interface)] out IEnumScript ppEnumScript);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetCharCodePages([In] ushort chSrc, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetCharsetInfo([In, MarshalAs(UnmanagedType.BStr)] string Charset, out tagMIMECSETINFO pCharsetInfo);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetCodePageDescription([In] uint uiCodePage, [In] uint lcid, [In, Out, MarshalAs(UnmanagedType.LPWStr)] string lpWideCharStr, [In] int cchWideChar);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetCodePageInfo([In] uint uiCodePage, out tagMIMECPINFO pCodePageInfo);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetCodePageInfo([In] uint uiCodePage, [In] ushort langId, out tagMIMECPINFO pCodePageInfo);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetFamilyCodePage([In] uint uiCodePage, out uint puiFamilyCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetFontCodePages([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hFont, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetFontUnicodeRanges([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In, Out] ref uint puiRanges, out tagUNICODERANGE pUranges);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetLcidFromRfc1766(out uint plocale, [In, MarshalAs(UnmanagedType.BStr)] string bstrRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetNumberOfCodePageInfo(out uint pcCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetNumberOfScripts(out uint pnScripts);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetRfc1766FromLcid([In] uint locale, [MarshalAs(UnmanagedType.BStr)] out string pbstrRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetRfc1766Info([In] uint locale, out tagRFC1766INFO pRfc1766Info);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetRfc1766Info([In] uint locale, [In] ushort langId, out tagRFC1766INFO pRfc1766Info);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetScriptFontInfo([In] byte sid, [In] uint dwFlags, [In, Out] ref uint puiFonts, out tagSCRIPFONTINFO pScriptFont);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetStrCodePages([In] ref ushort pszSrc, [In] int cchSrc, [In] uint dwPriorityCodePages, out uint pdwCodePages, out int pcchCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangFontLinkCodePagesToCodePage([In] uint dwCodePages, [In] uint uDefaultCodePage, out uint puCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangFontLinkCodePageToCodePages([In] uint uCodePage, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangFontLinkGetCharCodePages([In] ushort chSrc, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangFontLinkGetStrCodePages([In] ref ushort pszSrc, [In] int cchSrc, [In] uint dwPriorityCodePages, out uint pdwCodePages, out int pcchCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangFontLink2CodePagesToCodePage([In] uint dwCodePages, [In] uint uDefaultCodePage, out uint puCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangFontLink2CodePageToCodePages([In] uint uCodePage, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangFontLink2GetCharCodePages([In] ushort chSrc, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangFontLink2GetFontCodePages([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hFont, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangFontLink2GetStrCodePages([In] ref ushort pszSrc, [In] int cchSrc, [In] uint dwPriorityCodePages, out uint pdwCodePages, out int pcchCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangFontLink2ReleaseFont([In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hFont);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangFontLink2ResetFontMapping();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage2ConvertString([In, Out] ref uint pdwMode, [In] uint dwSrcEncoding, [In] uint dwDstEncoding, [In] ref byte pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref byte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage2ConvertStringFromUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref sbyte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage2ConvertStringReset();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage2ConvertStringToUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref ushort pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage2CreateConvertCharset([In] uint uiSrcCodePage, [In] uint uiDstCodePage, [In] uint dwProperty, [MarshalAs(UnmanagedType.Interface)] out ICMLangConvertCharset ppMLangConvertCharset);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage2GetCharsetInfo([In, MarshalAs(UnmanagedType.BStr)] string charset, out tagMIMECSETINFO pCharsetInfo);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage2GetFamilyCodePage([In] uint uiCodePage, out uint puiFamilyCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage2GetLcidFromRfc1766(out uint plocale, [In, MarshalAs(UnmanagedType.BStr)] string bstrRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage2GetNumberOfCodePageInfo(out uint pcCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage2GetRfc1766FromLcid([In] uint locale, [MarshalAs(UnmanagedType.BStr)] out string pbstrRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage2IsConvertible([In] uint dwSrcEncoding, [In] uint dwDstEncoding);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3ConvertString([In, Out] ref uint pdwMode, [In] uint dwSrcEncoding, [In] uint dwDstEncoding, [In] ref byte pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref byte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3ConvertStringFromUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref sbyte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3ConvertStringFromUnicodeEx([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref sbyte pDstStr, [In, Out] ref uint pcDstSize, [In] uint dwFlag, [In] ref ushort lpFallBack);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3ConvertStringInIStream([In, Out] ref uint pdwMode, [In] uint dwFlag, [In] ref ushort lpFallBack, [In] uint dwSrcEncoding, [In] uint dwDstEncoding, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmIn, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmOut);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3ConvertStringReset();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3ConvertStringToUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref ushort pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3ConvertStringToUnicodeEx([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref ushort pDstStr, [In, Out] ref uint pcDstSize, [In] uint dwFlag, [In] ref ushort lpFallBack);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3CreateConvertCharset([In] uint uiSrcCodePage, [In] uint uiDstCodePage, [In] uint dwProperty, [MarshalAs(UnmanagedType.Interface)] out ICMLangConvertCharset ppMLangConvertCharset);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3DetectCodepageInIStream([In] uint dwFlag, [In] uint dwPrefWinCodePage, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmIn, [In, Out] ref DetectEncodingInfo lpEncoding, [In, Out] ref int pnScores);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3DetectInputCodepage([In] uint dwFlag, [In] uint dwPrefWinCodePage, [In] ref sbyte pSrcStr, [In, Out] ref int pcSrcSize, [In, Out] ref DetectEncodingInfo lpEncoding, [In, Out] ref int pnScores);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3EnumCodePages([In] uint grfFlags, [In] ushort langId, [MarshalAs(UnmanagedType.Interface)] out IEnumCodePage ppEnumCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3EnumRfc1766([In] ushort langId, [MarshalAs(UnmanagedType.Interface)] out IEnumRfc1766 ppEnumRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3EnumScripts([In] uint dwFlags, [In] ushort langId, [MarshalAs(UnmanagedType.Interface)] out IEnumScript ppEnumScript);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3GetCharsetInfo([In, MarshalAs(UnmanagedType.BStr)] string charset, out tagMIMECSETINFO pCharsetInfo);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3GetCodePageDescription([In] uint uiCodePage, [In] uint lcid, [In, Out, MarshalAs(UnmanagedType.LPWStr)] string lpWideCharStr, [In] int cchWideChar);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3GetCodePageInfo([In] uint uiCodePage, [In] ushort langId, out tagMIMECPINFO pCodePageInfo);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3GetFamilyCodePage([In] uint uiCodePage, out uint puiFamilyCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3GetLcidFromRfc1766(out uint plocale, [In, MarshalAs(UnmanagedType.BStr)] string bstrRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3GetNumberOfCodePageInfo(out uint pcCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3GetNumberOfScripts(out uint pnScripts);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3GetRfc1766FromLcid([In] uint locale, [MarshalAs(UnmanagedType.BStr)] out string pbstrRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3GetRfc1766Info([In] uint locale, [In] ushort langId, out tagRFC1766INFO pRfc1766Info);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3IsCodePageInstallable([In] uint uiCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3IsConvertible([In] uint dwSrcEncoding, [In] uint dwDstEncoding);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3SetMimeDBSource([In] tagMIMECONTF dwSource);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3ValidateCodePage([In] uint uiCodePage, [In, ComAliasName("MultiLanguage.wireHWND")] ref _RemotableHandle hwnd);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3ValidateCodePageEx([In] uint uiCodePage, [In, ComAliasName("MultiLanguage.wireHWND")] ref _RemotableHandle hwnd, [In] uint dwfIODControl);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IsCodePageInstallable([In] uint uiCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IsConvertible([In] uint dwSrcEncoding, [In] uint dwDstEncoding);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void MapFont([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In] uint dwCodePages, [In] ushort chSrc, [Out, ComAliasName("MultiLanguage.wireHFONT")] IntPtr pFont);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void MapFont([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In] uint dwCodePages, [In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hSrcFont, [Out, ComAliasName("MultiLanguage.wireHFONT")] IntPtr phDestFont);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void ReleaseFont([In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hFont);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void ResetFontMapping();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void SetMimeDBSource([In] tagMIMECONTF dwSource);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void ValidateCodePage([In] uint uiCodePage, [In, ComAliasName("MultiLanguage.wireHWND")] ref _RemotableHandle hwnd);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void ValidateCodePageEx([In] uint uiCodePage, [In, ComAliasName("MultiLanguage.wireHWND")] ref _RemotableHandle hwnd, [In] uint dwfIODControl);
|
||||
}
|
||||
}
|
18
libse/DetectEncoding/Multilang/IEnumCodePage.cs
Normal file
18
libse/DetectEncoding/Multilang/IEnumCodePage.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[ComImport, Guid("275C23E3-3747-11D0-9FEA-00AA003F8646"), InterfaceType((short)1)]
|
||||
public interface IEnumCodePage
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Clone([MarshalAs(UnmanagedType.Interface)] out IEnumCodePage ppEnum);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Next([In] uint celt, out tagMIMECPINFO rgelt, out uint pceltFetched);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Reset();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Skip([In] uint celt);
|
||||
}
|
||||
}
|
18
libse/DetectEncoding/Multilang/IEnumRfc1766.cs
Normal file
18
libse/DetectEncoding/Multilang/IEnumRfc1766.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[ComImport, Guid("3DC39D1D-C030-11D0-B81B-00C04FC9B31F"), InterfaceType((short)1)]
|
||||
public interface IEnumRfc1766
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Clone([MarshalAs(UnmanagedType.Interface)] out IEnumRfc1766 ppEnum);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Next([In] uint celt, out tagRFC1766INFO rgelt, out uint pceltFetched);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Reset();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Skip([In] uint celt);
|
||||
}
|
||||
}
|
18
libse/DetectEncoding/Multilang/IEnumScript.cs
Normal file
18
libse/DetectEncoding/Multilang/IEnumScript.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[ComImport, Guid("AE5F1430-388B-11D2-8380-00C04F8F5DA1"), InterfaceType((short)1)]
|
||||
public interface IEnumScript
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Clone([MarshalAs(UnmanagedType.Interface)] out IEnumScript ppEnum);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Next([In] uint celt, out tagSCRIPTINFO rgelt, out uint pceltFetched);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Reset();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Skip([In] uint celt);
|
||||
}
|
||||
}
|
18
libse/DetectEncoding/Multilang/IMLangCodePages.cs
Normal file
18
libse/DetectEncoding/Multilang/IMLangCodePages.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[ComImport, Guid("359F3443-BD4A-11D0-B188-00AA0038C969"), InterfaceType((short)1)]
|
||||
public interface IMLangCodePages
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetCharCodePages([In] ushort chSrc, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetStrCodePages([In] ref ushort pszSrc, [In] int cchSrc, [In] uint dwPriorityCodePages, out uint pdwCodePages, out int pcchCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void CodePageToCodePages([In] uint uCodePage, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void CodePagesToCodePage([In] uint dwCodePages, [In] uint uDefaultCodePage, out uint puCodePage);
|
||||
}
|
||||
}
|
24
libse/DetectEncoding/Multilang/IMLangConvertCharset.cs
Normal file
24
libse/DetectEncoding/Multilang/IMLangConvertCharset.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[ComImport, Guid("D66D6F98-CDAA-11D0-B822-00C04FC9B31F"), InterfaceType((short)1)]
|
||||
public interface IMLangConvertCharset
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Initialize([In] uint uiSrcCodePage, [In] uint uiDstCodePage, [In] uint dwProperty);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetSourceCodePage(out uint puiSrcCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetDestinationCodePage(out uint puiDstCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetProperty(out uint pdwProperty);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void DoConversion([In] ref byte pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref byte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void DoConversionToUnicode([In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref ushort pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void DoConversionFromUnicode([In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref sbyte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
}
|
||||
}
|
29
libse/DetectEncoding/Multilang/IMLangFontLink.cs
Normal file
29
libse/DetectEncoding/Multilang/IMLangFontLink.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
#pragma warning disable 0108
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[ComImport, InterfaceType((short)1), ComConversionLoss, Guid("359F3441-BD4A-11D0-B188-00AA0038C969")]
|
||||
public interface IMLangFontLink : IMLangCodePages
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetCharCodePages([In] ushort chSrc, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetStrCodePages([In] ref ushort pszSrc, [In] int cchSrc, [In] uint dwPriorityCodePages, out uint pdwCodePages, out int pcchCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void CodePageToCodePages([In] uint uCodePage, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void CodePagesToCodePage([In] uint dwCodePages, [In] uint uDefaultCodePage, out uint puCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetFontCodePages([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hFont, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void MapFont([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In] uint dwCodePages, [In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hSrcFont, [Out, ComAliasName("MultiLanguage.wireHFONT")] IntPtr phDestFont);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ReleaseFont([In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hFont);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ResetFontMapping();
|
||||
}
|
||||
}
|
37
libse/DetectEncoding/Multilang/IMLangFontLink2.cs
Normal file
37
libse/DetectEncoding/Multilang/IMLangFontLink2.cs
Normal file
@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
#pragma warning disable 0108
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[ComImport, ComConversionLoss, InterfaceType((short)1), Guid("DCCFC162-2B38-11D2-B7EC-00C04F8F5D9A")]
|
||||
public interface IMLangFontLink2 : IMLangCodePages
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetCharCodePages([In] ushort chSrc, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetStrCodePages([In] ref ushort pszSrc, [In] int cchSrc, [In] uint dwPriorityCodePages, out uint pdwCodePages, out int pcchCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void CodePageToCodePages([In] uint uCodePage, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void CodePagesToCodePage([In] uint dwCodePages, [In] uint uDefaultCodePage, out uint puCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetFontCodePages([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hFont, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ReleaseFont([In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hFont);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ResetFontMapping();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void MapFont([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In] uint dwCodePages, [In] ushort chSrc, [Out, ComAliasName("MultiLanguage.wireHFONT")] IntPtr pFont);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetFontUnicodeRanges([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In, Out] ref uint puiRanges, out tagUNICODERANGE pUranges);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetScriptFontInfo([In] byte sid, [In] uint dwFlags, [In, Out] ref uint puiFonts, out tagSCRIPFONTINFO pScriptFont);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void CodePageToScriptID([In] uint uiCodePage, out byte pSid);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning restore 0108
|
16
libse/DetectEncoding/Multilang/IMLangLineBreakConsole.cs
Normal file
16
libse/DetectEncoding/Multilang/IMLangLineBreakConsole.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[ComImport, InterfaceType((short)1), Guid("F5BE2EE1-BFD7-11D0-B188-00AA0038C969")]
|
||||
public interface IMLangLineBreakConsole
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void BreakLineML([In, MarshalAs(UnmanagedType.Interface)] ICMLangString pSrcMLStr, [In] int lSrcPos, [In] int lSrcLen, [In] int cMinColumns, [In] int cMaxColumns, out int plLineLen, out int plSkipLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void BreakLineW([In] uint locale, [In] ref ushort pszSrc, [In] int cchSrc, [In] int cMaxColumns, out int pcchLine, out int pcchSkip);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void BreakLineA([In] uint locale, [In] uint uCodePage, [In] ref sbyte pszSrc, [In] int cchSrc, [In] int cMaxColumns, out int pcchLine, out int pcchSkip);
|
||||
}
|
||||
}
|
19
libse/DetectEncoding/Multilang/IMLangString.cs
Normal file
19
libse/DetectEncoding/Multilang/IMLangString.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[ComImport, Guid("C04D65CE-B70D-11D0-B188-00AA0038C969"), InterfaceType((short)1)]
|
||||
public interface IMLangString
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Sync([In] int fNoAccess);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
int GetLength();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void SetMLStr([In] int lDestPos, [In] int lDestLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pSrcMLStr, [In] int lSrcPos, [In] int lSrcLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetMLStr([In] int lSrcPos, [In] int lSrcLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter, [In] uint dwClsContext, [In] ref Guid piid, [MarshalAs(UnmanagedType.IUnknown)] out object ppDestMLStr, out int plDestPos, out int plDestLen);
|
||||
}
|
||||
}
|
39
libse/DetectEncoding/Multilang/IMLangStringAStr.cs
Normal file
39
libse/DetectEncoding/Multilang/IMLangStringAStr.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
#pragma warning disable 0108
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[ComImport, Guid("C04D65D2-B70D-11D0-B188-00AA0038C969"), ComConversionLoss, InterfaceType((short)1)]
|
||||
public interface IMLangStringAStr : IMLangString
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Sync([In] int fNoAccess);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
int GetLength();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void SetMLStr([In] int lDestPos, [In] int lDestLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pSrcMLStr, [In] int lSrcPos, [In] int lSrcLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetMLStr([In] int lSrcPos, [In] int lSrcLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter, [In] uint dwClsContext, [In] ref Guid piid, [MarshalAs(UnmanagedType.IUnknown)] out object ppDestMLStr, out int plDestPos, out int plDestLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void SetAStr([In] int lDestPos, [In] int lDestLen, [In] uint uCodePage, [In] ref sbyte pszSrc, [In] int cchSrc, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void SetStrBufA([In] int lDestPos, [In] int lDestLen, [In] uint uCodePage, [In, MarshalAs(UnmanagedType.Interface)] IMLangStringBufA pSrcBuf, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetAStr([In] int lSrcPos, [In] int lSrcLen, [In] uint uCodePageIn, out uint puCodePageOut, out sbyte pszDest, [In] int cchDest, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetStrBufA([In] int lSrcPos, [In] int lSrcMaxLen, out uint puDestCodePage, [MarshalAs(UnmanagedType.Interface)] out IMLangStringBufA ppDestBuf, out int plDestLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void LockAStr([In] int lSrcPos, [In] int lSrcLen, [In] int lFlags, [In] uint uCodePageIn, [In] int cchRequest, out uint puCodePageOut, [Out] IntPtr ppszDest, out int pcchDest, out int plDestLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void UnlockAStr([In] ref sbyte pszSrc, [In] int cchSrc, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void SetLocale([In] int lDestPos, [In] int lDestLen, [In] uint locale);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetLocale([In] int lSrcPos, [In] int lSrcMaxLen, out uint plocale, out int plLocalePos, out int plLocaleLen);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning restore 0108
|
21
libse/DetectEncoding/Multilang/IMLangStringBufA.cs
Normal file
21
libse/DetectEncoding/Multilang/IMLangStringBufA.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[ComImport, Guid("D24ACD23-BA72-11D0-B188-00AA0038C969"), InterfaceType((short)1), ComConversionLoss]
|
||||
public interface IMLangStringBufA
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetStatus(out int plFlags, out int pcchBuf);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void LockBuf([In] int cchOffset, [In] int cchMaxLock, [Out] IntPtr ppszBuf, out int pcchBuf);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void UnlockBuf([In] ref sbyte pszBuf, [In] int cchOffset, [In] int cchWrite);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Insert([In] int cchOffset, [In] int cchMaxInsert, out int pcchActual);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Delete([In] int cchOffset, [In] int cchDelete);
|
||||
}
|
||||
}
|
21
libse/DetectEncoding/Multilang/IMLangStringBufW.cs
Normal file
21
libse/DetectEncoding/Multilang/IMLangStringBufW.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[ComImport, InterfaceType((short)1), Guid("D24ACD21-BA72-11D0-B188-00AA0038C969"), ComConversionLoss]
|
||||
public interface IMLangStringBufW
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetStatus(out int plFlags, out int pcchBuf);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void LockBuf([In] int cchOffset, [In] int cchMaxLock, [Out] IntPtr ppszBuf, out int pcchBuf);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void UnlockBuf([In] ref ushort pszBuf, [In] int cchOffset, [In] int cchWrite);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Insert([In] int cchOffset, [In] int cchMaxInsert, out int pcchActual);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Delete([In] int cchOffset, [In] int cchDelete);
|
||||
}
|
||||
}
|
39
libse/DetectEncoding/Multilang/IMLangStringWStr.cs
Normal file
39
libse/DetectEncoding/Multilang/IMLangStringWStr.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
#pragma warning disable 0108
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[ComImport, InterfaceType((short)1), ComConversionLoss, Guid("C04D65D0-B70D-11D0-B188-00AA0038C969")]
|
||||
public interface IMLangStringWStr : IMLangString
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Sync([In] int fNoAccess);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
int GetLength();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void SetMLStr([In] int lDestPos, [In] int lDestLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pSrcMLStr, [In] int lSrcPos, [In] int lSrcLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetMLStr([In] int lSrcPos, [In] int lSrcLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter, [In] uint dwClsContext, [In] ref Guid piid, [MarshalAs(UnmanagedType.IUnknown)] out object ppDestMLStr, out int plDestPos, out int plDestLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void SetWStr([In] int lDestPos, [In] int lDestLen, [In] ref ushort pszSrc, [In] int cchSrc, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void SetStrBufW([In] int lDestPos, [In] int lDestLen, [In, MarshalAs(UnmanagedType.Interface)] IMLangStringBufW pSrcBuf, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetWStr([In] int lSrcPos, [In] int lSrcLen, out ushort pszDest, [In] int cchDest, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetStrBufW([In] int lSrcPos, [In] int lSrcMaxLen, [MarshalAs(UnmanagedType.Interface)] out IMLangStringBufW ppDestBuf, out int plDestLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void LockWStr([In] int lSrcPos, [In] int lSrcLen, [In] int lFlags, [In] int cchRequest, [Out] IntPtr ppszDest, out int pcchDest, out int plDestLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void UnlockWStr([In] ref ushort pszSrc, [In] int cchSrc, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void SetLocale([In] int lDestPos, [In] int lDestLen, [In] uint locale);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetLocale([In] int lSrcPos, [In] int lSrcMaxLen, out uint plocale, out int plLocalePos, out int plLocaleLen);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning restore 0108
|
40
libse/DetectEncoding/Multilang/IMultiLanguage.cs
Normal file
40
libse/DetectEncoding/Multilang/IMultiLanguage.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[ComImport, Guid("275C23E1-3747-11D0-9FEA-00AA003F8646"), InterfaceType((short)1)]
|
||||
public interface IMultiLanguage
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetNumberOfCodePageInfo(out uint pcCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetCodePageInfo([In] uint uiCodePage, out tagMIMECPINFO pCodePageInfo);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetFamilyCodePage([In] uint uiCodePage, out uint puiFamilyCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void EnumCodePages([In] uint grfFlags, [MarshalAs(UnmanagedType.Interface)] out IEnumCodePage ppEnumCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetCharsetInfo([In, MarshalAs(UnmanagedType.BStr)] string charset, out tagMIMECSETINFO pCharsetInfo);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void IsConvertible([In] uint dwSrcEncoding, [In] uint dwDstEncoding);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertString([In, Out] ref uint pdwMode, [In] uint dwSrcEncoding, [In] uint dwDstEncoding, [In] ref byte pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref byte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertStringToUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref ushort pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertStringFromUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref sbyte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertStringReset();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetRfc1766FromLcid([In] uint locale, [MarshalAs(UnmanagedType.BStr)] out string pbstrRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetLcidFromRfc1766(out uint plocale, [In, MarshalAs(UnmanagedType.BStr)] string bstrRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void EnumRfc1766([MarshalAs(UnmanagedType.Interface)] out IEnumRfc1766 ppEnumRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetRfc1766Info([In] uint locale, out tagRFC1766INFO pRfc1766Info);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void CreateConvertCharset([In] uint uiSrcCodePage, [In] uint uiDstCodePage, [In] uint dwProperty, [MarshalAs(UnmanagedType.Interface)] out ICMLangConvertCharset ppMLangConvertCharset);
|
||||
}
|
||||
}
|
74
libse/DetectEncoding/Multilang/IMultiLanguage2.cs
Normal file
74
libse/DetectEncoding/Multilang/IMultiLanguage2.cs
Normal file
@ -0,0 +1,74 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[ComImport, InterfaceType((short)1), Guid("DCCFC164-2B38-11D2-B7EC-00C04F8F5D9A")]
|
||||
public interface IMultiLanguage2
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetNumberOfCodePageInfo(out uint pcCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetCodePageInfo([In] uint uiCodePage, [In] ushort langId, out tagMIMECPINFO pCodePageInfo);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetFamilyCodePage([In] uint uiCodePage, out uint puiFamilyCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void EnumCodePages([In] uint grfFlags, [In] ushort langId, [MarshalAs(UnmanagedType.Interface)] out IEnumCodePage ppEnumCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetCharsetInfo([In, MarshalAs(UnmanagedType.BStr)] string charset, out tagMIMECSETINFO pCharsetInfo);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void IsConvertible([In] uint dwSrcEncoding, [In] uint dwDstEncoding);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertString([In, Out] ref uint pdwMode, [In] uint dwSrcEncoding, [In] uint dwDstEncoding, [In] ref byte pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref byte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertStringToUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref ushort pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertStringFromUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref sbyte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertStringReset();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetRfc1766FromLcid([In] uint locale, [MarshalAs(UnmanagedType.BStr)] out string pbstrRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetLcidFromRfc1766(out uint plocale, [In, MarshalAs(UnmanagedType.BStr)] string bstrRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void EnumRfc1766([In] ushort langId, [MarshalAs(UnmanagedType.Interface)] out IEnumRfc1766 ppEnumRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetRfc1766Info([In] uint locale, [In] ushort langId, out tagRFC1766INFO pRfc1766Info);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void CreateConvertCharset([In] uint uiSrcCodePage, [In] uint uiDstCodePage, [In] uint dwProperty, [MarshalAs(UnmanagedType.Interface)] out ICMLangConvertCharset ppMLangConvertCharset);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertStringInIStream([In, Out] ref uint pdwMode, [In] uint dwFlag, [In] ref ushort lpFallBack, [In] uint dwSrcEncoding, [In] uint dwDstEncoding, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmIn, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmOut);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertStringToUnicodeEx([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref ushort pDstStr, [In, Out] ref uint pcDstSize, [In] uint dwFlag, [In] ref ushort lpFallBack);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertStringFromUnicodeEx([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref sbyte pDstStr, [In, Out] ref uint pcDstSize, [In] uint dwFlag, [In] ref ushort lpFallBack);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void DetectCodepageInIStream([In] MLDETECTCP flags,
|
||||
[In] uint dwPrefWinCodePage,
|
||||
[In, MarshalAs(UnmanagedType.Interface)] IStream pstmIn,
|
||||
[In, Out] ref DetectEncodingInfo lpEncoding,
|
||||
[In, Out] ref int pnScores);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void DetectInputCodepage([In] MLDETECTCP flags, [In] uint dwPrefWinCodePage,
|
||||
[In] ref byte pSrcStr, [In, Out] ref int pcSrcSize,
|
||||
[In, Out] ref DetectEncodingInfo lpEncoding,
|
||||
[In, Out] ref int pnScores);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ValidateCodePage([In] uint uiCodePage, [In, ComAliasName("MultiLanguage.wireHWND")] ref _RemotableHandle hwnd);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetCodePageDescription([In] uint uiCodePage, [In] uint lcid, [In, Out, MarshalAs(UnmanagedType.LPWStr)] string lpWideCharStr, [In] int cchWideChar);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void IsCodePageInstallable([In] uint uiCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void SetMimeDBSource([In] tagMIMECONTF dwSource);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetNumberOfScripts(out uint pnScripts);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void EnumScripts([In] uint dwFlags, [In] ushort langId, [MarshalAs(UnmanagedType.Interface)] out IEnumScript ppEnumScript);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ValidateCodePageEx([In] uint uiCodePage, [In, ComAliasName("MultiLanguage.wireHWND")] ref _RemotableHandle hwnd, [In] uint dwfIODControl);
|
||||
}
|
||||
}
|
92
libse/DetectEncoding/Multilang/IMultiLanguage3.cs
Normal file
92
libse/DetectEncoding/Multilang/IMultiLanguage3.cs
Normal file
@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
#pragma warning disable 0108
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[ComImport, InterfaceType((short)1), Guid("4E5868AB-B157-4623-9ACC-6A1D9CAEBE04")]
|
||||
public interface IMultiLanguage3 : IMultiLanguage2
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetNumberOfCodePageInfo(out uint pcCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetCodePageInfo([In] uint uiCodePage, [In] ushort langId, out tagMIMECPINFO pCodePageInfo);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetFamilyCodePage([In] uint uiCodePage, out uint puiFamilyCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void EnumCodePages([In] uint grfFlags, [In] ushort langId, [MarshalAs(UnmanagedType.Interface)] out IEnumCodePage ppEnumCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetCharsetInfo([In, MarshalAs(UnmanagedType.BStr)] string Charset, out tagMIMECSETINFO pCharsetInfo);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void IsConvertible([In] uint dwSrcEncoding, [In] uint dwDstEncoding);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertString([In, Out] ref uint pdwMode, [In] uint dwSrcEncoding, [In] uint dwDstEncoding, [In] ref byte pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref byte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertStringToUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref ushort pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertStringFromUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref sbyte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertStringReset();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetRfc1766FromLcid([In] uint locale, [MarshalAs(UnmanagedType.BStr)] out string pbstrRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetLcidFromRfc1766(out uint plocale, [In, MarshalAs(UnmanagedType.BStr)] string bstrRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void EnumRfc1766([In] ushort langId, [MarshalAs(UnmanagedType.Interface)] out IEnumRfc1766 ppEnumRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetRfc1766Info([In] uint locale, [In] ushort langId, out tagRFC1766INFO pRfc1766Info);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void CreateConvertCharset([In] uint uiSrcCodePage, [In] uint uiDstCodePage, [In] uint dwProperty, [MarshalAs(UnmanagedType.Interface)] out ICMLangConvertCharset ppMLangConvertCharset);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertStringInIStream([In, Out] ref uint pdwMode, [In] uint dwFlag, [In] ref ushort lpFallBack, [In] uint dwSrcEncoding, [In] uint dwDstEncoding, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmIn, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmOut);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertStringToUnicodeEx([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref ushort pDstStr, [In, Out] ref uint pcDstSize, [In] uint dwFlag, [In] ref ushort lpFallBack);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertStringFromUnicodeEx([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, [In] ref sbyte pDstStr, [In, Out] ref uint pcDstSize, [In] uint dwFlag, [In] ref ushort lpFallBack);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void DetectCodepageInIStream([In] MLDETECTCP flags,
|
||||
[In] uint dwPrefWinCodePage,
|
||||
[In, MarshalAs(UnmanagedType.Interface)] IStream pstmIn,
|
||||
[In, Out] ref DetectEncodingInfo lpEncoding,
|
||||
[In, Out] ref int pnScores);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void DetectInputCodepage([In] MLDETECTCP flags, [In] uint dwPrefWinCodePage,
|
||||
[In] ref byte pSrcStr, [In, Out] ref int pcSrcSize,
|
||||
[In, Out] ref DetectEncodingInfo lpEncoding,
|
||||
[In, Out] ref int pnScores);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ValidateCodePage([In] uint uiCodePage, [In, ComAliasName("MultiLanguage.wireHWND")] ref _RemotableHandle hwnd);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetCodePageDescription([In] uint uiCodePage, [In] uint lcid, [In, Out, MarshalAs(UnmanagedType.LPWStr)] string lpWideCharStr, [In] int cchWideChar);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void IsCodePageInstallable([In] uint uiCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void SetMimeDBSource([In] tagMIMECONTF dwSource);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetNumberOfScripts(out uint pnScripts);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void EnumScripts([In] uint dwFlags, [In] ushort langId, [MarshalAs(UnmanagedType.Interface)] out IEnumScript ppEnumScript);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ValidateCodePageEx([In] uint uiCodePage, [In, ComAliasName("MultiLanguage.wireHWND")] ref _RemotableHandle hwnd, [In] uint dwfIODControl);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void DetectOutboundCodePage([In] MLCPF dwFlags,
|
||||
[In, MarshalAs(UnmanagedType.LPWStr)] string lpWideCharStr,
|
||||
[In] uint cchWideChar,
|
||||
[In] IntPtr puiPreferredCodePages,
|
||||
[In] uint nPreferredCodePages,
|
||||
[In] IntPtr puiDetectedCodePages,
|
||||
[In, Out] ref uint pnDetectedCodePages,
|
||||
[In] ref ushort lpSpecialChar);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void DetectOutboundCodePageInIStream([In] uint dwFlags, [In, MarshalAs(UnmanagedType.Interface)] IStream pStrIn, [In] ref uint puiPreferredCodePages, [In] uint nPreferredCodePages, [In] ref uint puiDetectedCodePages, [In, Out] ref uint pnDetectedCodePages, [In] ref ushort lpSpecialChar);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning restore 0108
|
15
libse/DetectEncoding/Multilang/ISequentialStream.cs
Normal file
15
libse/DetectEncoding/Multilang/ISequentialStream.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[ComImport, Guid("0C733A30-2A1C-11CE-ADE5-00AA0044773D"), InterfaceType((short)1)]
|
||||
public interface ISequentialStream
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void RemoteRead(IntPtr pv, uint cb, ref uint pcbRead);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void RemoteWrite([In] ref byte pv, [In] uint cb, ref uint pcbWritten);
|
||||
}
|
||||
}
|
37
libse/DetectEncoding/Multilang/IStream.cs
Normal file
37
libse/DetectEncoding/Multilang/IStream.cs
Normal file
@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
#pragma warning disable 0108
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[ComImport, Guid("0000000C-0000-0000-C000-000000000046"), InterfaceType((short)1)]
|
||||
public interface IStream : ISequentialStream
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void RemoteRead(IntPtr pv, uint cb, ref uint pcbRead);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void RemoteWrite([In] ref byte pv, [In] uint cb, ref uint pcbWritten);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void RemoteSeek([In] _LARGE_INTEGER dlibMove, [In] uint dwOrigin, IntPtr plibNewPosition);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void SetSize([In] _ULARGE_INTEGER libNewSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void RemoteCopyTo([In, MarshalAs(UnmanagedType.Interface)] IStream pstm, [In] _ULARGE_INTEGER cb, out _ULARGE_INTEGER pcbRead, out _ULARGE_INTEGER pcbWritten);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Commit([In] uint grfCommitFlags);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Revert();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void LockRegion([In] _ULARGE_INTEGER libOffset, [In] _ULARGE_INTEGER cb, [In] uint dwLockType);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void UnlockRegion([In] _ULARGE_INTEGER libOffset, [In] _ULARGE_INTEGER cb, [In] uint dwLockType);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Stat(out tagSTATSTG pstatstg, [In] uint grfStatFlag);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Clone([MarshalAs(UnmanagedType.Interface)] out IStream ppstm);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning restore 0108
|
11
libse/DetectEncoding/Multilang/_FILETIME.cs
Normal file
11
libse/DetectEncoding/Multilang/_FILETIME.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
public struct _FILETIME
|
||||
{
|
||||
public uint dwLowDateTime;
|
||||
public uint dwHighDateTime;
|
||||
}
|
||||
}
|
10
libse/DetectEncoding/Multilang/_LARGE_INTEGER.cs
Normal file
10
libse/DetectEncoding/Multilang/_LARGE_INTEGER.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||
public struct _LARGE_INTEGER
|
||||
{
|
||||
public long QuadPart;
|
||||
}
|
||||
}
|
11
libse/DetectEncoding/Multilang/_RemotableHandle.cs
Normal file
11
libse/DetectEncoding/Multilang/_RemotableHandle.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
public struct _RemotableHandle
|
||||
{
|
||||
public int fContext;
|
||||
public __MIDL_IWinTypes_0009 u;
|
||||
}
|
||||
}
|
10
libse/DetectEncoding/Multilang/_ULARGE_INTEGER.cs
Normal file
10
libse/DetectEncoding/Multilang/_ULARGE_INTEGER.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||
public struct _ULARGE_INTEGER
|
||||
{
|
||||
public ulong QuadPart;
|
||||
}
|
||||
}
|
13
libse/DetectEncoding/Multilang/__MIDL_IWinTypes_0009.cs
Normal file
13
libse/DetectEncoding/Multilang/__MIDL_IWinTypes_0009.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[StructLayout(LayoutKind.Explicit, Pack = 4)]
|
||||
public struct __MIDL_IWinTypes_0009
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public int hInproc;
|
||||
[FieldOffset(0)]
|
||||
public int hRemote;
|
||||
}
|
||||
}
|
15
libse/DetectEncoding/Multilang/tagDetectEncodingInfo.cs
Normal file
15
libse/DetectEncoding/Multilang/tagDetectEncodingInfo.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
/// Thanks to jannewe for finding the fix!
|
||||
/// http://www.codeproject.com/KB/recipes/DetectEncoding.aspx?msg=3247475#xx3247475xx
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct DetectEncodingInfo
|
||||
{
|
||||
public uint nLangID;
|
||||
public uint nCodePage;
|
||||
public int nDocPercent;
|
||||
public int nConfidence;
|
||||
}
|
||||
}
|
20
libse/DetectEncoding/Multilang/tagMIMECONTF.cs
Normal file
20
libse/DetectEncoding/Multilang/tagMIMECONTF.cs
Normal file
@ -0,0 +1,20 @@
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
|
||||
public enum tagMIMECONTF
|
||||
{
|
||||
MIMECONTF_BROWSER = 2,
|
||||
MIMECONTF_EXPORT = 0x400,
|
||||
MIMECONTF_IMPORT = 8,
|
||||
MIMECONTF_MAILNEWS = 1,
|
||||
MIMECONTF_MIME_IE4 = 0x10000000,
|
||||
MIMECONTF_MIME_LATEST = 0x20000000,
|
||||
MIMECONTF_MIME_REGISTRY = 0x40000000,
|
||||
MIMECONTF_MINIMAL = 4,
|
||||
MIMECONTF_PRIVCONVERTER = 0x10000,
|
||||
MIMECONTF_SAVABLE_BROWSER = 0x200,
|
||||
MIMECONTF_SAVABLE_MAILNEWS = 0x100,
|
||||
MIMECONTF_VALID = 0x20000,
|
||||
MIMECONTF_VALID_NLS = 0x40000
|
||||
}
|
||||
}
|
25
libse/DetectEncoding/Multilang/tagMIMECPINFO.cs
Normal file
25
libse/DetectEncoding/Multilang/tagMIMECPINFO.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
public struct tagMIMECPINFO
|
||||
{
|
||||
public uint dwFlags;
|
||||
public uint uiCodePage;
|
||||
public uint uiFamilyCodePage;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x40)]
|
||||
public ushort[] wszDescription;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)]
|
||||
public ushort[] wszWebCharset;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)]
|
||||
public ushort[] wszHeaderCharset;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)]
|
||||
public ushort[] wszBodyCharset;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)]
|
||||
public ushort[] wszFixedWidthFont;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)]
|
||||
public ushort[] wszProportionalFont;
|
||||
public byte bGDICharset;
|
||||
}
|
||||
}
|
13
libse/DetectEncoding/Multilang/tagMIMECSETINFO.cs
Normal file
13
libse/DetectEncoding/Multilang/tagMIMECSETINFO.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
public struct tagMIMECSETINFO
|
||||
{
|
||||
public uint uiCodePage;
|
||||
public uint uiInternetEncoding;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)]
|
||||
public ushort[] wszCharset;
|
||||
}
|
||||
}
|
35
libse/DetectEncoding/Multilang/tagMLCPF.cs
Normal file
35
libse/DetectEncoding/Multilang/tagMLCPF.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using System;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[Flags]
|
||||
public enum MLCPF
|
||||
{
|
||||
// Not currently supported.
|
||||
MLDETECTF_MAILNEWS = 0x0001,
|
||||
|
||||
// Not currently supported.
|
||||
MLDETECTF_BROWSER = 0x0002,
|
||||
|
||||
// Detection result must be valid for conversion and text rendering.
|
||||
MLDETECTF_VALID = 0x0004,
|
||||
|
||||
// Detection result must be valid for conversion.
|
||||
MLDETECTF_VALID_NLS = 0x0008,
|
||||
|
||||
//Preserve preferred code page order.
|
||||
//This is meaningful only if you have set the puiPreferredCodePages parameter in IMultiLanguage3::DetectOutboundCodePage or IMultiLanguage3::DetectOutboundCodePageInIStream.
|
||||
MLDETECTF_PRESERVE_ORDER = 0x0010,
|
||||
|
||||
// Only return one of the preferred code pages as the detection result.
|
||||
// This is meaningful only if you have set the puiPreferredCodePages parameter in IMultiLanguage3::DetectOutboundCodePage or IMultiLanguage3::DetectOutboundCodePageInIStream.
|
||||
MLDETECTF_PREFERRED_ONLY = 0x0020,
|
||||
|
||||
// Filter out graphical symbols and punctuation.
|
||||
MLDETECTF_FILTER_SPECIALCHAR = 0x0040,
|
||||
|
||||
// Return only Unicode codepages if the euro character is detected.
|
||||
MLDETECTF_EURO_UTF8 = 0x0080
|
||||
}
|
||||
|
||||
}
|
23
libse/DetectEncoding/Multilang/tagMLDETECTCP.cs
Normal file
23
libse/DetectEncoding/Multilang/tagMLDETECTCP.cs
Normal file
@ -0,0 +1,23 @@
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
public enum MLDETECTCP
|
||||
{
|
||||
// Default setting will be used.
|
||||
MLDETECTCP_NONE = 0,
|
||||
|
||||
// Input stream consists of 7-bit data.
|
||||
MLDETECTCP_7BIT = 1,
|
||||
|
||||
// Input stream consists of 8-bit data.
|
||||
MLDETECTCP_8BIT = 2,
|
||||
|
||||
// Input stream consists of double-byte data.
|
||||
MLDETECTCP_DBCS = 4,
|
||||
|
||||
// Input stream is an HTML page.
|
||||
MLDETECTCP_HTML = 8,
|
||||
|
||||
//Not currently supported.
|
||||
MLDETECTCP_NUMBER = 16
|
||||
}
|
||||
}
|
9
libse/DetectEncoding/Multilang/tagMLSTR_FLAGS.cs
Normal file
9
libse/DetectEncoding/Multilang/tagMLSTR_FLAGS.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
|
||||
public enum tagMLSTR_FLAGS
|
||||
{
|
||||
MLSTR_READ = 1,
|
||||
MLSTR_WRITE = 2
|
||||
}
|
||||
}
|
14
libse/DetectEncoding/Multilang/tagRFC1766INFO.cs
Normal file
14
libse/DetectEncoding/Multilang/tagRFC1766INFO.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
public struct tagRFC1766INFO
|
||||
{
|
||||
public uint lcid;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
||||
public ushort[] wszRfc1766;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)]
|
||||
public ushort[] wszLocaleName;
|
||||
}
|
||||
}
|
12
libse/DetectEncoding/Multilang/tagSCRIPFONTINFO.cs
Normal file
12
libse/DetectEncoding/Multilang/tagSCRIPFONTINFO.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||
public struct tagSCRIPFONTINFO
|
||||
{
|
||||
public long scripts;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)]
|
||||
public ushort[] wszFont;
|
||||
}
|
||||
}
|
17
libse/DetectEncoding/Multilang/tagSCRIPTINFO.cs
Normal file
17
libse/DetectEncoding/Multilang/tagSCRIPTINFO.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
public struct tagSCRIPTINFO
|
||||
{
|
||||
public byte ScriptId;
|
||||
public uint uiCodePage;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x30)]
|
||||
public ushort[] wszDescription;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)]
|
||||
public ushort[] wszFixedWidthFont;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)]
|
||||
public ushort[] wszProportionalFont;
|
||||
}
|
||||
}
|
22
libse/DetectEncoding/Multilang/tagSTATSTG.cs
Normal file
22
libse/DetectEncoding/Multilang/tagSTATSTG.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||
public struct tagSTATSTG
|
||||
{
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
public string pwcsName;
|
||||
public uint type;
|
||||
public _ULARGE_INTEGER cbSize;
|
||||
public _FILETIME mtime;
|
||||
public _FILETIME ctime;
|
||||
public _FILETIME atime;
|
||||
public uint grfMode;
|
||||
public uint grfLocksSupported;
|
||||
public Guid clsid;
|
||||
public uint grfStateBits;
|
||||
public uint reserved;
|
||||
}
|
||||
}
|
11
libse/DetectEncoding/Multilang/tagUNICODERANGE.cs
Normal file
11
libse/DetectEncoding/Multilang/tagUNICODERANGE.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.DetectEncoding.Multilang
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 2)]
|
||||
public struct tagUNICODERANGE
|
||||
{
|
||||
public ushort wcFrom;
|
||||
public ushort wcTo;
|
||||
}
|
||||
}
|
258
libse/Dictionaries/NamesList.cs
Normal file
258
libse/Dictionaries/NamesList.cs
Normal file
@ -0,0 +1,258 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.Dictionaries
|
||||
{
|
||||
public class NamesList
|
||||
{
|
||||
private readonly string _dictionaryFolder;
|
||||
private readonly HashSet<string> _namesList;
|
||||
private readonly HashSet<string> _namesMultiList;
|
||||
private readonly string _languageName;
|
||||
|
||||
public NamesList(string dictionaryFolder, string languageName, bool useOnlineNamesEtc, string namesEtcUrl)
|
||||
{
|
||||
_dictionaryFolder = dictionaryFolder;
|
||||
_languageName = languageName;
|
||||
|
||||
_namesList = new HashSet<string>();
|
||||
_namesMultiList = new HashSet<string>();
|
||||
|
||||
if (useOnlineNamesEtc && !string.IsNullOrEmpty(namesEtcUrl))
|
||||
{
|
||||
try
|
||||
{
|
||||
var xml = Utilities.DownloadString(Configuration.Settings.WordLists.NamesEtcUrl);
|
||||
var namesDoc = new XmlDocument();
|
||||
namesDoc.LoadXml(xml);
|
||||
LoadNames(_namesList, _namesMultiList, namesDoc);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
LoadNamesList(Path.Combine(_dictionaryFolder, "names_etc.xml"), _namesList, _namesMultiList);
|
||||
System.Diagnostics.Debug.WriteLine(exception.Message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LoadNamesList(Path.Combine(_dictionaryFolder, "names_etc.xml"), _namesList, _namesMultiList);
|
||||
}
|
||||
|
||||
LoadNamesList(GetLocalNamesFileName(), _namesList, _namesMultiList);
|
||||
|
||||
var userFile = GetLocalNamesUserFileName();
|
||||
LoadNamesList(userFile, _namesList, _namesMultiList);
|
||||
UnloadRemovedNames(userFile);
|
||||
}
|
||||
|
||||
public List<string> GetAllNames()
|
||||
{
|
||||
var list = new List<string>();
|
||||
foreach (var name in _namesList)
|
||||
{
|
||||
list.Add(name);
|
||||
}
|
||||
foreach (var name in _namesMultiList)
|
||||
{
|
||||
list.Add(name);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public HashSet<string> GetNames()
|
||||
{
|
||||
return _namesList;
|
||||
}
|
||||
|
||||
public HashSet<string> GetMultiNames()
|
||||
{
|
||||
return _namesMultiList;
|
||||
}
|
||||
|
||||
private void UnloadRemovedNames(string fileName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fileName) || !File.Exists(fileName))
|
||||
return;
|
||||
|
||||
var namesDoc = new XmlDocument();
|
||||
namesDoc.Load(fileName);
|
||||
if (namesDoc.DocumentElement == null)
|
||||
return;
|
||||
|
||||
foreach (XmlNode node in namesDoc.DocumentElement.SelectNodes("removed_name"))
|
||||
{
|
||||
string s = node.InnerText.Trim();
|
||||
if (s.Contains(' '))
|
||||
{
|
||||
if (_namesMultiList.Contains(s))
|
||||
_namesMultiList.Remove(s);
|
||||
}
|
||||
else if (_namesList.Contains(s))
|
||||
{
|
||||
_namesList.Remove(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string GetLocalNamesFileName()
|
||||
{
|
||||
if (_languageName.Length == 2)
|
||||
{
|
||||
string[] files = Directory.GetFiles(_dictionaryFolder, _languageName + "_??_names_etc.xml");
|
||||
if (files.Length > 0)
|
||||
return files[0];
|
||||
}
|
||||
return Path.Combine(_dictionaryFolder, _languageName + "_names_etc.xml");
|
||||
}
|
||||
|
||||
private string GetLocalNamesUserFileName()
|
||||
{
|
||||
if (_languageName.Length == 2)
|
||||
{
|
||||
string[] files = Directory.GetFiles(_dictionaryFolder, _languageName + "_??_names_etc_user.xml");
|
||||
if (files.Length > 0)
|
||||
return files[0];
|
||||
}
|
||||
return Path.Combine(_dictionaryFolder, _languageName + "_names_etc_user.xml");
|
||||
}
|
||||
|
||||
private static void LoadNamesList(string fileName, HashSet<string> namesList, HashSet<string> namesMultiList)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fileName) || !File.Exists(fileName))
|
||||
return;
|
||||
|
||||
var namesDoc = new XmlDocument();
|
||||
namesDoc.Load(fileName);
|
||||
if (namesDoc.DocumentElement == null)
|
||||
return;
|
||||
|
||||
LoadNames(namesList, namesMultiList, namesDoc);
|
||||
}
|
||||
|
||||
private static void LoadNames(HashSet<string> namesList, HashSet<string> namesMultiList, XmlDocument namesDoc)
|
||||
{
|
||||
foreach (XmlNode node in namesDoc.DocumentElement.SelectNodes("name"))
|
||||
{
|
||||
string s = node.InnerText.Trim();
|
||||
if (s.Contains(' ') && !namesMultiList.Contains(s))
|
||||
{
|
||||
namesMultiList.Add(s);
|
||||
}
|
||||
else if (!namesList.Contains(s))
|
||||
{
|
||||
namesList.Add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(string name)
|
||||
{
|
||||
name = name.Trim();
|
||||
if (name.Length > 1 && _namesList.Contains(name) || _namesMultiList.Contains(name))
|
||||
{
|
||||
if (_namesList.Contains(name))
|
||||
_namesList.Remove(name);
|
||||
if (_namesMultiList.Contains(name))
|
||||
_namesMultiList.Remove(name);
|
||||
|
||||
var userList = new HashSet<string>();
|
||||
var fileName = GetLocalNamesUserFileName();
|
||||
LoadNamesList(fileName, userList, userList);
|
||||
|
||||
var namesDoc = new XmlDocument();
|
||||
if (File.Exists(fileName))
|
||||
{
|
||||
namesDoc.Load(fileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
namesDoc.LoadXml("<ignore_words />");
|
||||
}
|
||||
|
||||
if (userList.Contains(name))
|
||||
{
|
||||
userList.Remove(name);
|
||||
XmlNode nodeToRemove = null;
|
||||
foreach (XmlNode node in namesDoc.DocumentElement.SelectNodes("name"))
|
||||
{
|
||||
if (node.InnerText == name)
|
||||
{
|
||||
nodeToRemove = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nodeToRemove != null)
|
||||
namesDoc.DocumentElement.RemoveChild(nodeToRemove);
|
||||
}
|
||||
else
|
||||
{
|
||||
XmlNode node = namesDoc.CreateElement("removed_name");
|
||||
node.InnerText = name;
|
||||
namesDoc.DocumentElement.AppendChild(node);
|
||||
}
|
||||
namesDoc.Save(fileName);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Add(string name)
|
||||
{
|
||||
name = name.Trim();
|
||||
if (name.Length > 1 && name.ContainsLetter())
|
||||
{
|
||||
if (name.Contains(' '))
|
||||
{
|
||||
if (!_namesMultiList.Contains(name))
|
||||
_namesMultiList.Add(name);
|
||||
}
|
||||
else if (!_namesList.Contains(name))
|
||||
{
|
||||
_namesList.Add(name);
|
||||
}
|
||||
|
||||
var fileName = GetLocalNamesUserFileName();
|
||||
var namesEtcDoc = new XmlDocument();
|
||||
if (File.Exists(fileName))
|
||||
namesEtcDoc.Load(fileName);
|
||||
else
|
||||
namesEtcDoc.LoadXml("<ignore_words />");
|
||||
|
||||
XmlNode de = namesEtcDoc.DocumentElement;
|
||||
if (de != null)
|
||||
{
|
||||
XmlNode node = namesEtcDoc.CreateElement("name");
|
||||
node.InnerText = name;
|
||||
de.AppendChild(node);
|
||||
namesEtcDoc.Save(fileName);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool IsInNamesEtcMultiWordList(string text, string word)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text))
|
||||
return false;
|
||||
|
||||
text = text.Replace(Environment.NewLine, " ");
|
||||
text = text.FixExtraSpaces();
|
||||
|
||||
foreach (string s in _namesMultiList)
|
||||
{
|
||||
if (s.Contains(word) && text.Contains(s))
|
||||
{
|
||||
if (s.StartsWith(word + " ", StringComparison.Ordinal) || s.EndsWith(" " + word, StringComparison.Ordinal) || s.Contains(" " + word + " "))
|
||||
return true;
|
||||
if (word == s)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
962
libse/Dictionaries/OcrFixReplaceList.cs
Normal file
962
libse/Dictionaries/OcrFixReplaceList.cs
Normal file
@ -0,0 +1,962 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Forms;
|
||||
using System.Xml;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.Dictionaries
|
||||
{
|
||||
public class OcrFixReplaceList
|
||||
{
|
||||
private static readonly Regex RegExQuestion = new Regex(@"\S\?[A-ZÆØÅÄÖÉÈÀÙÂÊÎÔÛËÏa-zæøåäöéèàùâêîôûëï]", RegexOptions.Compiled);
|
||||
private static readonly Regex RegExIandZero = new Regex(@"[a-zæøåöääöéèàùâêîôûëï][I1]", RegexOptions.Compiled);
|
||||
private static readonly Regex RegExTime1 = new Regex(@"[a-zæøåöääöéèàùâêîôûëï]0", RegexOptions.Compiled);
|
||||
private static readonly Regex RegExTime2 = new Regex(@"0[a-zæøåöääöéèàùâêîôûëï]", RegexOptions.Compiled);
|
||||
private static readonly Regex HexNumber = new Regex(@"^#?[\dABDEFabcdef]+$", RegexOptions.Compiled);
|
||||
private static readonly Regex StartEndEndsWithNumber = new Regex(@"^\d+.+\d$", RegexOptions.Compiled);
|
||||
|
||||
public Dictionary<string, string> WordReplaceList;
|
||||
public Dictionary<string, string> PartialLineWordBoundaryReplaceList;
|
||||
private readonly Dictionary<string, string> _partialLineAlwaysReplaceList;
|
||||
private readonly Dictionary<string, string> _beginLineReplaceList;
|
||||
private readonly Dictionary<string, string> _endLineReplaceList;
|
||||
private readonly Dictionary<string, string> _wholeLineReplaceList;
|
||||
private readonly Dictionary<string, string> _partialWordReplaceListAlways;
|
||||
private readonly Dictionary<string, string> _partialWordReplaceList;
|
||||
private readonly Dictionary<string, string> _regExList;
|
||||
private readonly string _replaceListXmlFileName;
|
||||
|
||||
public OcrFixReplaceList(string replaceListXmlFileName)
|
||||
{
|
||||
_replaceListXmlFileName = replaceListXmlFileName;
|
||||
WordReplaceList = new Dictionary<string, string>();
|
||||
PartialLineWordBoundaryReplaceList = new Dictionary<string, string>();
|
||||
_partialLineAlwaysReplaceList = new Dictionary<string, string>();
|
||||
_beginLineReplaceList = new Dictionary<string, string>();
|
||||
_endLineReplaceList = new Dictionary<string, string>();
|
||||
_wholeLineReplaceList = new Dictionary<string, string>();
|
||||
_partialWordReplaceListAlways = new Dictionary<string, string>();
|
||||
_partialWordReplaceList = new Dictionary<string, string>();
|
||||
_regExList = new Dictionary<string, string>();
|
||||
|
||||
var doc = LoadXmlReplaceListDocument();
|
||||
var userDoc = LoadXmlReplaceListUserDocument();
|
||||
|
||||
WordReplaceList = LoadReplaceList(doc, "WholeWords");
|
||||
_partialWordReplaceListAlways = LoadReplaceList(doc, "PartialWordsAlways");
|
||||
_partialWordReplaceList = LoadReplaceList(doc, "PartialWords");
|
||||
PartialLineWordBoundaryReplaceList = LoadReplaceList(doc, "PartialLines");
|
||||
_partialLineAlwaysReplaceList = LoadReplaceList(doc, "PartialAlwaysLines");
|
||||
_beginLineReplaceList = LoadReplaceList(doc, "BeginLines");
|
||||
_endLineReplaceList = LoadReplaceList(doc, "EndLines");
|
||||
_wholeLineReplaceList = LoadReplaceList(doc, "WholeLines");
|
||||
_regExList = LoadRegExList(doc, "RegularExpressions");
|
||||
|
||||
foreach (var kp in LoadReplaceList(userDoc, "RemovedWholeWords"))
|
||||
{
|
||||
if (WordReplaceList.ContainsKey(kp.Key))
|
||||
WordReplaceList.Remove(kp.Key);
|
||||
}
|
||||
foreach (var kp in LoadReplaceList(userDoc, "WholeWords"))
|
||||
{
|
||||
if (!WordReplaceList.ContainsKey(kp.Key))
|
||||
WordReplaceList.Add(kp.Key, kp.Value);
|
||||
}
|
||||
|
||||
foreach (var kp in LoadReplaceList(userDoc, "RemovedPartialLines"))
|
||||
{
|
||||
if (PartialLineWordBoundaryReplaceList.ContainsKey(kp.Key))
|
||||
PartialLineWordBoundaryReplaceList.Remove(kp.Key);
|
||||
}
|
||||
foreach (var kp in LoadReplaceList(userDoc, "PartialLines"))
|
||||
{
|
||||
if (!PartialLineWordBoundaryReplaceList.ContainsKey(kp.Key))
|
||||
PartialLineWordBoundaryReplaceList.Add(kp.Key, kp.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public static OcrFixReplaceList FromLanguageId(string languageId)
|
||||
{
|
||||
return new OcrFixReplaceList(Configuration.DictionariesFolder + languageId + "_OCRFixReplaceList.xml");
|
||||
}
|
||||
|
||||
private static Dictionary<string, string> LoadReplaceList(XmlDocument doc, string name)
|
||||
{
|
||||
var list = new Dictionary<string, string>();
|
||||
if (doc.DocumentElement != null)
|
||||
{
|
||||
XmlNode node = doc.DocumentElement.SelectSingleNode(name);
|
||||
if (node != null)
|
||||
{
|
||||
foreach (XmlNode item in node.ChildNodes)
|
||||
{
|
||||
if (item.Attributes != null && item.Attributes["to"] != null && item.Attributes["from"] != null)
|
||||
{
|
||||
string to = item.Attributes["to"].InnerText;
|
||||
string from = item.Attributes["from"].InnerText;
|
||||
if (!list.ContainsKey(from))
|
||||
list.Add(from, to);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static Dictionary<string, string> LoadRegExList(XmlDocument doc, string name)
|
||||
{
|
||||
var list = new Dictionary<string, string>();
|
||||
if (doc.DocumentElement != null)
|
||||
{
|
||||
XmlNode node = doc.DocumentElement.SelectSingleNode(name);
|
||||
if (node != null)
|
||||
{
|
||||
foreach (XmlNode item in node.ChildNodes)
|
||||
{
|
||||
if (item.Attributes != null && item.Attributes["replaceWith"] != null && item.Attributes["find"] != null)
|
||||
{
|
||||
string to = item.Attributes["replaceWith"].InnerText;
|
||||
string from = item.Attributes["find"].InnerText;
|
||||
if (!list.ContainsKey(from))
|
||||
list.Add(from, to);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public string FixOcrErrorViaLineReplaceList(string input)
|
||||
{
|
||||
// Whole fromLine
|
||||
foreach (string from in _wholeLineReplaceList.Keys)
|
||||
{
|
||||
if (input == from)
|
||||
return _wholeLineReplaceList[from];
|
||||
}
|
||||
|
||||
string newText = input;
|
||||
string pre = string.Empty;
|
||||
if (newText.StartsWith("<i>", StringComparison.Ordinal))
|
||||
{
|
||||
pre += "<i>";
|
||||
newText = newText.Remove(0, 3);
|
||||
}
|
||||
while (newText.Length > 1 && @" -""['¶(".Contains(newText[0]))
|
||||
{
|
||||
pre += newText[0];
|
||||
newText = newText.Substring(1);
|
||||
}
|
||||
if (newText.StartsWith("<i>", StringComparison.Ordinal))
|
||||
{
|
||||
pre += "<i>";
|
||||
newText = newText.Remove(0, 3);
|
||||
}
|
||||
|
||||
// begin fromLine
|
||||
var lines = newText.SplitToLines();
|
||||
var sb = new StringBuilder();
|
||||
foreach (string l in lines)
|
||||
{
|
||||
string s = l;
|
||||
foreach (string from in _beginLineReplaceList.Keys)
|
||||
{
|
||||
if (s.Contains(from))
|
||||
{
|
||||
if (s.StartsWith(from))
|
||||
s = s.Remove(0, from.Length).Insert(0, _beginLineReplaceList[from]);
|
||||
if (s.Contains(". " + from))
|
||||
s = s.Replace(". " + from, ". " + _beginLineReplaceList[from]);
|
||||
if (s.Contains("! " + from))
|
||||
s = s.Replace("! " + from, "! " + _beginLineReplaceList[from]);
|
||||
if (s.Contains("? " + from))
|
||||
s = s.Replace("? " + from, "? " + _beginLineReplaceList[from]);
|
||||
if (s.Contains("." + Environment.NewLine + from))
|
||||
s = s.Replace(". " + Environment.NewLine + from, ". " + Environment.NewLine + _beginLineReplaceList[from]);
|
||||
if (s.Contains("! " + Environment.NewLine + from))
|
||||
s = s.Replace("! " + Environment.NewLine + from, "! " + Environment.NewLine + _beginLineReplaceList[from]);
|
||||
if (s.Contains("? " + Environment.NewLine + from))
|
||||
s = s.Replace("? " + Environment.NewLine + from, "? " + Environment.NewLine + _beginLineReplaceList[from]);
|
||||
if (s.StartsWith('"') && !from.StartsWith('"') && s.StartsWith("\"" + from))
|
||||
s = s.Replace("\"" + from, "\"" + _beginLineReplaceList[from]);
|
||||
}
|
||||
}
|
||||
sb.AppendLine(s);
|
||||
}
|
||||
newText = sb.ToString().TrimEnd('\r').TrimEnd('\n').TrimEnd('\r').TrimEnd('\n');
|
||||
newText = pre + newText;
|
||||
|
||||
string post = string.Empty;
|
||||
if (newText.EndsWith("</i>", StringComparison.Ordinal))
|
||||
{
|
||||
newText = newText.Remove(newText.Length - 4, 4);
|
||||
post = "</i>";
|
||||
}
|
||||
|
||||
foreach (string from in _endLineReplaceList.Keys)
|
||||
{
|
||||
if (newText.EndsWith(from, StringComparison.Ordinal))
|
||||
{
|
||||
int position = (newText.Length - from.Length);
|
||||
newText = newText.Remove(position).Insert(position, _endLineReplaceList[from]);
|
||||
}
|
||||
}
|
||||
newText += post;
|
||||
|
||||
foreach (string from in PartialLineWordBoundaryReplaceList.Keys)
|
||||
{
|
||||
if (newText.FastIndexOf(from) >= 0)
|
||||
newText = ReplaceWord(newText, from, PartialLineWordBoundaryReplaceList[from]);
|
||||
}
|
||||
|
||||
foreach (string from in _partialLineAlwaysReplaceList.Keys)
|
||||
{
|
||||
if (newText.FastIndexOf(from) >= 0)
|
||||
newText = newText.Replace(from, _partialLineAlwaysReplaceList[from]);
|
||||
}
|
||||
|
||||
foreach (string findWhat in _regExList.Keys)
|
||||
{
|
||||
newText = Regex.Replace(newText, findWhat, _regExList[findWhat], RegexOptions.Multiline);
|
||||
}
|
||||
|
||||
return newText;
|
||||
}
|
||||
|
||||
private static string AddToGuessList(List<string> list, string word, int index, string letter, string replaceLetters)
|
||||
{
|
||||
if (string.IsNullOrEmpty(word) || index < 0 || index + letter.Length - 1 >= word.Length)
|
||||
return word;
|
||||
|
||||
string s = word.Remove(index, letter.Length);
|
||||
if (index >= s.Length)
|
||||
s += replaceLetters;
|
||||
else
|
||||
s = s.Insert(index, replaceLetters);
|
||||
|
||||
if (!list.Contains(s))
|
||||
list.Add(s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public IEnumerable<string> CreateGuessesFromLetters(string word)
|
||||
{
|
||||
var list = new List<string>();
|
||||
foreach (string letter in _partialWordReplaceList.Keys)
|
||||
{
|
||||
string s = word;
|
||||
int i = 0;
|
||||
while (s.Contains(letter) && i < 10)
|
||||
{
|
||||
int index = s.FastIndexOf(letter);
|
||||
s = AddToGuessList(list, s, index, letter, _partialWordReplaceList[letter]);
|
||||
AddToGuessList(list, word, index, letter, _partialWordReplaceList[letter]);
|
||||
i++;
|
||||
}
|
||||
s = word;
|
||||
i = 0;
|
||||
while (s.Contains(letter) && i < 10)
|
||||
{
|
||||
int index = s.LastIndexOf(letter, StringComparison.Ordinal);
|
||||
s = AddToGuessList(list, s, index, letter, _partialWordReplaceList[letter]);
|
||||
AddToGuessList(list, word, index, letter, _partialWordReplaceList[letter]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public string FixCommonWordErrors(string word)
|
||||
{
|
||||
if (Configuration.Settings.Tools.OcrFixUseHardcodedRules)
|
||||
{
|
||||
word = word.Replace("fi", "fi");
|
||||
word = word.Replace("ν", "v"); // NOTE: first 'v' is a special unicode character!!!!
|
||||
|
||||
if (word.Contains('’'))
|
||||
word = word.Replace('’', '\'');
|
||||
|
||||
if (word.Contains('`'))
|
||||
word = word.Replace('`', '\'');
|
||||
|
||||
if (word.Contains('‘'))
|
||||
word = word.Replace('‘', '\'');
|
||||
|
||||
if (word.Contains('—'))
|
||||
word = word.Replace('—', '-');
|
||||
|
||||
while (word.Contains("--"))
|
||||
word = word.Replace("--", "-");
|
||||
|
||||
if (word.Contains('|'))
|
||||
word = word.Replace('|', 'l');
|
||||
|
||||
if (word.Contains("vx/"))
|
||||
word = word.Replace("vx/", "w");
|
||||
|
||||
if (word.Contains('¤'))
|
||||
{
|
||||
if (Regex.IsMatch(word, "[A-ZÆØÅÄÖÉÈÀÙÂÊÎÔÛËÏa-zæøåäöéèàùâêîôûëï]¤"))
|
||||
word = word.Replace('¤', 'o');
|
||||
}
|
||||
}
|
||||
|
||||
//always replace list
|
||||
foreach (string letter in _partialWordReplaceListAlways.Keys)
|
||||
word = word.Replace(letter, _partialWordReplaceListAlways[letter]);
|
||||
|
||||
string pre = string.Empty;
|
||||
string post = string.Empty;
|
||||
|
||||
if (word.StartsWith("<i>", StringComparison.Ordinal))
|
||||
{
|
||||
pre += "<i>";
|
||||
word = word.Remove(0, 3);
|
||||
}
|
||||
while (word.Length > 2 && word.StartsWith(Environment.NewLine, StringComparison.Ordinal))
|
||||
{
|
||||
pre += Environment.NewLine;
|
||||
word = word.Substring(2);
|
||||
}
|
||||
|
||||
while (word.Length > 1 && word[0] == '-')
|
||||
{
|
||||
pre += "-";
|
||||
word = word.Substring(1);
|
||||
}
|
||||
while (word.Length > 1 && word[0] == '.')
|
||||
{
|
||||
pre += ".";
|
||||
word = word.Substring(1);
|
||||
}
|
||||
while (word.Length > 1 && word[0] == '"')
|
||||
{
|
||||
pre += "\"";
|
||||
word = word.Substring(1);
|
||||
}
|
||||
if (word.Length > 1 && word[0] == '(')
|
||||
{
|
||||
pre += "(";
|
||||
word = word.Substring(1);
|
||||
}
|
||||
if (word.StartsWith("<i>", StringComparison.Ordinal))
|
||||
{
|
||||
pre += "<i>";
|
||||
word = word.Remove(0, 3);
|
||||
}
|
||||
while (word.Length > 2 && word.EndsWith(Environment.NewLine))
|
||||
{
|
||||
post += Environment.NewLine;
|
||||
word = word.Substring(0, word.Length - 2);
|
||||
}
|
||||
while (word.Length > 1 && word.EndsWith('"'))
|
||||
{
|
||||
post = post + "\"";
|
||||
word = word.Substring(0, word.Length - 1);
|
||||
}
|
||||
while (word.Length > 1 && word.EndsWith('.'))
|
||||
{
|
||||
post = post + ".";
|
||||
word = word.Substring(0, word.Length - 1);
|
||||
}
|
||||
while (word.EndsWith(',') && word.Length > 1)
|
||||
{
|
||||
post = post + ",";
|
||||
word = word.Substring(0, word.Length - 1);
|
||||
}
|
||||
while (word.EndsWith('?') && word.Length > 1)
|
||||
{
|
||||
post = post + "?";
|
||||
word = word.Substring(0, word.Length - 1);
|
||||
}
|
||||
while (word.EndsWith('!') && word.Length > 1)
|
||||
{
|
||||
post = post + "!";
|
||||
word = word.Substring(0, word.Length - 1);
|
||||
}
|
||||
while (word.EndsWith(')') && word.Length > 1)
|
||||
{
|
||||
post = post + ")";
|
||||
word = word.Substring(0, word.Length - 1);
|
||||
}
|
||||
if (word.EndsWith("</i>", StringComparison.Ordinal))
|
||||
{
|
||||
post = post + "</i>";
|
||||
word = word.Remove(word.Length - 4, 4);
|
||||
}
|
||||
string preWordPost = pre + word + post;
|
||||
if (word.Length == 0)
|
||||
return preWordPost;
|
||||
|
||||
if (word.Contains('?'))
|
||||
{
|
||||
var match = RegExQuestion.Match(word);
|
||||
if (match.Success)
|
||||
word = word.Insert(match.Index + 2, " ");
|
||||
}
|
||||
|
||||
foreach (string from in WordReplaceList.Keys)
|
||||
{
|
||||
if (word.Length == from.Length)
|
||||
{
|
||||
if (word == from)
|
||||
return pre + WordReplaceList[from] + post;
|
||||
}
|
||||
else if (word.Length + post.Length == from.Length)
|
||||
{
|
||||
if (string.CompareOrdinal(word + post, from) == 0)
|
||||
return pre + WordReplaceList[from];
|
||||
}
|
||||
if (pre.Length + word.Length + post.Length == from.Length && string.CompareOrdinal(preWordPost, from) == 0)
|
||||
{
|
||||
return WordReplaceList[from];
|
||||
}
|
||||
}
|
||||
|
||||
if (Configuration.Settings.Tools.OcrFixUseHardcodedRules)
|
||||
{
|
||||
// uppercase I or 1 inside lowercase fromWord (will be replaced by lowercase L)
|
||||
word = FixIor1InsideLowerCaseWord(word);
|
||||
|
||||
// uppercase 0 inside lowercase fromWord (will be replaced by lowercase L)
|
||||
word = Fix0InsideLowerCaseWord(word);
|
||||
|
||||
// uppercase I or 1 inside lowercase fromWord (will be replaced by lowercase L)
|
||||
word = FixIor1InsideLowerCaseWord(word);
|
||||
|
||||
word = FixLowerCaseLInsideUpperCaseWord(word); // eg. SCARLETTl => SCARLETTI
|
||||
}
|
||||
|
||||
// Retry fromWord replace list
|
||||
foreach (string from in WordReplaceList.Keys)
|
||||
{
|
||||
if (word.Length == from.Length)
|
||||
{
|
||||
if (string.CompareOrdinal(word, from) == 0)
|
||||
return pre + WordReplaceList[from] + post;
|
||||
}
|
||||
else if (word.Length + post.Length == from.Length)
|
||||
{
|
||||
if (string.CompareOrdinal(word + post, from) == 0)
|
||||
return pre + WordReplaceList[from];
|
||||
}
|
||||
if (pre.Length + word.Length + post.Length == from.Length && string.CompareOrdinal(preWordPost, from) == 0)
|
||||
{
|
||||
return WordReplaceList[from];
|
||||
}
|
||||
}
|
||||
|
||||
return preWordPost;
|
||||
}
|
||||
|
||||
public static string FixLowerCaseLInsideUpperCaseWord(string word)
|
||||
{
|
||||
if (word.Length > 3 && word.Replace("l", string.Empty).ToUpper() == word.Replace("l", string.Empty))
|
||||
{
|
||||
if (!word.Contains('<') && !word.Contains('>') && !word.Contains('\''))
|
||||
{
|
||||
word = word.Replace('l', 'I');
|
||||
}
|
||||
}
|
||||
return word;
|
||||
}
|
||||
|
||||
public static string FixIor1InsideLowerCaseWord(string word)
|
||||
{
|
||||
if (StartEndEndsWithNumber.IsMatch(word))
|
||||
return word;
|
||||
|
||||
if (word.Contains('2') ||
|
||||
word.Contains('3') ||
|
||||
word.Contains('4') ||
|
||||
word.Contains('5') ||
|
||||
word.Contains('6') ||
|
||||
word.Contains('7') ||
|
||||
word.Contains('8') ||
|
||||
word.Contains('9'))
|
||||
return word;
|
||||
|
||||
if (HexNumber.IsMatch(word))
|
||||
return word;
|
||||
|
||||
if (word.LastIndexOf('I') > 0 || word.LastIndexOf('1') > 0)
|
||||
{
|
||||
var match = RegExIandZero.Match(word);
|
||||
while (match.Success)
|
||||
{
|
||||
if (word[match.Index + 1] == 'I' || word[match.Index + 1] == '1')
|
||||
{
|
||||
bool doFix = word[match.Index + 1] != 'I' && match.Index >= 1 && word.Substring(match.Index - 1).StartsWith("Mc");
|
||||
if (word[match.Index + 1] == 'I' && match.Index >= 2 && word.Substring(match.Index - 2).StartsWith("Mac"))
|
||||
doFix = false;
|
||||
|
||||
if (doFix)
|
||||
{
|
||||
string oldText = word;
|
||||
word = word.Substring(0, match.Index + 1) + "l";
|
||||
if (match.Index + 2 < oldText.Length)
|
||||
word += oldText.Substring(match.Index + 2);
|
||||
}
|
||||
}
|
||||
match = RegExIandZero.Match(word, match.Index + 1);
|
||||
}
|
||||
}
|
||||
return word;
|
||||
}
|
||||
|
||||
public static string Fix0InsideLowerCaseWord(string word)
|
||||
{
|
||||
if (StartEndEndsWithNumber.IsMatch(word))
|
||||
return word;
|
||||
|
||||
if (word.Contains('1') ||
|
||||
word.Contains('2') ||
|
||||
word.Contains('3') ||
|
||||
word.Contains('4') ||
|
||||
word.Contains('5') ||
|
||||
word.Contains('6') ||
|
||||
word.Contains('7') ||
|
||||
word.Contains('8') ||
|
||||
word.Contains('9') ||
|
||||
word.EndsWith("a.m", StringComparison.Ordinal) ||
|
||||
word.EndsWith("p.m", StringComparison.Ordinal) ||
|
||||
word.EndsWith("am", StringComparison.Ordinal) ||
|
||||
word.EndsWith("pm", StringComparison.Ordinal))
|
||||
return word;
|
||||
|
||||
if (HexNumber.IsMatch(word))
|
||||
return word;
|
||||
|
||||
if (word.LastIndexOf('0') > 0)
|
||||
{
|
||||
Match match = RegExTime1.Match(word);
|
||||
while (match.Success)
|
||||
{
|
||||
if (word[match.Index + 1] == '0')
|
||||
{
|
||||
string oldText = word;
|
||||
word = word.Substring(0, match.Index + 1) + "o";
|
||||
if (match.Index + 2 < oldText.Length)
|
||||
word += oldText.Substring(match.Index + 2);
|
||||
}
|
||||
match = RegExTime1.Match(word);
|
||||
}
|
||||
|
||||
match = RegExTime2.Match(word);
|
||||
while (match.Success)
|
||||
{
|
||||
if (word[match.Index] == '0')
|
||||
{
|
||||
if (match.Index == 0 || !@"123456789".Contains(word[match.Index - 1]))
|
||||
{
|
||||
string oldText = word;
|
||||
word = word.Substring(0, match.Index) + "o";
|
||||
if (match.Index + 1 < oldText.Length)
|
||||
word += oldText.Substring(match.Index + 1);
|
||||
}
|
||||
}
|
||||
match = RegExTime2.Match(word, match.Index + 1);
|
||||
}
|
||||
}
|
||||
return word;
|
||||
}
|
||||
|
||||
public string FixCommonWordErrorsQuick(string word)
|
||||
{
|
||||
//always replace list
|
||||
foreach (string letter in _partialWordReplaceListAlways.Keys)
|
||||
word = word.Replace(letter, _partialWordReplaceListAlways[letter]);
|
||||
|
||||
string pre = string.Empty;
|
||||
string post = string.Empty;
|
||||
|
||||
if (word.StartsWith("<i>", StringComparison.Ordinal))
|
||||
{
|
||||
pre += "<i>";
|
||||
word = word.Remove(0, 3);
|
||||
}
|
||||
while (word.StartsWith(Environment.NewLine) && word.Length > 2)
|
||||
{
|
||||
pre += Environment.NewLine;
|
||||
word = word.Substring(2);
|
||||
}
|
||||
|
||||
while (word.Length > 1 && word[0] == '-')
|
||||
{
|
||||
pre += "-";
|
||||
word = word.Substring(1);
|
||||
}
|
||||
while (word.Length > 1 && word[0] == '.')
|
||||
{
|
||||
pre += ".";
|
||||
word = word.Substring(1);
|
||||
}
|
||||
while (word.Length > 1 && word[0] == '"')
|
||||
{
|
||||
pre += "\"";
|
||||
word = word.Substring(1);
|
||||
}
|
||||
if (word.Length > 1 && word[0] == '(')
|
||||
{
|
||||
pre += "(";
|
||||
word = word.Substring(1);
|
||||
}
|
||||
if (word.StartsWith("<i>", StringComparison.Ordinal))
|
||||
{
|
||||
pre += "<i>";
|
||||
word = word.Remove(0, 3);
|
||||
}
|
||||
while (word.EndsWith(Environment.NewLine) && word.Length > 2)
|
||||
{
|
||||
post += Environment.NewLine;
|
||||
word = word.Substring(0, word.Length - 2);
|
||||
}
|
||||
while (word.EndsWith('"') && word.Length > 1)
|
||||
{
|
||||
post = post + "\"";
|
||||
word = word.Substring(0, word.Length - 1);
|
||||
}
|
||||
while (word.EndsWith('.') && word.Length > 1)
|
||||
{
|
||||
post = post + ".";
|
||||
word = word.Substring(0, word.Length - 1);
|
||||
}
|
||||
while (word.EndsWith(',') && word.Length > 1)
|
||||
{
|
||||
post = post + ",";
|
||||
word = word.Substring(0, word.Length - 1);
|
||||
}
|
||||
while (word.EndsWith('?') && word.Length > 1)
|
||||
{
|
||||
post = post + "?";
|
||||
word = word.Substring(0, word.Length - 1);
|
||||
}
|
||||
while (word.EndsWith('!') && word.Length > 1)
|
||||
{
|
||||
post = post + "!";
|
||||
word = word.Substring(0, word.Length - 1);
|
||||
}
|
||||
while (word.EndsWith(')') && word.Length > 1)
|
||||
{
|
||||
post = post + ")";
|
||||
word = word.Substring(0, word.Length - 1);
|
||||
}
|
||||
if (word.EndsWith("</i>", StringComparison.Ordinal))
|
||||
{
|
||||
post = post + "</i>";
|
||||
word = word.Remove(word.Length - 4, 4);
|
||||
}
|
||||
|
||||
string preWordPost = pre + word + post;
|
||||
if (word.Length == 0)
|
||||
return preWordPost;
|
||||
|
||||
foreach (string from in WordReplaceList.Keys)
|
||||
{
|
||||
if (word.Length == from.Length)
|
||||
{
|
||||
if (string.CompareOrdinal(word, from) == 0)
|
||||
return pre + WordReplaceList[from] + post;
|
||||
}
|
||||
else if (word.Length + post.Length == from.Length)
|
||||
{
|
||||
if (string.CompareOrdinal(word + post, from) == 0)
|
||||
return pre + WordReplaceList[from];
|
||||
}
|
||||
if (pre.Length + word.Length + post.Length == from.Length && string.CompareOrdinal(preWordPost, from) == 0)
|
||||
{
|
||||
return WordReplaceList[from];
|
||||
}
|
||||
}
|
||||
|
||||
return preWordPost;
|
||||
}
|
||||
|
||||
public bool RemoveWordOrPartial(string word)
|
||||
{
|
||||
if (word.Contains(' '))
|
||||
{
|
||||
if (DeletePartialLineFromWordList(word))
|
||||
{
|
||||
if (PartialLineWordBoundaryReplaceList.ContainsKey(word))
|
||||
PartialLineWordBoundaryReplaceList.Remove(word);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (DeleteWordFromWordList(word))
|
||||
{
|
||||
if (WordReplaceList.ContainsKey(word))
|
||||
WordReplaceList.Remove(word);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool DeleteWordFromWordList(string fromWord)
|
||||
{
|
||||
const string replaceListName = "WholeWords";
|
||||
|
||||
var doc = LoadXmlReplaceListDocument();
|
||||
var list = LoadReplaceList(doc, replaceListName);
|
||||
|
||||
var userDoc = LoadXmlReplaceListUserDocument();
|
||||
var userList = LoadReplaceList(userDoc, replaceListName);
|
||||
|
||||
return DeleteFromList(fromWord, userDoc, replaceListName, "Word", list, userList);
|
||||
}
|
||||
|
||||
private bool DeletePartialLineFromWordList(string fromWord)
|
||||
{
|
||||
const string replaceListName = "PartialLines";
|
||||
|
||||
var doc = LoadXmlReplaceListDocument();
|
||||
var list = LoadReplaceList(doc, replaceListName);
|
||||
|
||||
var userDoc = LoadXmlReplaceListUserDocument();
|
||||
var userList = LoadReplaceList(userDoc, replaceListName);
|
||||
|
||||
return DeleteFromList(fromWord, userDoc, replaceListName, "LinePart", list, userList);
|
||||
}
|
||||
|
||||
private bool DeleteFromList(string word, XmlDocument userDoc, string replaceListName, string elementName, Dictionary<string, string> dictionary, Dictionary<string, string> userDictionary)
|
||||
{
|
||||
if (dictionary == null)
|
||||
throw new ArgumentNullException("dictionary");
|
||||
if (userDictionary == null)
|
||||
throw new ArgumentNullException("userDictionary");
|
||||
|
||||
bool removed = false;
|
||||
if (userDictionary.ContainsKey((word)))
|
||||
{
|
||||
userDictionary.Remove(word);
|
||||
XmlNode wholeWordsNode = userDoc.DocumentElement.SelectSingleNode(replaceListName);
|
||||
if (wholeWordsNode != null)
|
||||
{
|
||||
wholeWordsNode.RemoveAll();
|
||||
foreach (var kvp in userDictionary)
|
||||
{
|
||||
XmlNode newNode = userDoc.CreateNode(XmlNodeType.Element, elementName, null);
|
||||
XmlAttribute aFrom = userDoc.CreateAttribute("from");
|
||||
XmlAttribute aTo = userDoc.CreateAttribute("to");
|
||||
aFrom.InnerText = kvp.Key;
|
||||
aTo.InnerText = kvp.Value;
|
||||
newNode.Attributes.Append(aTo);
|
||||
newNode.Attributes.Append(aFrom);
|
||||
wholeWordsNode.AppendChild(newNode);
|
||||
}
|
||||
userDoc.Save(ReplaceListXmlFileNameUser);
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
if (dictionary.ContainsKey((word)))
|
||||
{
|
||||
XmlNode wholeWordsNode = userDoc.DocumentElement.SelectSingleNode("Removed" + replaceListName);
|
||||
if (wholeWordsNode != null)
|
||||
{
|
||||
XmlNode newNode = userDoc.CreateNode(XmlNodeType.Element, elementName, null);
|
||||
XmlAttribute aFrom = userDoc.CreateAttribute("from");
|
||||
XmlAttribute aTo = userDoc.CreateAttribute("to");
|
||||
aFrom.InnerText = word;
|
||||
aTo.InnerText = string.Empty;
|
||||
newNode.Attributes.Append(aTo);
|
||||
newNode.Attributes.Append(aFrom);
|
||||
wholeWordsNode.AppendChild(newNode);
|
||||
userDoc.Save(ReplaceListXmlFileNameUser);
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
private XmlDocument LoadXmlReplaceListDocument()
|
||||
{
|
||||
const string xmlText = "<ReplaceList><WholeWords/><PartialLines/><BeginLines/><EndLines/><WholeLines/></ReplaceList>";
|
||||
var doc = new XmlDocument();
|
||||
if (File.Exists(_replaceListXmlFileName))
|
||||
{
|
||||
try
|
||||
{
|
||||
doc.Load(_replaceListXmlFileName);
|
||||
}
|
||||
catch
|
||||
{
|
||||
doc.LoadXml(xmlText);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
doc.LoadXml(xmlText);
|
||||
}
|
||||
return doc;
|
||||
}
|
||||
|
||||
private string ReplaceListXmlFileNameUser
|
||||
{
|
||||
get { return Path.Combine(Path.GetDirectoryName(_replaceListXmlFileName), Path.GetFileNameWithoutExtension(_replaceListXmlFileName) + "_User" + Path.GetExtension(_replaceListXmlFileName)); }
|
||||
}
|
||||
|
||||
private XmlDocument LoadXmlReplaceListUserDocument()
|
||||
{
|
||||
const string xmlText = "<ReplaceList><WholeWords/><PartialLines/><BeginLines/><EndLines/><WholeLines/><RemovedWholeWords/><RemovedPartialLines/><RemovedBeginLines/><RemovedEndLines/><RemovedWholeLines/></ReplaceList>";
|
||||
var doc = new XmlDocument();
|
||||
if (File.Exists(ReplaceListXmlFileNameUser))
|
||||
{
|
||||
try
|
||||
{
|
||||
doc.Load(ReplaceListXmlFileNameUser);
|
||||
}
|
||||
catch
|
||||
{
|
||||
doc.LoadXml(xmlText);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
doc.LoadXml(xmlText);
|
||||
}
|
||||
return doc;
|
||||
}
|
||||
|
||||
public bool AddWordOrPartial(string fromWord, string toWord)
|
||||
{
|
||||
if (fromWord.Contains(' '))
|
||||
{
|
||||
if (SavePartialLineToWordList(fromWord, toWord))
|
||||
{
|
||||
if (!PartialLineWordBoundaryReplaceList.ContainsKey(fromWord))
|
||||
PartialLineWordBoundaryReplaceList.Add(fromWord, toWord);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (SaveWordToWordList(fromWord, toWord))
|
||||
{
|
||||
if (!WordReplaceList.ContainsKey(fromWord))
|
||||
WordReplaceList.Add(fromWord, toWord);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool SaveWordToWordList(string fromWord, string toWord)
|
||||
{
|
||||
const string replaceListName = "WholeWords";
|
||||
|
||||
var doc = LoadXmlReplaceListDocument();
|
||||
var list = LoadReplaceList(doc, replaceListName);
|
||||
|
||||
var userDoc = LoadXmlReplaceListUserDocument();
|
||||
var userList = LoadReplaceList(userDoc, replaceListName);
|
||||
|
||||
return SaveToList(fromWord, toWord, userDoc, replaceListName, "Word", list, userList);
|
||||
}
|
||||
|
||||
private bool SavePartialLineToWordList(string fromWord, string toWord)
|
||||
{
|
||||
const string replaceListName = "PartialLines";
|
||||
|
||||
var doc = LoadXmlReplaceListDocument();
|
||||
var list = LoadReplaceList(doc, replaceListName);
|
||||
|
||||
var userDoc = LoadXmlReplaceListUserDocument();
|
||||
var userList = LoadReplaceList(userDoc, replaceListName);
|
||||
|
||||
return SaveToList(fromWord, toWord, userDoc, replaceListName, "LinePart", list, userList);
|
||||
}
|
||||
|
||||
private bool SaveToList(string fromWord, string toWord, XmlDocument userDoc, string replaceListName, string elementName, Dictionary<string, string> dictionary, Dictionary<string, string> userDictionary)
|
||||
{
|
||||
if (dictionary == null)
|
||||
throw new ArgumentNullException("dictionary");
|
||||
if (userDictionary == null)
|
||||
throw new ArgumentNullException("userDictionary");
|
||||
if (userDictionary.ContainsKey(fromWord))
|
||||
return false;
|
||||
|
||||
userDictionary.Add(fromWord, toWord);
|
||||
XmlNode wholeWordsNode = userDoc.DocumentElement.SelectSingleNode(replaceListName);
|
||||
if (wholeWordsNode != null)
|
||||
{
|
||||
XmlNode newNode = userDoc.CreateNode(XmlNodeType.Element, elementName, null);
|
||||
XmlAttribute aFrom = userDoc.CreateAttribute("from");
|
||||
XmlAttribute aTo = userDoc.CreateAttribute("to");
|
||||
aTo.InnerText = toWord;
|
||||
aFrom.InnerText = fromWord;
|
||||
newNode.Attributes.Append(aFrom);
|
||||
newNode.Attributes.Append(aTo);
|
||||
wholeWordsNode.AppendChild(newNode);
|
||||
userDoc.Save(ReplaceListXmlFileNameUser);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void AddToWholeLineList(string fromLine, string toLine)
|
||||
{
|
||||
try
|
||||
{
|
||||
var userDocument = LoadXmlReplaceListUserDocument();
|
||||
if (!_wholeLineReplaceList.ContainsKey(fromLine))
|
||||
_wholeLineReplaceList.Add(fromLine, toLine);
|
||||
XmlNode wholeWordsNode = userDocument.DocumentElement.SelectSingleNode("WholeLines");
|
||||
if (wholeWordsNode != null)
|
||||
{
|
||||
XmlNode newNode = userDocument.CreateNode(XmlNodeType.Element, "Line", null);
|
||||
XmlAttribute aFrom = userDocument.CreateAttribute("from");
|
||||
XmlAttribute aTo = userDocument.CreateAttribute("to");
|
||||
aTo.InnerText = toLine;
|
||||
aFrom.InnerText = fromLine;
|
||||
newNode.Attributes.Append(aFrom);
|
||||
newNode.Attributes.Append(aTo);
|
||||
wholeWordsNode.AppendChild(newNode);
|
||||
userDocument.Save(_replaceListXmlFileName);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
MessageBox.Show(exception + Environment.NewLine + exception.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
public static string ReplaceWord(string text, string word, string newWord)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
if (word != null && text != null && text.Contains(word))
|
||||
{
|
||||
const string startChars = @" ¡¿<>-""”“()[]'‘`´¶♪¿¡.…—!?,:;/";
|
||||
int appendFrom = 0;
|
||||
for (int i = 0; i < text.Length; i++)
|
||||
{
|
||||
if (text.Substring(i).StartsWith(word) && i >= appendFrom)
|
||||
{
|
||||
bool startOk = i == 0;
|
||||
if (!startOk)
|
||||
startOk = (startChars + Environment.NewLine).Contains(text[i - 1]);
|
||||
if (!startOk && word.StartsWith(' '))
|
||||
startOk = true;
|
||||
if (startOk)
|
||||
{
|
||||
bool endOk = (i + word.Length == text.Length);
|
||||
if (!endOk)
|
||||
endOk = (startChars + Environment.NewLine).Contains(text[i + word.Length]);
|
||||
if (!endOk)
|
||||
endOk = newWord.EndsWith(' ');
|
||||
if (endOk)
|
||||
{
|
||||
sb.Append(newWord);
|
||||
appendFrom = i + word.Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i >= appendFrom)
|
||||
sb.Append(text[i]);
|
||||
}
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
9
libse/Enums/FindType.cs
Normal file
9
libse/Enums/FindType.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace Nikse.Core.Enums
|
||||
{
|
||||
public enum FindType
|
||||
{
|
||||
Normal,
|
||||
CaseSensitive,
|
||||
RegEx
|
||||
}
|
||||
}
|
9
libse/Enums/SelectionChoice.cs
Normal file
9
libse/Enums/SelectionChoice.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace Nikse.Core.Enums
|
||||
{
|
||||
public enum SelectionChoice
|
||||
{
|
||||
SelectionOnly,
|
||||
AllLines,
|
||||
SelectionAndForward,
|
||||
}
|
||||
}
|
15
libse/Enums/SpellCheckAction.cs
Normal file
15
libse/Enums/SpellCheckAction.cs
Normal file
@ -0,0 +1,15 @@
|
||||
namespace Nikse.Core.Enums
|
||||
{
|
||||
public enum SpellCheckAction
|
||||
{
|
||||
Change,
|
||||
ChangeAll,
|
||||
Skip,
|
||||
SkipAll,
|
||||
AddToDictionary,
|
||||
Abort,
|
||||
ChangeLanguage,
|
||||
AddToNamesEtc,
|
||||
ChangeWholeText
|
||||
}
|
||||
}
|
17
libse/Enums/SubtitleSortCriteria.cs
Normal file
17
libse/Enums/SubtitleSortCriteria.cs
Normal file
@ -0,0 +1,17 @@
|
||||
namespace Nikse.Core.Enums
|
||||
{
|
||||
public enum SubtitleSortCriteria
|
||||
{
|
||||
Number,
|
||||
StartTime,
|
||||
EndTime,
|
||||
Duration,
|
||||
Text,
|
||||
TextMaxLineLength,
|
||||
TextTotalLength,
|
||||
TextNumberOfLines,
|
||||
TextCharactersPerSeconds,
|
||||
WordsPerMinute,
|
||||
Style,
|
||||
}
|
||||
}
|
110
libse/FastBitmap.cs
Normal file
110
libse/FastBitmap.cs
Normal file
@ -0,0 +1,110 @@
|
||||
//Downloaded from Visual C# Kicks - http://www.vcskicks.com/
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core
|
||||
{
|
||||
unsafe public class FastBitmap
|
||||
{
|
||||
private struct PixelData
|
||||
{
|
||||
public byte Blue;
|
||||
public byte Green;
|
||||
public byte Red;
|
||||
public byte Alpha;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "(" + Alpha + ", " + Red + ", " + Green + ", " + Blue + ")";
|
||||
}
|
||||
}
|
||||
|
||||
public int Width { get; set; }
|
||||
public int Height { get; set; }
|
||||
|
||||
private readonly Bitmap _workingBitmap;
|
||||
private int _width;
|
||||
private BitmapData _bitmapData;
|
||||
private Byte* _pBase = null;
|
||||
|
||||
public FastBitmap(Bitmap inputBitmap)
|
||||
{
|
||||
_workingBitmap = inputBitmap;
|
||||
|
||||
if (_workingBitmap.PixelFormat != PixelFormat.Format32bppArgb &&
|
||||
Environment.OSVersion.Version.Major < 6 && Configuration.Settings.General.SubtitleFontName == Utilities.WinXP2KUnicodeFontName) // 6 == Vista/Win2008Server/Win7
|
||||
{ // WinXp Fix
|
||||
var newBitmap = new Bitmap(_workingBitmap.Width, _workingBitmap.Height, PixelFormat.Format32bppArgb);
|
||||
for (int y = 0; y < _workingBitmap.Height; y++)
|
||||
for (int x = 0; x < _workingBitmap.Width; x++)
|
||||
newBitmap.SetPixel(x, y, _workingBitmap.GetPixel(x, y));
|
||||
_workingBitmap = newBitmap;
|
||||
}
|
||||
|
||||
Width = inputBitmap.Width;
|
||||
Height = inputBitmap.Height;
|
||||
}
|
||||
|
||||
public void LockImage()
|
||||
{
|
||||
var bounds = new Rectangle(Point.Empty, _workingBitmap.Size);
|
||||
|
||||
_width = bounds.Width * sizeof(PixelData);
|
||||
if (_width % 4 != 0) _width = 4 * (_width / 4 + 1);
|
||||
|
||||
//Lock Image
|
||||
_bitmapData = _workingBitmap.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
|
||||
_pBase = (Byte*)_bitmapData.Scan0.ToPointer();
|
||||
}
|
||||
|
||||
private PixelData* _pixelData = null;
|
||||
|
||||
public Color GetPixel(int x, int y)
|
||||
{
|
||||
_pixelData = (PixelData*)(_pBase + y * _width + x * sizeof(PixelData));
|
||||
return Color.FromArgb(_pixelData->Alpha, _pixelData->Red, _pixelData->Green, _pixelData->Blue);
|
||||
}
|
||||
|
||||
public Color GetPixelNext()
|
||||
{
|
||||
_pixelData++;
|
||||
return Color.FromArgb(_pixelData->Alpha, _pixelData->Red, _pixelData->Green, _pixelData->Blue);
|
||||
}
|
||||
|
||||
public void SetPixel(int x, int y, Color color)
|
||||
{
|
||||
var data = (PixelData*)(_pBase + y * _width + x * sizeof(PixelData));
|
||||
data->Alpha = color.A;
|
||||
data->Red = color.R;
|
||||
data->Green = color.G;
|
||||
data->Blue = color.B;
|
||||
}
|
||||
|
||||
public void SetPixel(int x, int y, Color color, int length)
|
||||
{
|
||||
var data = (PixelData*)(_pBase + y * _width + x * sizeof(PixelData));
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
data->Alpha = color.A;
|
||||
data->Red = color.R;
|
||||
data->Green = color.G;
|
||||
data->Blue = color.B;
|
||||
data++;
|
||||
}
|
||||
}
|
||||
|
||||
public Bitmap GetBitmap()
|
||||
{
|
||||
return _workingBitmap;
|
||||
}
|
||||
|
||||
public void UnlockImage()
|
||||
{
|
||||
_workingBitmap.UnlockBits(_bitmapData);
|
||||
_bitmapData = null;
|
||||
_pBase = null;
|
||||
}
|
||||
}
|
||||
}
|
104
libse/FastFileStream.cs
Normal file
104
libse/FastFileStream.cs
Normal file
@ -0,0 +1,104 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Exposes a <see cref="Stream"/> around a file, supporting synchronous read operations.
|
||||
/// </summary>
|
||||
internal class FastFileStream : FileStream
|
||||
{
|
||||
private readonly long _length;
|
||||
private long _position;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FastFileStream"/> class with the specified path.
|
||||
/// </summary>
|
||||
/// <param name="path">A relative or absolute path for the file that the current <see cref="FastFileStream"/> object will encapsulate.</param>
|
||||
public FastFileStream(string path)
|
||||
: base(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
|
||||
{
|
||||
_length = base.Length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length in bytes of the stream.
|
||||
/// </summary>
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return _length;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current position of the stream.
|
||||
/// </summary>
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return _position;
|
||||
}
|
||||
set
|
||||
{
|
||||
Seek(value, SeekOrigin.Begin);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current position of this stream to the given value.
|
||||
/// </summary>
|
||||
/// <param name="offset">The point relative to <paramref name="origin"/> from which to begin seeking.</param>
|
||||
/// <param name="origin">Specifies the beginning, the end, or the current position as a reference point for origin, using a value of type <see cref="SeekOrigin"/>.</param>
|
||||
/// <returns>The new position in the stream.</returns>
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
switch (origin)
|
||||
{
|
||||
case SeekOrigin.Begin:
|
||||
if (_position != offset)
|
||||
{
|
||||
_position = offset;
|
||||
base.Seek(offset, origin);
|
||||
}
|
||||
break;
|
||||
case SeekOrigin.Current:
|
||||
if (_position != _position + offset)
|
||||
{
|
||||
_position += offset;
|
||||
base.Seek(offset, origin);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
_position = base.Seek(offset, origin);
|
||||
break;
|
||||
}
|
||||
return _position;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a block of bytes from the stream and writes the data in a given buffer.
|
||||
/// </summary>
|
||||
/// <param name="array">When this method returns, contains the specified byte array with the values between <paramref name="offset"/> and (<paramref name="offset"/> + <paramref name="count"/> - 1) replaced by the bytes read from the current source.</param>
|
||||
/// <param name="offset">The byte offset in <paramref name="array"/> at which the read bytes will be placed.</param>
|
||||
/// <param name="count">The maximum number of bytes to read.</param>
|
||||
/// <returns>The total number of bytes read into the buffer. This might be less than the number of bytes requested if that number of bytes are not currently available, or zero if the end of the stream is reached.</returns>
|
||||
public override int Read(byte[] array, int offset, int count)
|
||||
{
|
||||
var bytesRead = base.Read(array, offset, count);
|
||||
_position += bytesRead;
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a byte from the file and advances the read position one byte.
|
||||
/// </summary>
|
||||
/// <returns>The byte, cast to an Int32, or -1 if the end of the stream has been reached.</returns>
|
||||
public override int ReadByte()
|
||||
{
|
||||
_position++;
|
||||
return base.ReadByte();
|
||||
}
|
||||
}
|
||||
}
|
331
libse/FileUtil.cs
Normal file
331
libse/FileUtil.cs
Normal file
@ -0,0 +1,331 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using Nikse.SubtitleEdit.Core.TransportStream;
|
||||
using Nikse.SubtitleEdit.Core.VobSub;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// File related utilities.
|
||||
/// </summary>
|
||||
public static class FileUtil
|
||||
{
|
||||
/// <summary>
|
||||
/// Opens a binary file in read/write shared mode, reads the contents of the file into a
|
||||
/// byte array, and then closes the file.
|
||||
/// </summary>
|
||||
/// <param name="path">The file to open for reading. </param>
|
||||
/// <returns>A byte array containing the contents of the file.</returns>
|
||||
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 > Int32.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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an existing file for reading, and allow the user to retry if it fails.
|
||||
/// </summary>
|
||||
/// <param name="path">The file to be opened for reading. </param>
|
||||
/// <returns>A read-only <see cref="FileStream"/> on the specified path.</returns>
|
||||
public static FileStream RetryOpenRead(string path)
|
||||
{
|
||||
FileStream fs = null;
|
||||
while (fs == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
var result = MessageBox.Show(string.Format("An error occured while opening file: {0}", ex.Message), string.Empty, MessageBoxButtons.RetryCancel);
|
||||
if (result == DialogResult.Cancel)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return fs;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
return (buffer[0] == 0x47 && buffer[188] == 0x47) || // 47hex (71 dec or 'G') == TS sync byte
|
||||
(buffer[0] == 0x54 && buffer[1] == 0x46 && buffer[2] == 0x72 && buffer[3760] == 0x47); // 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";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if file is an MXF file
|
||||
/// </summary>
|
||||
/// <param name="fileName">Input file</param>
|
||||
/// <returns>true if file is an MXF file, otherwise false</returns>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
232
libse/FindReplaceDialogHelper.cs
Normal file
232
libse/FindReplaceDialogHelper.cs
Normal file
@ -0,0 +1,232 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Forms;
|
||||
using Nikse.Core;
|
||||
using Nikse.Core.Enums;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core
|
||||
{
|
||||
public class FindReplaceDialogHelper
|
||||
{
|
||||
private readonly string _findText = string.Empty;
|
||||
private readonly string _replaceText = string.Empty;
|
||||
private readonly Regex _regEx;
|
||||
private int _findTextLenght;
|
||||
|
||||
public bool Success { get; set; }
|
||||
public FindType FindType { get; set; }
|
||||
public int SelectedIndex { get; set; }
|
||||
public int SelectedPosition { get; set; }
|
||||
public int WindowPositionLeft { get; set; }
|
||||
public int WindowPositionTop { get; set; }
|
||||
public int StartLineIndex { get; set; }
|
||||
public bool MatchInOriginal { get; set; }
|
||||
|
||||
public int FindTextLength
|
||||
{
|
||||
get
|
||||
{
|
||||
return _findTextLenght;
|
||||
}
|
||||
}
|
||||
|
||||
public string FindText
|
||||
{
|
||||
get
|
||||
{
|
||||
return _findText;
|
||||
}
|
||||
}
|
||||
|
||||
public string ReplaceText
|
||||
{
|
||||
get
|
||||
{
|
||||
return _replaceText;
|
||||
}
|
||||
}
|
||||
|
||||
public FindReplaceDialogHelper(FindType findType, string findText, Regex regEx, string replaceText, int left, int top, int startLineIndex)
|
||||
{
|
||||
FindType = findType;
|
||||
_findText = findText;
|
||||
_replaceText = replaceText;
|
||||
_regEx = regEx;
|
||||
_findTextLenght = findText.Length;
|
||||
WindowPositionLeft = left;
|
||||
WindowPositionTop = top;
|
||||
StartLineIndex = startLineIndex;
|
||||
}
|
||||
|
||||
public bool Find(Subtitle subtitle, Subtitle originalSubtitle, int startIndex)
|
||||
{
|
||||
return FindNext(subtitle, originalSubtitle, startIndex, 0, Configuration.Settings.General.AllowEditOfOriginalSubtitle);
|
||||
}
|
||||
|
||||
public bool Find(TextBox textBox, int startIndex)
|
||||
{
|
||||
return FindNext(textBox, startIndex);
|
||||
}
|
||||
|
||||
private int FindPositionInText(string text, int startIndex)
|
||||
{
|
||||
if (startIndex >= text.Length && !(FindType == FindType.RegEx && startIndex == 0))
|
||||
return -1;
|
||||
|
||||
switch (FindType)
|
||||
{
|
||||
case FindType.Normal:
|
||||
return (text.IndexOf(_findText, startIndex, System.StringComparison.OrdinalIgnoreCase));
|
||||
case FindType.CaseSensitive:
|
||||
return (text.IndexOf(_findText, startIndex, System.StringComparison.Ordinal));
|
||||
case FindType.RegEx:
|
||||
{
|
||||
Match match = _regEx.Match(text, startIndex);
|
||||
if (match.Success)
|
||||
{
|
||||
string groupName = Utilities.GetRegExGroup(_findText);
|
||||
if (groupName != null && match.Groups[groupName] != null && match.Groups[groupName].Success)
|
||||
{
|
||||
_findTextLenght = match.Groups[groupName].Length;
|
||||
return match.Groups[groupName].Index;
|
||||
}
|
||||
_findTextLenght = match.Length;
|
||||
return match.Index;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public bool FindNext(Subtitle subtitle, Subtitle originalSubtitle, int startIndex, int position, bool allowEditOfOriginalSubtitle)
|
||||
{
|
||||
Success = false;
|
||||
int index = 0;
|
||||
if (position < 0)
|
||||
position = 0;
|
||||
foreach (Paragraph p in subtitle.Paragraphs)
|
||||
{
|
||||
if (index >= startIndex)
|
||||
{
|
||||
int pos = 0;
|
||||
if (!MatchInOriginal)
|
||||
{
|
||||
pos = FindPositionInText(p.Text, position);
|
||||
if (pos >= 0)
|
||||
{
|
||||
MatchInOriginal = false;
|
||||
SelectedIndex = index;
|
||||
SelectedPosition = pos;
|
||||
Success = true;
|
||||
return true;
|
||||
}
|
||||
position = 0;
|
||||
}
|
||||
MatchInOriginal = false;
|
||||
|
||||
if (originalSubtitle != null && allowEditOfOriginalSubtitle)
|
||||
{
|
||||
Paragraph o = Utilities.GetOriginalParagraph(index, p, originalSubtitle.Paragraphs);
|
||||
if (o != null)
|
||||
{
|
||||
pos = FindPositionInText(o.Text, position);
|
||||
if (pos >= 0)
|
||||
{
|
||||
MatchInOriginal = true;
|
||||
SelectedIndex = index;
|
||||
SelectedPosition = pos;
|
||||
Success = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static ContextMenu GetRegExContextMenu(TextBox textBox)
|
||||
{
|
||||
var cm = new ContextMenu();
|
||||
var l = Configuration.Settings.Language.RegularExpressionContextMenu;
|
||||
cm.MenuItems.Add(l.WordBoundary, delegate { textBox.SelectedText = "\\b"; });
|
||||
cm.MenuItems.Add(l.NonWordBoundary, delegate { textBox.SelectedText = "\\B"; });
|
||||
cm.MenuItems.Add(l.NewLine, delegate { textBox.SelectedText = "\\r\\n"; });
|
||||
cm.MenuItems.Add(l.AnyDigit, delegate { textBox.SelectedText = "\\d"; });
|
||||
cm.MenuItems.Add(l.NonDigit, delegate { textBox.SelectedText = "\\D"; });
|
||||
cm.MenuItems.Add(l.AnyCharacter, delegate { textBox.SelectedText = "."; });
|
||||
cm.MenuItems.Add(l.AnyWhitespace, delegate { textBox.SelectedText = "\\s"; });
|
||||
cm.MenuItems.Add(l.NonSpaceCharacter, delegate { textBox.SelectedText = "\\S"; });
|
||||
cm.MenuItems.Add(l.ZeroOrMore, delegate { textBox.SelectedText = "*"; });
|
||||
cm.MenuItems.Add(l.OneOrMore, delegate { textBox.SelectedText = "+"; });
|
||||
cm.MenuItems.Add(l.InCharacterGroup, delegate { textBox.SelectedText = "[test]"; });
|
||||
cm.MenuItems.Add(l.NotInCharacterGroup, delegate { textBox.SelectedText = "[^test]"; });
|
||||
return cm;
|
||||
}
|
||||
|
||||
public static ContextMenu GetRegExContextMenu(ComboBox comboBox)
|
||||
{
|
||||
var cm = new ContextMenu();
|
||||
var l = Configuration.Settings.Language.RegularExpressionContextMenu;
|
||||
cm.MenuItems.Add(l.WordBoundary, delegate { comboBox.SelectedText = "\\b"; });
|
||||
cm.MenuItems.Add(l.NonWordBoundary, delegate { comboBox.SelectedText = "\\B"; });
|
||||
cm.MenuItems.Add(l.NewLine, delegate { comboBox.SelectedText = "\\r\\n"; });
|
||||
cm.MenuItems.Add(l.AnyDigit, delegate { comboBox.SelectedText = "\\d"; });
|
||||
cm.MenuItems.Add(l.NonDigit, delegate { comboBox.SelectedText = "\\D"; });
|
||||
cm.MenuItems.Add(l.AnyCharacter, delegate { comboBox.SelectedText = "."; });
|
||||
cm.MenuItems.Add(l.AnyWhitespace, delegate { comboBox.SelectedText = "\\s"; });
|
||||
cm.MenuItems.Add(l.NonSpaceCharacter, delegate { comboBox.SelectedText = "\\S"; });
|
||||
cm.MenuItems.Add(l.ZeroOrMore, delegate { comboBox.SelectedText = "*"; });
|
||||
cm.MenuItems.Add(l.OneOrMore, delegate { comboBox.SelectedText = "+"; });
|
||||
cm.MenuItems.Add(l.InCharacterGroup, delegate { comboBox.SelectedText = "[test]"; });
|
||||
cm.MenuItems.Add(l.NotInCharacterGroup, delegate { comboBox.SelectedText = "[^test]"; });
|
||||
return cm;
|
||||
}
|
||||
|
||||
public static ContextMenu GetReplaceTextContextMenu(TextBox textBox)
|
||||
{
|
||||
var cm = new ContextMenu();
|
||||
cm.MenuItems.Add(Configuration.Settings.Language.RegularExpressionContextMenu.NewLineShort, delegate { textBox.SelectedText = "\\n"; });
|
||||
return cm;
|
||||
}
|
||||
|
||||
public bool FindNext(TextBox textBox, int startIndex)
|
||||
{
|
||||
Success = false;
|
||||
startIndex++;
|
||||
if (startIndex < textBox.Text.Length)
|
||||
{
|
||||
if (FindType == FindType.RegEx)
|
||||
{
|
||||
Match match = _regEx.Match(textBox.Text, startIndex);
|
||||
if (match.Success)
|
||||
{
|
||||
string groupName = Utilities.GetRegExGroup(_findText);
|
||||
if (groupName != null && match.Groups[groupName] != null && match.Groups[groupName].Success)
|
||||
{
|
||||
_findTextLenght = match.Groups[groupName].Length;
|
||||
SelectedIndex = match.Groups[groupName].Index;
|
||||
}
|
||||
else
|
||||
{
|
||||
_findTextLenght = match.Length;
|
||||
SelectedIndex = match.Index;
|
||||
}
|
||||
Success = true;
|
||||
}
|
||||
return match.Success;
|
||||
}
|
||||
string searchText = textBox.Text.Substring(startIndex);
|
||||
int pos = FindPositionInText(searchText, 0);
|
||||
if (pos >= 0)
|
||||
{
|
||||
SelectedIndex = pos + startIndex;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
186
libse/Forms/CheckForUpdatesHelper.cs
Normal file
186
libse/Forms/CheckForUpdatesHelper.cs
Normal file
@ -0,0 +1,186 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.Forms
|
||||
{
|
||||
public class CheckForUpdatesHelper
|
||||
{
|
||||
private readonly static Regex regex = new Regex(@"\d\.\d", RegexOptions.Compiled); // 3.4.0 (xth June 2014)
|
||||
|
||||
//private const string ReleasesUrl = "https://api.github.com/repos/SubtitleEdit/subtitleedit/releases";
|
||||
private const string ChangeLogUrl = "https://raw.githubusercontent.com/SubtitleEdit/subtitleedit/master/Changelog.txt";
|
||||
|
||||
//private string _jsonReleases;
|
||||
private string _changeLog;
|
||||
private int _successCount;
|
||||
|
||||
public string Error { get; set; }
|
||||
public bool Done
|
||||
{
|
||||
get
|
||||
{
|
||||
return _successCount == 1;
|
||||
}
|
||||
}
|
||||
public string LatestVersionNumber { get; set; }
|
||||
public string LatestChangeLog { get; set; }
|
||||
|
||||
private void StartDownloadString(string url, string contentType, AsyncCallback callback)
|
||||
{
|
||||
try
|
||||
{
|
||||
var request = (HttpWebRequest)WebRequest.Create(url);
|
||||
request.UserAgent = "SubtitleEdit";
|
||||
request.ContentType = contentType;
|
||||
request.Timeout = Timeout.Infinite;
|
||||
request.Method = "GET";
|
||||
request.AllowAutoRedirect = true;
|
||||
request.Accept = contentType;
|
||||
request.BeginGetResponse(callback, request);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (Error == null)
|
||||
{
|
||||
Error = exception.Message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void FinishWebRequestReleases(IAsyncResult result)
|
||||
//{
|
||||
// try
|
||||
// {
|
||||
// _jsonReleases = GetStringFromResponse(result);
|
||||
// }
|
||||
// catch (Exception exception)
|
||||
// {
|
||||
// if (Error == null)
|
||||
// {
|
||||
// Error = exception.Message;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
private void FinishWebRequestChangeLog(IAsyncResult result)
|
||||
{
|
||||
try
|
||||
{
|
||||
_changeLog = GetStringFromResponse(result);
|
||||
LatestChangeLog = GetLastestChangeLog(_changeLog);
|
||||
LatestVersionNumber = GetLastestVersionNumber(LatestChangeLog);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (Error == null)
|
||||
{
|
||||
Error = exception.Message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetLastestVersionNumber(string latestChangeLog)
|
||||
{
|
||||
foreach (string line in latestChangeLog.Replace(Environment.NewLine, "\n").Split('\n'))
|
||||
{
|
||||
string s = line.Trim();
|
||||
if (!s.Contains("BETA", StringComparison.OrdinalIgnoreCase) && !s.Contains('x') && !s.Contains('*') && s.Contains('(') && s.Contains(')') && regex.IsMatch(s))
|
||||
{
|
||||
int indexOfSpace = s.IndexOf(' ');
|
||||
if (indexOfSpace > 0)
|
||||
return s.Substring(0, indexOfSpace).Trim();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string GetLastestChangeLog(string changeLog)
|
||||
{
|
||||
bool releaseOn = false;
|
||||
var sb = new StringBuilder();
|
||||
foreach (string line in changeLog.Replace(Environment.NewLine, "\n").Split('\n'))
|
||||
{
|
||||
string s = line.Trim();
|
||||
if (s.Length == 0 && releaseOn)
|
||||
return sb.ToString();
|
||||
|
||||
if (!releaseOn)
|
||||
{
|
||||
if (!s.Contains('x') && !s.Contains('*') && s.Contains('(') && s.Contains(')') && regex.IsMatch(s))
|
||||
releaseOn = true;
|
||||
}
|
||||
|
||||
if (releaseOn)
|
||||
{
|
||||
sb.AppendLine(line);
|
||||
}
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private string GetStringFromResponse(IAsyncResult result)
|
||||
{
|
||||
HttpWebResponse response = (result.AsyncState as HttpWebRequest).EndGetResponse(result) as HttpWebResponse;
|
||||
System.IO.Stream responseStream = response.GetResponseStream();
|
||||
byte[] buffer = new byte[5000000];
|
||||
int count = 1;
|
||||
int index = 0;
|
||||
while (count > 0)
|
||||
{
|
||||
count = responseStream.Read(buffer, index, 2048);
|
||||
index += count;
|
||||
}
|
||||
if (index > 0)
|
||||
_successCount++;
|
||||
return Encoding.UTF8.GetString(buffer, 0, index);
|
||||
}
|
||||
|
||||
public CheckForUpdatesHelper()
|
||||
{
|
||||
Error = null;
|
||||
_successCount = 0;
|
||||
}
|
||||
|
||||
public void CheckForUpdates()
|
||||
{
|
||||
// load github release json
|
||||
//StartDownloadString(ReleasesUrl, "application/json", FinishWebRequestReleases);
|
||||
|
||||
// load change log
|
||||
StartDownloadString(ChangeLogUrl, null, FinishWebRequestChangeLog);
|
||||
}
|
||||
|
||||
public bool IsUpdateAvailable()
|
||||
{
|
||||
try
|
||||
{
|
||||
//string[] currentVersionInfo = "3.3.14".Split('.'); // for testing...
|
||||
string[] currentVersionInfo = Utilities.AssemblyVersion.Split('.');
|
||||
string minorMinorVersion = string.Empty;
|
||||
if (currentVersionInfo.Length >= 3 && currentVersionInfo[2] != "0")
|
||||
minorMinorVersion = "." + currentVersionInfo[2];
|
||||
string currentVersion = String.Format("{0}.{1}{2}", currentVersionInfo[0], currentVersionInfo[1], minorMinorVersion);
|
||||
if (currentVersion == LatestVersionNumber)
|
||||
return false;
|
||||
|
||||
string[] latestVersionInfo = LatestVersionNumber.Split('.');
|
||||
if (int.Parse(latestVersionInfo[0]) > int.Parse(currentVersionInfo[0]))
|
||||
return true;
|
||||
if (int.Parse(latestVersionInfo[0]) == int.Parse(currentVersionInfo[0]) && int.Parse(latestVersionInfo[1]) > int.Parse(currentVersionInfo[1]))
|
||||
return true;
|
||||
if (int.Parse(latestVersionInfo[0]) == int.Parse(currentVersionInfo[0]) && int.Parse(latestVersionInfo[1]) == int.Parse(currentVersionInfo[1]) && int.Parse(latestVersionInfo[2]) > int.Parse(currentVersionInfo[2]))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
464
libse/Forms/FixCommonErrorsHelper.cs
Normal file
464
libse/Forms/FixCommonErrorsHelper.cs
Normal file
@ -0,0 +1,464 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.Forms
|
||||
{
|
||||
public static class FixCommonErrorsHelper
|
||||
{
|
||||
public static string FixEllipsesStartHelper(string text)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text) || text.Trim().Length < 4 || !(text.Contains("..", StringComparison.Ordinal) || text.Contains(". .", StringComparison.Ordinal)))
|
||||
return text;
|
||||
|
||||
var pre = string.Empty;
|
||||
if (text.StartsWith("<font ", StringComparison.Ordinal) && text.IndexOf('>', 5) >= 0)
|
||||
{
|
||||
var idx = text.IndexOf('>', 5);
|
||||
if (idx >= 0)
|
||||
{
|
||||
pre = text.Substring(0, text.IndexOf('>') + 1);
|
||||
text = text.Substring(idx + 1).TrimStart();
|
||||
}
|
||||
}
|
||||
|
||||
if (text.StartsWith("...", StringComparison.Ordinal))
|
||||
{
|
||||
text = text.TrimStart('.').TrimStart();
|
||||
}
|
||||
|
||||
// "...foobar" / "... foobar" / ". .. foobar"
|
||||
if (text.StartsWith("\"") && (text.StartsWith("\"..") || text.StartsWith("\". .") || text.StartsWith("\" ..") || text.StartsWith("\" . .")))
|
||||
{
|
||||
int removeLength = 0;
|
||||
while (removeLength + 1 < text.Length && (text[1 + removeLength] == '.' || text[1 + removeLength] == ' '))
|
||||
removeLength++;
|
||||
text = text.Remove(1, removeLength);
|
||||
}
|
||||
|
||||
text = text.Replace("-..", "- ..");
|
||||
var tag = "- ...";
|
||||
if (text.StartsWith(tag, StringComparison.Ordinal))
|
||||
{
|
||||
text = "- " + text.Substring(tag.Length);
|
||||
while (text.StartsWith("- .", StringComparison.Ordinal))
|
||||
{
|
||||
text = "- " + text.Substring(3);
|
||||
text = text.Replace(" ", " ");
|
||||
}
|
||||
}
|
||||
|
||||
tag = "<i>...";
|
||||
if (text.StartsWith(tag, StringComparison.Ordinal))
|
||||
{
|
||||
text = "<i>" + text.Substring(tag.Length);
|
||||
while (text.StartsWith("<i>.", StringComparison.Ordinal) || text.StartsWith("<i> ", StringComparison.Ordinal))
|
||||
text = "<i>" + text.Substring(4);
|
||||
}
|
||||
tag = "<i> ...";
|
||||
if (text.StartsWith(tag, StringComparison.Ordinal))
|
||||
{
|
||||
text = "<i>" + text.Substring(tag.Length);
|
||||
while (text.StartsWith("<i>.", StringComparison.Ordinal) || text.StartsWith("<i> ", StringComparison.Ordinal))
|
||||
text = "<i>" + text.Substring(4, text.Length - 4);
|
||||
}
|
||||
|
||||
tag = "- <i>...";
|
||||
if (text.StartsWith(tag, StringComparison.Ordinal))
|
||||
{
|
||||
text = "- <i>" + text.Substring(tag.Length);
|
||||
while (text.StartsWith("- <i>.", StringComparison.Ordinal))
|
||||
text = "- <i>" + text.Substring(6);
|
||||
}
|
||||
tag = "- <i> ...";
|
||||
if (text.StartsWith(tag, StringComparison.Ordinal))
|
||||
{
|
||||
text = "- <i>" + text.Substring(tag.Length);
|
||||
while (text.StartsWith("- <i>.", StringComparison.Ordinal))
|
||||
text = "- <i>" + text.Substring(6);
|
||||
}
|
||||
|
||||
// Narrator:... Hello foo!
|
||||
text = text.Replace(":..", ": ..");
|
||||
tag = ": ..";
|
||||
if (text.Contains(tag, StringComparison.Ordinal))
|
||||
{
|
||||
text = text.Replace(": ..", ": ");
|
||||
while (text.Contains(": ."))
|
||||
text = text.Replace(": .", ": ");
|
||||
}
|
||||
|
||||
// <i>- ... Foo</i>
|
||||
tag = "<i>- ...";
|
||||
if (text.StartsWith(tag, StringComparison.Ordinal))
|
||||
{
|
||||
text = text.Substring(tag.Length);
|
||||
text = text.TrimStart('.', ' ');
|
||||
text = "<i>- " + text;
|
||||
}
|
||||
text = text.Replace(" ", " ");
|
||||
|
||||
// WOMAN 2: <i>...24 hours a day at BabyC.</i>
|
||||
var index = text.IndexOf(':');
|
||||
if (index > 0 && text.Length > index + 2 && !char.IsDigit(text[index + 1]) && text.Contains("..", StringComparison.Ordinal))
|
||||
{
|
||||
pre += text.Substring(0, index + 1);
|
||||
if (pre.Length < 2)
|
||||
return text;
|
||||
|
||||
text = text.Remove(0, index + 1).TrimStart();
|
||||
text = FixEllipsesStartHelper(text);
|
||||
if (pre.Length > 0)
|
||||
pre += " ";
|
||||
}
|
||||
return pre + text;
|
||||
}
|
||||
|
||||
public static string FixDialogsOnOneLine(string text, string language)
|
||||
{
|
||||
if (text.Contains(" - ") && !text.Contains(Environment.NewLine))
|
||||
{
|
||||
var noTagLines = HtmlUtil.RemoveHtmlTags(text.Replace(" - ", Environment.NewLine), true).SplitToLines();
|
||||
if (noTagLines.Length == 2)
|
||||
{
|
||||
string part0 = noTagLines[0];
|
||||
string part1 = noTagLines[1];
|
||||
if (part0.Length > 1 && "-—!?.\")]".Contains(part0[part0.Length - 1]) &&
|
||||
part1.Length > 1 && ("'" + Utilities.UppercaseLetters).Contains(part1[0]))
|
||||
{
|
||||
text = text.Replace(" - ", Environment.NewLine + "- ");
|
||||
if (Utilities.AllLettersAndNumbers.Contains(part0[0]))
|
||||
{
|
||||
if (text.Length > 3 && text[0] == '<' && text[2] == '>')
|
||||
text = "<" + text[1] + ">" + "- " + text.Substring(3).TrimStart();
|
||||
else
|
||||
text = "- " + text;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var stringArray = new string[] { ". -", "! -", "? -", "— -", "-- -", ") -", "] -", "> -" };
|
||||
var idx = text.IndexOfAny(stringArray, StringComparison.Ordinal);
|
||||
if (idx >= 0)
|
||||
{
|
||||
if (Utilities.GetNumberOfLines(text) == 2)
|
||||
{
|
||||
string temp = Utilities.AutoBreakLine(text, 99, 33, language);
|
||||
var arr = text.SplitToLines();
|
||||
var arrTemp = temp.SplitToLines();
|
||||
if (arrTemp.Length == 2 && arr.Length == 2)
|
||||
{
|
||||
var secLine = HtmlUtil.RemoveHtmlTags(arr[1]).TrimStart();
|
||||
var secLineTemp = HtmlUtil.RemoveHtmlTags(arrTemp[1]).TrimStart();
|
||||
if (secLineTemp.StartsWith('-') && !secLine.StartsWith('-'))
|
||||
text = temp;
|
||||
}
|
||||
}
|
||||
else if (Utilities.GetNumberOfLines(text) == 1)
|
||||
{
|
||||
string temp = Utilities.AutoBreakLine(text, language);
|
||||
var arrTemp = temp.SplitToLines();
|
||||
if (arrTemp.Length == 2)
|
||||
{
|
||||
var secLineTemp = HtmlUtil.RemoveHtmlTags(arrTemp[1]).TrimStart();
|
||||
if (secLineTemp.StartsWith('-'))
|
||||
text = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = text.IndexOfAny(new[] { ". -", "! -", "? -", "— -" }, StringComparison.Ordinal);
|
||||
if (index < 0 && text.IndexOf("-- -", StringComparison.Ordinal) > 0)
|
||||
index = text.IndexOf("-- -", StringComparison.Ordinal) + 1;
|
||||
if (index > 0)
|
||||
{
|
||||
text = text.Remove(index + 1, 1).Insert(index + 1, Environment.NewLine);
|
||||
text = text.Replace(Environment.NewLine + " ", Environment.NewLine);
|
||||
text = text.Replace(" " + Environment.NewLine, Environment.NewLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
public static bool IsPreviousTextEndOfParagraph(string prevText)
|
||||
{
|
||||
if (string.IsNullOrEmpty(prevText) || prevText.Length < 3)
|
||||
return true;
|
||||
|
||||
prevText = prevText.Replace("♪", string.Empty).Replace("♫", string.Empty).Trim();
|
||||
bool isPrevEndOfLine = prevText.Length > 1 &&
|
||||
!prevText.EndsWith("...", StringComparison.Ordinal) &&
|
||||
(".!?—".Contains(prevText[prevText.Length - 1]) || // em dash, unicode character
|
||||
prevText.EndsWith("--", StringComparison.Ordinal));
|
||||
|
||||
if (isPrevEndOfLine && prevText.Length > 5 && prevText.EndsWith('.') &&
|
||||
prevText[prevText.Length - 3] == '.' &&
|
||||
Utilities.AllLetters.Contains(prevText[prevText.Length - 2]))
|
||||
isPrevEndOfLine = false;
|
||||
return isPrevEndOfLine;
|
||||
}
|
||||
|
||||
public static string FixHyphensRemove(Subtitle subtitle, int i)
|
||||
{
|
||||
Paragraph p = subtitle.Paragraphs[i];
|
||||
string text = p.Text;
|
||||
|
||||
if (text.TrimStart().StartsWith('-') ||
|
||||
text.TrimStart().StartsWith("<i>-", StringComparison.OrdinalIgnoreCase) ||
|
||||
text.TrimStart().StartsWith("<i> -", StringComparison.OrdinalIgnoreCase) ||
|
||||
text.Contains(Environment.NewLine + '-') ||
|
||||
text.Contains(Environment.NewLine + " -") ||
|
||||
text.Contains(Environment.NewLine + "<i>-") ||
|
||||
text.Contains(Environment.NewLine + "<i> -") ||
|
||||
text.Contains(Environment.NewLine + "<I>-") ||
|
||||
text.Contains(Environment.NewLine + "<I> -"))
|
||||
{
|
||||
var prev = subtitle.GetParagraphOrDefault(i - 1);
|
||||
|
||||
if (prev == null || !HtmlUtil.RemoveHtmlTags(prev.Text).TrimEnd().EndsWith('-') || HtmlUtil.RemoveHtmlTags(prev.Text).TrimEnd().EndsWith("--", StringComparison.Ordinal))
|
||||
{
|
||||
var noTaglines = HtmlUtil.RemoveHtmlTags(p.Text).SplitToLines();
|
||||
int startHyphenCount = noTaglines.Count(line => line.TrimStart().StartsWith('-'));
|
||||
if (startHyphenCount == 1)
|
||||
{
|
||||
bool remove = true;
|
||||
var noTagparts = HtmlUtil.RemoveHtmlTags(text).SplitToLines();
|
||||
if (noTagparts.Length == 2)
|
||||
{
|
||||
if (noTagparts[0].TrimStart().StartsWith('-') && noTagparts[1].Contains(": "))
|
||||
remove = false;
|
||||
if (noTagparts[1].TrimStart().StartsWith('-') && noTagparts[0].Contains(": "))
|
||||
remove = false;
|
||||
}
|
||||
|
||||
if (remove)
|
||||
{
|
||||
int idx = text.IndexOf('-');
|
||||
var st = new StripableText(text);
|
||||
if (idx < 5 && st.Pre.Length >= idx)
|
||||
{
|
||||
text = text.Remove(idx, 1).TrimStart();
|
||||
idx = text.IndexOf('-');
|
||||
st = new StripableText(text);
|
||||
if (idx < 5 && idx >= 0 && st.Pre.Length >= idx)
|
||||
{
|
||||
text = text.Remove(idx, 1).TrimStart();
|
||||
st = new StripableText(text);
|
||||
}
|
||||
idx = text.IndexOf('-');
|
||||
if (idx < 5 && idx >= 0 && st.Pre.Length >= idx)
|
||||
text = text.Remove(idx, 1).TrimStart();
|
||||
|
||||
text = RemoveSpacesBeginLine(text);
|
||||
}
|
||||
else
|
||||
{
|
||||
int indexOfNewLine = text.IndexOf(Environment.NewLine, StringComparison.Ordinal);
|
||||
if (indexOfNewLine > 0)
|
||||
{
|
||||
idx = text.IndexOf('-', indexOfNewLine);
|
||||
if (idx >= 0 && indexOfNewLine + 5 > indexOfNewLine)
|
||||
{
|
||||
text = text.Remove(idx, 1).TrimStart().Replace(Environment.NewLine + " ", Environment.NewLine);
|
||||
|
||||
idx = text.IndexOf('-', indexOfNewLine);
|
||||
if (idx >= 0 && indexOfNewLine + 5 > indexOfNewLine)
|
||||
{
|
||||
text = text.Remove(idx, 1).TrimStart();
|
||||
|
||||
text = RemoveSpacesBeginLine(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (text.StartsWith("<font ", StringComparison.Ordinal))
|
||||
{
|
||||
var prev = subtitle.GetParagraphOrDefault(i - 1);
|
||||
if (prev == null || !HtmlUtil.RemoveHtmlTags(prev.Text).TrimEnd().EndsWith('-') || HtmlUtil.RemoveHtmlTags(prev.Text).TrimEnd().EndsWith("--", StringComparison.Ordinal))
|
||||
{
|
||||
var st = new StripableText(text);
|
||||
if (st.Pre.EndsWith('-') || st.Pre.EndsWith("- ", StringComparison.Ordinal))
|
||||
{
|
||||
text = st.Pre.TrimEnd('-', ' ') + st.StrippedText + st.Post;
|
||||
}
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
private static string RemoveSpacesBeginLine(string text)
|
||||
{
|
||||
text = text.TrimStart();
|
||||
text = text.Replace(" ", " ");
|
||||
text = text.Replace(Environment.NewLine + " ", Environment.NewLine);
|
||||
text = text.Replace(Environment.NewLine + "<i> ", Environment.NewLine + "<i>");
|
||||
text = text.Replace(Environment.NewLine + "<b> ", Environment.NewLine + "<b>");
|
||||
text = text.Replace(Environment.NewLine + "<u> ", Environment.NewLine + "<u>");
|
||||
|
||||
if (text.LineStartsWithHtmlTag(true) && text[3] == 0x20)
|
||||
{
|
||||
text = text.Remove(3, 1).TrimStart();
|
||||
}
|
||||
if (text.LineStartsWithHtmlTag(false, true))
|
||||
{
|
||||
var closeIdx = text.IndexOf('>');
|
||||
if (closeIdx > 6 && text[closeIdx + 1] == 0x20)
|
||||
text = text.Remove(closeIdx + 1, 1);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
public static string RemoveSpacesBeginLineAfterEllipses(string line)
|
||||
{
|
||||
if (line.StartsWith("... ", StringComparison.Ordinal))
|
||||
line = line.Remove(3, 1);
|
||||
if (line.Length > 6 && line.LineStartsWithHtmlTag(true)) // <i>... foobar
|
||||
{
|
||||
var idx = line.IndexOf('>') + 1;
|
||||
var pre = line.Substring(0, idx);
|
||||
line = line.Remove(0, idx).TrimStart();
|
||||
if (line.StartsWith("... ", StringComparison.Ordinal))
|
||||
line = line.Remove(3, 1);
|
||||
line = pre + line;
|
||||
}
|
||||
if (line.LineStartsWithHtmlTag(false, true)) //<font color="#000000"> and <font>
|
||||
{
|
||||
var closeIdx = line.IndexOf('>', 5);
|
||||
if (closeIdx >= 5 && line.Length > closeIdx + 5)
|
||||
{
|
||||
var fontTag = line.Substring(0, closeIdx + 1).TrimStart();
|
||||
line = line.Substring(closeIdx + 1).TrimStart();
|
||||
if (line.StartsWith("... ", StringComparison.Ordinal))
|
||||
line = line.Remove("... ".Length - 1, 1);
|
||||
line = fontTag + line;
|
||||
}
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
public static string FixHyphensAdd(Subtitle subtitle, int i, string language)
|
||||
{
|
||||
Paragraph p = subtitle.Paragraphs[i];
|
||||
string text = p.Text;
|
||||
var textCache = HtmlUtil.RemoveHtmlTags(text.TrimStart());
|
||||
if (textCache.StartsWith('-') || textCache.Contains(Environment.NewLine + "-"))
|
||||
{
|
||||
Paragraph prev = subtitle.GetParagraphOrDefault(i - 1);
|
||||
|
||||
if (prev == null || !HtmlUtil.RemoveHtmlTags(prev.Text).TrimEnd().EndsWith('-') || HtmlUtil.RemoveHtmlTags(prev.Text).TrimEnd().EndsWith("--", StringComparison.Ordinal))
|
||||
{
|
||||
var lines = HtmlUtil.RemoveHtmlTags(p.Text).SplitToLines();
|
||||
int startHyphenCount = lines.Count(line => line.TrimStart().StartsWith('-'));
|
||||
int totalSpaceHyphen = Utilities.CountTagInText(text, " -");
|
||||
if (startHyphenCount == 1 && totalSpaceHyphen == 0)
|
||||
{
|
||||
var parts = HtmlUtil.RemoveHtmlTags(text).SplitToLines();
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
var part0 = parts[0].TrimEnd();
|
||||
bool doAdd = "!?.".Contains(part0[part0.Length - 1]) || language == "ko";
|
||||
if (parts[0].TrimStart().StartsWith('-') && parts[1].Contains(':') && !doAdd)
|
||||
doAdd = false;
|
||||
if (parts[1].TrimStart().StartsWith('-') && parts[0].Contains(':') && !doAdd)
|
||||
doAdd = false;
|
||||
|
||||
if (doAdd)
|
||||
{
|
||||
int idx = text.IndexOf('-');
|
||||
int newLineIdx = text.IndexOf(Environment.NewLine, StringComparison.Ordinal);
|
||||
bool addSecondLine = idx < newLineIdx ? true : false;
|
||||
|
||||
if (addSecondLine && idx > 0 && Utilities.AllLetters.Contains(text[idx - 1]))
|
||||
addSecondLine = false;
|
||||
if (addSecondLine)
|
||||
{
|
||||
// add dash in second line.
|
||||
newLineIdx += 2;
|
||||
if (text.LineBreakStartsWithHtmlTag(true))
|
||||
{
|
||||
text = text.Insert(newLineIdx + 3, "- ").TrimEnd();
|
||||
}
|
||||
else
|
||||
{
|
||||
text = text.Replace(Environment.NewLine, Environment.NewLine + "- ").Replace(Environment.NewLine + "- ", Environment.NewLine + "- ");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// add dash in first line.
|
||||
if (text.LineStartsWithHtmlTag(true))
|
||||
text = text.Substring(0, 3) + "- " + text.Remove(0, 3).TrimEnd();
|
||||
else if (text.StartsWith("{\\an", StringComparison.Ordinal) && text.Length > 6 && text[5] == '}')
|
||||
text = text.Insert(6, "- ");
|
||||
else
|
||||
text = "- " + text.Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// - Shut it off. -Get the fuck<br/>out of here, Darryl.
|
||||
if (totalSpaceHyphen == 1 && startHyphenCount == 1)
|
||||
{
|
||||
var idx = text.IndexOf(" -", StringComparison.Ordinal);
|
||||
if (idx > 1 && ".?!".Contains(text[idx - 1]) && idx + 2 < text.Length)
|
||||
{
|
||||
var firstLine = text.Substring(0, idx).Replace(Environment.NewLine, " ").Trim();
|
||||
var secondLine = text.Substring(idx + 1).Insert(1, " ").Replace(Environment.NewLine, " ").Trim();
|
||||
text = firstLine + Environment.NewLine + secondLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
public static string FixDoubleGreaterThanHelper(string text)
|
||||
{
|
||||
string post = string.Empty;
|
||||
if (text.Length > 3 && text[0] == '<' && text[2] == '>' && (text[1] == 'i' || text[1] == 'b' || text[1] == 'u'))
|
||||
{
|
||||
post += "<" + text[1] + ">";
|
||||
text = text.Remove(0, 3).TrimStart();
|
||||
}
|
||||
if (text.StartsWith("<font", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var endIdx = text.IndexOf('>', 5);
|
||||
if (endIdx >= 5 && endIdx < text.Length - 7)
|
||||
{
|
||||
post += text.Substring(0, endIdx + 1);
|
||||
text = text.Substring(endIdx + 1).TrimStart();
|
||||
}
|
||||
}
|
||||
if (text.StartsWith(">>", StringComparison.Ordinal) && text.Length > 3)
|
||||
text = text.TrimStart('>', ' ').TrimStart();
|
||||
return post + text;
|
||||
}
|
||||
|
||||
public static string FixShortLines(string text)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(text) || !text.Contains(Environment.NewLine, StringComparison.Ordinal))
|
||||
return text;
|
||||
|
||||
string s = HtmlUtil.RemoveHtmlTags(text, true);
|
||||
if (s.Contains(Environment.NewLine) && s.Replace(Environment.NewLine, " ").Replace(" ", " ").Length < Configuration.Settings.Tools.MergeLinesShorterThan)
|
||||
{
|
||||
s = s.TrimEnd().TrimEnd('.', '?', '!', ':', ';');
|
||||
s = s.TrimStart('-');
|
||||
if (!s.Contains(new[] { '.', '?', '!', ':', ';', '-', '♪', '♫' }) &&
|
||||
!(s.StartsWith('[') && s.Contains("]" + Environment.NewLine, StringComparison.Ordinal)) &&
|
||||
!(s.StartsWith('(') && s.Contains(")" + Environment.NewLine, StringComparison.Ordinal)) &&
|
||||
s != s.ToUpper())
|
||||
{
|
||||
return Utilities.UnbreakLine(text);
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
1122
libse/Forms/RemoveTextForHI.cs
Normal file
1122
libse/Forms/RemoveTextForHI.cs
Normal file
File diff suppressed because it is too large
Load Diff
48
libse/Forms/RemoveTextForHISettings.cs
Normal file
48
libse/Forms/RemoveTextForHISettings.cs
Normal file
@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.Forms
|
||||
{
|
||||
public class RemoveTextForHISettings
|
||||
{
|
||||
public bool OnlyIfInSeparateLine { get; set; }
|
||||
public bool RemoveIfAllUppercase { get; set; }
|
||||
public bool RemoveTextBeforeColon { get; set; }
|
||||
public bool RemoveTextBeforeColonOnlyUppercase { get; set; }
|
||||
public bool ColonSeparateLine { get; set; }
|
||||
public bool RemoveWhereContains { get; set; }
|
||||
public List<string> RemoveIfTextContains { get; set; }
|
||||
public bool RemoveTextBetweenCustomTags { get; set; }
|
||||
public bool RemoveInterjections { get; set; }
|
||||
public bool RemoveTextBetweenSquares { get; set; }
|
||||
public bool RemoveTextBetweenBrackets { get; set; }
|
||||
public bool RemoveTextBetweenQuestionMarks { get; set; }
|
||||
public bool RemoveTextBetweenParentheses { get; set; }
|
||||
public string CustomStart { get; set; }
|
||||
public string CustomEnd { get; set; }
|
||||
|
||||
public RemoveTextForHISettings()
|
||||
{
|
||||
OnlyIfInSeparateLine = Configuration.Settings.RemoveTextForHearingImpaired.RemoveTextBetweenOnlySeperateLines;
|
||||
RemoveIfAllUppercase = Configuration.Settings.RemoveTextForHearingImpaired.RemoveIfAllUppercase;
|
||||
RemoveTextBeforeColon = Configuration.Settings.RemoveTextForHearingImpaired.RemoveTextBeforeColon;
|
||||
RemoveTextBeforeColonOnlyUppercase = Configuration.Settings.RemoveTextForHearingImpaired.RemoveTextBeforeColonOnlyIfUppercase;
|
||||
ColonSeparateLine = Configuration.Settings.RemoveTextForHearingImpaired.RemoveTextBeforeColonOnlyOnSeparateLine;
|
||||
RemoveWhereContains = Configuration.Settings.RemoveTextForHearingImpaired.RemoveIfContains;
|
||||
RemoveIfTextContains = new List<string>();
|
||||
foreach (string item in Configuration.Settings.RemoveTextForHearingImpaired.RemoveIfContainsText.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
RemoveIfTextContains.Add(item.Trim());
|
||||
}
|
||||
RemoveTextBetweenCustomTags = Configuration.Settings.RemoveTextForHearingImpaired.RemoveTextBetweenCustom;
|
||||
RemoveInterjections = Configuration.Settings.RemoveTextForHearingImpaired.RemoveInterjections;
|
||||
RemoveTextBetweenSquares = Configuration.Settings.RemoveTextForHearingImpaired.RemoveTextBetweenBrackets;
|
||||
RemoveTextBetweenBrackets = Configuration.Settings.RemoveTextForHearingImpaired.RemoveTextBetweenCurlyBrackets;
|
||||
RemoveTextBetweenQuestionMarks = Configuration.Settings.RemoveTextForHearingImpaired.RemoveTextBetweenQuestionMarks;
|
||||
RemoveTextBetweenParentheses = Configuration.Settings.RemoveTextForHearingImpaired.RemoveTextBetweenParentheses;
|
||||
CustomStart = Configuration.Settings.RemoveTextForHearingImpaired.RemoveTextBetweenCustomBefore;
|
||||
CustomEnd = Configuration.Settings.RemoveTextForHearingImpaired.RemoveTextBetweenCustomAfter;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
143
libse/Forms/SplitLongLinesHelper.cs
Normal file
143
libse/Forms/SplitLongLinesHelper.cs
Normal file
@ -0,0 +1,143 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.Forms
|
||||
{
|
||||
public static class SplitLongLinesHelper
|
||||
{
|
||||
public static bool QualifiesForSplit(string text, int singleLineMaxCharacters, int totalLineMaxCharacters)
|
||||
{
|
||||
string s = HtmlUtil.RemoveHtmlTags(text.Trim(), true);
|
||||
if (s.Length > totalLineMaxCharacters)
|
||||
return true;
|
||||
|
||||
var arr = s.SplitToLines();
|
||||
foreach (string line in arr)
|
||||
{
|
||||
if (line.Length > singleLineMaxCharacters)
|
||||
return true;
|
||||
}
|
||||
|
||||
var tempText = Utilities.UnbreakLine(text);
|
||||
if (Utilities.CountTagInText(tempText, '-') == 2 && (text.StartsWith('-') || text.StartsWith("<i>-")))
|
||||
{
|
||||
var idx = tempText.IndexOfAny(new[] { ". -", "! -", "? -" }, StringComparison.Ordinal);
|
||||
if (idx > 1)
|
||||
{
|
||||
idx++;
|
||||
string dialogText = tempText.Remove(idx, 1).Insert(idx, Environment.NewLine);
|
||||
foreach (string line in dialogText.SplitToLines())
|
||||
{
|
||||
if (line.Length > singleLineMaxCharacters)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Subtitle SplitLongLinesInSubtitle(Subtitle subtitle, int totalLineMaxCharacters, int singleLineMaxCharacters)
|
||||
{
|
||||
var splittedIndexes = new List<int>();
|
||||
var autoBreakedIndexes = new List<int>();
|
||||
var splittedSubtitle = new Subtitle();
|
||||
string language = Utilities.AutoDetectGoogleLanguage(subtitle);
|
||||
for (int i = 0; i < subtitle.Paragraphs.Count; i++)
|
||||
{
|
||||
bool added = false;
|
||||
var p = subtitle.GetParagraphOrDefault(i);
|
||||
if (p != null && p.Text != null)
|
||||
{
|
||||
if (QualifiesForSplit(p.Text, singleLineMaxCharacters, totalLineMaxCharacters))
|
||||
{
|
||||
var text = Utilities.AutoBreakLine(p.Text, language);
|
||||
if (!QualifiesForSplit(text, singleLineMaxCharacters, totalLineMaxCharacters))
|
||||
{
|
||||
var newParagraph = new Paragraph(p) { Text = text };
|
||||
autoBreakedIndexes.Add(splittedSubtitle.Paragraphs.Count);
|
||||
splittedSubtitle.Paragraphs.Add(newParagraph);
|
||||
added = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (text.Contains(Environment.NewLine))
|
||||
{
|
||||
var arr = text.SplitToLines();
|
||||
if (arr.Length == 2)
|
||||
{
|
||||
var minMsBtwnLnBy2 = Configuration.Settings.General.MinimumMillisecondsBetweenLines / 2;
|
||||
int spacing1 = minMsBtwnLnBy2;
|
||||
int spacing2 = minMsBtwnLnBy2;
|
||||
if (Configuration.Settings.General.MinimumMillisecondsBetweenLines % 2 == 1)
|
||||
spacing2++;
|
||||
|
||||
double duration = p.Duration.TotalMilliseconds / 2.0;
|
||||
var newParagraph1 = new Paragraph(p);
|
||||
var newParagraph2 = new Paragraph(p);
|
||||
newParagraph1.Text = Utilities.AutoBreakLine(arr[0], language);
|
||||
newParagraph1.EndTime.TotalMilliseconds = p.StartTime.TotalMilliseconds + duration - spacing1;
|
||||
newParagraph2.Text = Utilities.AutoBreakLine(arr[1], language);
|
||||
newParagraph2.StartTime.TotalMilliseconds = newParagraph1.EndTime.TotalMilliseconds + spacing2;
|
||||
|
||||
splittedIndexes.Add(splittedSubtitle.Paragraphs.Count);
|
||||
splittedIndexes.Add(splittedSubtitle.Paragraphs.Count + 1);
|
||||
|
||||
string p1 = HtmlUtil.RemoveHtmlTags(newParagraph1.Text);
|
||||
var len = p1.Length - 1;
|
||||
if (p1.Length > 0 && (p1[len] == '.' || p1[len] == '!' || p1[len] == '?' || p1[len] == ':' || p1[len] == ')' || p1[len] == ']' || p1[len] == '♪'))
|
||||
{
|
||||
if (newParagraph1.Text.StartsWith('-') && newParagraph2.Text.StartsWith('-'))
|
||||
{
|
||||
newParagraph1.Text = newParagraph1.Text.Remove(0, 1).Trim();
|
||||
newParagraph2.Text = newParagraph2.Text.Remove(0, 1).Trim();
|
||||
}
|
||||
else if (newParagraph1.Text.StartsWith("<i>-", StringComparison.Ordinal) && newParagraph2.Text.StartsWith('-'))
|
||||
{
|
||||
newParagraph1.Text = newParagraph1.Text.Remove(3, 1).Trim();
|
||||
if (newParagraph1.Text.StartsWith("<i> ", StringComparison.Ordinal))
|
||||
newParagraph1.Text = newParagraph1.Text.Remove(3, 1).Trim();
|
||||
newParagraph2.Text = newParagraph2.Text.Remove(0, 1).Trim();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (newParagraph1.Text.EndsWith("</i>", StringComparison.Ordinal))
|
||||
{
|
||||
const string post = "</i>";
|
||||
newParagraph1.Text = newParagraph1.Text.Remove(newParagraph1.Text.Length - post.Length);
|
||||
}
|
||||
//newParagraph1.Text += comboBoxLineContinuationEnd.Text.TrimEnd() + post;
|
||||
|
||||
if (newParagraph2.Text.StartsWith("<i>", StringComparison.Ordinal))
|
||||
{
|
||||
const string pre = "<i>";
|
||||
newParagraph2.Text = newParagraph2.Text.Remove(0, pre.Length);
|
||||
}
|
||||
//newParagraph2.Text = pre + comboBoxLineContinuationBegin.Text + newParagraph2.Text;
|
||||
}
|
||||
|
||||
var indexOfItalicOpen1 = newParagraph1.Text.IndexOf("<i>", StringComparison.Ordinal);
|
||||
if (indexOfItalicOpen1 >= 0 && indexOfItalicOpen1 < 10 && newParagraph1.Text.IndexOf("</i>", StringComparison.Ordinal) < 0 &&
|
||||
newParagraph2.Text.Contains("</i>") && newParagraph2.Text.IndexOf("<i>", StringComparison.Ordinal) < 0)
|
||||
{
|
||||
newParagraph1.Text += "</i>";
|
||||
newParagraph2.Text = "<i>" + newParagraph2.Text;
|
||||
}
|
||||
|
||||
splittedSubtitle.Paragraphs.Add(newParagraph1);
|
||||
splittedSubtitle.Paragraphs.Add(newParagraph2);
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!added)
|
||||
splittedSubtitle.Paragraphs.Add(new Paragraph(p));
|
||||
}
|
||||
splittedSubtitle.Renumber();
|
||||
return splittedSubtitle;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
162
libse/Fourier.cs
Normal file
162
libse/Fourier.cs
Normal file
@ -0,0 +1,162 @@
|
||||
using System;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Fourier transform
|
||||
///
|
||||
/// *****************************************************************************
|
||||
/// *
|
||||
/// * Copyright (c) 2002, Wilhelm Kurz. All Rights Reserved.
|
||||
/// * wkurz@foni.net
|
||||
/// *
|
||||
/// * This file is provided for demonstration and educational uses only.
|
||||
/// * Permission to use, copy, modify and distribute this file for
|
||||
/// * any purpose and without fee is hereby granted.
|
||||
/// *
|
||||
/// *****************************************************************************
|
||||
/// Converted/optimized by Nikse from vb code: http://www.wilhelm-kurz-software.de/dynaplot/applicationnotes/spectrogram.htm
|
||||
/// </summary>
|
||||
internal class Fourier
|
||||
{
|
||||
public const double W0Hanning = 0.5;
|
||||
public const double W0Hamming = 0.54;
|
||||
public const double W0Blackman = 0.42;
|
||||
private const double Pi = 3.14159265358979;
|
||||
|
||||
private double[] cosarray;
|
||||
private double[] sinarray;
|
||||
private bool _forward;
|
||||
private int _arraySize;
|
||||
private int _ldArraysize = 0;
|
||||
|
||||
public Fourier(int arraySize, bool forward)
|
||||
{
|
||||
_arraySize = arraySize;
|
||||
_forward = forward;
|
||||
cosarray = new double[arraySize];
|
||||
sinarray = new double[arraySize];
|
||||
|
||||
double sign = 1.0;
|
||||
if (forward)
|
||||
sign = -1.0;
|
||||
|
||||
double phase0 = 2.0 * Pi / arraySize;
|
||||
for (int i = 0; i <= arraySize - 1; i++)
|
||||
{
|
||||
sinarray[i] = sign * Math.Sin(phase0 * i);
|
||||
cosarray[i] = Math.Cos(phase0 * i);
|
||||
}
|
||||
|
||||
int j = _arraySize;
|
||||
while (j != 1)
|
||||
{
|
||||
_ldArraysize++;
|
||||
j /= 2;
|
||||
}
|
||||
}
|
||||
|
||||
public void MagnitudeSpectrum(double[] real, double[] imag, double w0, double[] magnitude)
|
||||
{
|
||||
int i;
|
||||
magnitude[0] = Math.Sqrt(SquareSum(real[0], imag[0]));
|
||||
for (i = 1; i <= (_arraySize / 2 - 1); i++)
|
||||
magnitude[i] = (Math.Sqrt(SquareSum(real[i], imag[i]) + SquareSum(real[_arraySize - i], imag[_arraySize - i]))) / w0;
|
||||
}
|
||||
|
||||
public static double Hanning(int n, int j)
|
||||
{
|
||||
return W0Hanning - 0.5 * Math.Cos(2.0 * Pi * j / n);
|
||||
}
|
||||
|
||||
public static double Hamming(int n, int j)
|
||||
{
|
||||
return W0Hamming - 0.46 * Math.Cos(2.0 * Pi * j / n);
|
||||
}
|
||||
|
||||
public static double Blackman(int n, int j)
|
||||
{
|
||||
return W0Blackman - 0.5 * Math.Cos(2.0 * Pi * j / n) + 0.08 * Math.Cos(4.0 * Pi * j / n);
|
||||
}
|
||||
|
||||
private static void Swap(ref double a, ref double b)
|
||||
{
|
||||
double temp = a;
|
||||
a = b;
|
||||
b = temp;
|
||||
}
|
||||
|
||||
private static double SquareSum(double a, double b)
|
||||
{
|
||||
return a * a + b * b;
|
||||
}
|
||||
|
||||
public void FourierTransform(double[] real, double[] imag)
|
||||
{
|
||||
int i;
|
||||
if (_forward)
|
||||
{
|
||||
for (i = 0; i <= _arraySize - 1; i++)
|
||||
{
|
||||
real[i] /= _arraySize;
|
||||
imag[i] /= _arraySize;
|
||||
}
|
||||
}
|
||||
|
||||
int k;
|
||||
int j = 0;
|
||||
for (i = 0; i <= _arraySize - 2; i++)
|
||||
{
|
||||
if (i < j)
|
||||
{
|
||||
Swap(ref real[i], ref real[j]);
|
||||
Swap(ref imag[i], ref imag[j]);
|
||||
}
|
||||
k = _arraySize / 2;
|
||||
while (k <= j)
|
||||
{
|
||||
j -= k;
|
||||
k /= 2;
|
||||
}
|
||||
j += k;
|
||||
}
|
||||
|
||||
int a = 2;
|
||||
int b = 1;
|
||||
for (int count = 1; count <= _ldArraysize; count++)
|
||||
{
|
||||
int c0 = _arraySize / a;
|
||||
int c1 = 0;
|
||||
for (k = 0; k <= b - 1; k++)
|
||||
{
|
||||
i = k;
|
||||
while (i < _arraySize)
|
||||
{
|
||||
int arg = i + b;
|
||||
double prodreal;
|
||||
double prodimag;
|
||||
if (k == 0)
|
||||
{
|
||||
prodreal = real[arg];
|
||||
prodimag = imag[arg];
|
||||
}
|
||||
else
|
||||
{
|
||||
prodreal = real[arg] * cosarray[c1] - imag[arg] * sinarray[c1];
|
||||
prodimag = real[arg] * sinarray[c1] + imag[arg] * cosarray[c1];
|
||||
}
|
||||
real[arg] = real[i] - prodreal;
|
||||
imag[arg] = imag[i] - prodimag;
|
||||
real[i] += prodreal;
|
||||
imag[i] += prodimag;
|
||||
i += a;
|
||||
}
|
||||
c1 += c0;
|
||||
}
|
||||
a *= 2;
|
||||
b *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
52
libse/HistoryItem.cs
Normal file
52
libse/HistoryItem.cs
Normal file
@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core
|
||||
{
|
||||
public class HistoryItem
|
||||
{
|
||||
public int Index { get; set; }
|
||||
public DateTime Timestamp { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string FileName { get; set; }
|
||||
public DateTime FileModified { get; set; }
|
||||
public Subtitle Subtitle { get; set; }
|
||||
public string SubtitleFormatFriendlyName { get; set; }
|
||||
public Subtitle OriginalSubtitle { get; set; }
|
||||
public string OriginalSubtitleFileName { get; set; }
|
||||
public List<Paragraph> RedoParagraphs { get; set; }
|
||||
public List<Paragraph> RedoParagraphsAlternate { get; set; }
|
||||
public int RedoLineIndex { get; set; }
|
||||
public int RedoLinePosition { get; set; }
|
||||
public int RedoLinePositionAlternate { get; set; }
|
||||
public string RedoFileName { get; set; }
|
||||
public DateTime RedoFileModified { get; set; }
|
||||
public string RedoOriginalFileName { get; set; }
|
||||
public int LineIndex { get; set; }
|
||||
public int LinePosition { get; set; }
|
||||
public int LinePositionAlternate { get; set; }
|
||||
|
||||
public HistoryItem(int index, Subtitle subtitle, string description, string fileName, DateTime fileModified, string subtitleFormatFriendlyName, Subtitle originalSubtitle, string originalSubtitleFileName, int lineIndex, int linePosition, int linePositionAlternate)
|
||||
{
|
||||
Index = index;
|
||||
Timestamp = DateTime.Now;
|
||||
Subtitle = new Subtitle(subtitle);
|
||||
Description = description;
|
||||
FileName = fileName;
|
||||
FileModified = fileModified;
|
||||
SubtitleFormatFriendlyName = subtitleFormatFriendlyName;
|
||||
OriginalSubtitle = new Subtitle(originalSubtitle);
|
||||
OriginalSubtitleFileName = originalSubtitleFileName;
|
||||
LineIndex = lineIndex;
|
||||
LinePosition = linePosition;
|
||||
LinePositionAlternate = linePositionAlternate;
|
||||
RedoLineIndex = -1;
|
||||
RedoLinePosition = -1;
|
||||
}
|
||||
|
||||
public string ToHHMMSS()
|
||||
{
|
||||
return string.Format("{0:00}:{1:00}:{2:00}", Timestamp.Hour, Timestamp.Minute, Timestamp.Second);
|
||||
}
|
||||
}
|
||||
}
|
669
libse/HtmlUtil.cs
Normal file
669
libse/HtmlUtil.cs
Normal file
@ -0,0 +1,669 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// HTML specific string manipulations.
|
||||
/// </summary>
|
||||
public static class HtmlUtil
|
||||
{
|
||||
public const string TagItalic = "i";
|
||||
public const string TagBold = "b";
|
||||
public const string TagUnderline = "u";
|
||||
public const string TagParagraph = "p";
|
||||
public const string TagFont = "font";
|
||||
public const string TagCyrillicI = "\u0456"; // Cyrillic Small Letter Byelorussian-Ukrainian i (http://graphemica.com/%D1%96)
|
||||
|
||||
private static readonly Regex TagOpenRegex = new Regex(@"<\s*(?:/\s*)?(\w+)[^>]*>", RegexOptions.Compiled);
|
||||
|
||||
/// <summary>
|
||||
/// Remove all of the specified opening and closing tags from the source HTML string.
|
||||
/// </summary>
|
||||
/// <param name="source">The source string to search for specified HTML tags.</param>
|
||||
/// <param name="tags">The HTML tags to remove.</param>
|
||||
/// <returns>A new string without the specified opening and closing tags.</returns>
|
||||
public static string RemoveOpenCloseTags(string source, params string[] tags)
|
||||
{
|
||||
// This pattern matches these tag formats:
|
||||
// <tag*>
|
||||
// < tag*>
|
||||
// </tag*>
|
||||
// < /tag*>
|
||||
// </ tag*>
|
||||
// < / tag*>
|
||||
return TagOpenRegex.Replace(
|
||||
source,
|
||||
m => tags.Contains(m.Groups[1].Value, StringComparer.OrdinalIgnoreCase) ? string.Empty : m.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a string to an HTML-encoded string using named character references.
|
||||
/// </summary>
|
||||
/// <param name="source">The string to encode.</param>
|
||||
/// <returns>An encoded string.</returns>
|
||||
public static string EncodeNamed(string source)
|
||||
{
|
||||
if (source == null)
|
||||
return string.Empty;
|
||||
|
||||
var encoded = new StringBuilder(source.Length);
|
||||
foreach (var ch in source)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case '<':
|
||||
encoded.Append("<");
|
||||
break;
|
||||
case '>':
|
||||
encoded.Append(">");
|
||||
break;
|
||||
case '"':
|
||||
encoded.Append(""");
|
||||
break;
|
||||
case '&':
|
||||
encoded.Append("&");
|
||||
break;
|
||||
case '\'':
|
||||
encoded.Append("'");
|
||||
break;
|
||||
case ' ':
|
||||
encoded.Append(" ");
|
||||
break;
|
||||
case '–':
|
||||
encoded.Append("–");
|
||||
break;
|
||||
case '—':
|
||||
encoded.Append("—");
|
||||
break;
|
||||
case '¡':
|
||||
encoded.Append("¡");
|
||||
break;
|
||||
case '¿':
|
||||
encoded.Append("¿");
|
||||
break;
|
||||
case '“':
|
||||
encoded.Append("“");
|
||||
break;
|
||||
case '”':
|
||||
encoded.Append("”");
|
||||
break;
|
||||
case '‘':
|
||||
encoded.Append("‘");
|
||||
break;
|
||||
case '’':
|
||||
encoded.Append("’");
|
||||
break;
|
||||
case '«':
|
||||
encoded.Append("«");
|
||||
break;
|
||||
case '»':
|
||||
encoded.Append("»");
|
||||
break;
|
||||
case '¢':
|
||||
encoded.Append("¢");
|
||||
break;
|
||||
case '©':
|
||||
encoded.Append("©");
|
||||
break;
|
||||
case '÷':
|
||||
encoded.Append("÷");
|
||||
break;
|
||||
case 'µ':
|
||||
encoded.Append("µ");
|
||||
break;
|
||||
case '·':
|
||||
encoded.Append("·");
|
||||
break;
|
||||
case '¶':
|
||||
encoded.Append("¶");
|
||||
break;
|
||||
case '±':
|
||||
encoded.Append("±");
|
||||
break;
|
||||
case '€':
|
||||
encoded.Append("€");
|
||||
break;
|
||||
case '£':
|
||||
encoded.Append("£");
|
||||
break;
|
||||
case '®':
|
||||
encoded.Append("®");
|
||||
break;
|
||||
case '§':
|
||||
encoded.Append("§");
|
||||
break;
|
||||
case '™':
|
||||
encoded.Append("™");
|
||||
break;
|
||||
case '¥':
|
||||
encoded.Append("¥");
|
||||
break;
|
||||
case 'á':
|
||||
encoded.Append("á");
|
||||
break;
|
||||
case 'Á':
|
||||
encoded.Append("Á");
|
||||
break;
|
||||
case 'à':
|
||||
encoded.Append("à");
|
||||
break;
|
||||
case 'À':
|
||||
encoded.Append("À");
|
||||
break;
|
||||
case 'â':
|
||||
encoded.Append("â");
|
||||
break;
|
||||
case 'Â':
|
||||
encoded.Append("Â");
|
||||
break;
|
||||
case 'å':
|
||||
encoded.Append("å");
|
||||
break;
|
||||
case 'Å':
|
||||
encoded.Append("Å");
|
||||
break;
|
||||
case 'ã':
|
||||
encoded.Append("ã");
|
||||
break;
|
||||
case 'Ã':
|
||||
encoded.Append("Ã");
|
||||
break;
|
||||
case 'ä':
|
||||
encoded.Append("ä");
|
||||
break;
|
||||
case 'Ä':
|
||||
encoded.Append("Ä");
|
||||
break;
|
||||
case 'æ':
|
||||
encoded.Append("æ");
|
||||
break;
|
||||
case 'Æ':
|
||||
encoded.Append("Æ");
|
||||
break;
|
||||
case 'ç':
|
||||
encoded.Append("ç");
|
||||
break;
|
||||
case 'Ç':
|
||||
encoded.Append("Ç");
|
||||
break;
|
||||
case 'é':
|
||||
encoded.Append("é");
|
||||
break;
|
||||
case 'É':
|
||||
encoded.Append("É");
|
||||
break;
|
||||
case 'è':
|
||||
encoded.Append("è");
|
||||
break;
|
||||
case 'È':
|
||||
encoded.Append("È");
|
||||
break;
|
||||
case 'ê':
|
||||
encoded.Append("ê");
|
||||
break;
|
||||
case 'Ê':
|
||||
encoded.Append("Ê");
|
||||
break;
|
||||
case 'ë':
|
||||
encoded.Append("ë");
|
||||
break;
|
||||
case 'Ë':
|
||||
encoded.Append("Ë");
|
||||
break;
|
||||
case 'í':
|
||||
encoded.Append("í");
|
||||
break;
|
||||
case 'Í':
|
||||
encoded.Append("Í");
|
||||
break;
|
||||
case 'ì':
|
||||
encoded.Append("ì");
|
||||
break;
|
||||
case 'Ì':
|
||||
encoded.Append("Ì");
|
||||
break;
|
||||
case 'î':
|
||||
encoded.Append("î");
|
||||
break;
|
||||
case 'Î':
|
||||
encoded.Append("Î");
|
||||
break;
|
||||
case 'ï':
|
||||
encoded.Append("ï");
|
||||
break;
|
||||
case 'Ï':
|
||||
encoded.Append("Ï");
|
||||
break;
|
||||
case 'ñ':
|
||||
encoded.Append("ñ");
|
||||
break;
|
||||
case 'Ñ':
|
||||
encoded.Append("Ñ");
|
||||
break;
|
||||
case 'ó':
|
||||
encoded.Append("ó");
|
||||
break;
|
||||
case 'Ó':
|
||||
encoded.Append("Ó");
|
||||
break;
|
||||
case 'ò':
|
||||
encoded.Append("ò");
|
||||
break;
|
||||
case 'Ò':
|
||||
encoded.Append("Ò");
|
||||
break;
|
||||
case 'ô':
|
||||
encoded.Append("ô");
|
||||
break;
|
||||
case 'Ô':
|
||||
encoded.Append("Ô");
|
||||
break;
|
||||
case 'ø':
|
||||
encoded.Append("ø");
|
||||
break;
|
||||
case 'Ø':
|
||||
encoded.Append("Ø");
|
||||
break;
|
||||
case 'õ':
|
||||
encoded.Append("õ");
|
||||
break;
|
||||
case 'Õ':
|
||||
encoded.Append("Õ");
|
||||
break;
|
||||
case 'ö':
|
||||
encoded.Append("ö");
|
||||
break;
|
||||
case 'Ö':
|
||||
encoded.Append("Ö");
|
||||
break;
|
||||
case 'ß':
|
||||
encoded.Append("ß");
|
||||
break;
|
||||
case 'ú':
|
||||
encoded.Append("ú");
|
||||
break;
|
||||
case 'Ú':
|
||||
encoded.Append("Ú");
|
||||
break;
|
||||
case 'ù':
|
||||
encoded.Append("ù");
|
||||
break;
|
||||
case 'Ù':
|
||||
encoded.Append("Ù");
|
||||
break;
|
||||
case 'û':
|
||||
encoded.Append("û");
|
||||
break;
|
||||
case 'Û':
|
||||
encoded.Append("Û");
|
||||
break;
|
||||
case 'ü':
|
||||
encoded.Append("ü");
|
||||
break;
|
||||
case 'Ü':
|
||||
encoded.Append("Ü");
|
||||
break;
|
||||
case 'ÿ':
|
||||
encoded.Append("ÿ");
|
||||
break;
|
||||
default:
|
||||
if (ch > 127)
|
||||
encoded.Append("&#" + (int)ch + ";");
|
||||
else
|
||||
encoded.Append(ch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return encoded.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a string to an HTML-encoded string using numeric character references.
|
||||
/// </summary>
|
||||
/// <param name="source">The string to encode.</param>
|
||||
/// <returns>An encoded string.</returns>
|
||||
public static string EncodeNumeric(string source)
|
||||
{
|
||||
if (source == null)
|
||||
return string.Empty;
|
||||
|
||||
var encoded = new StringBuilder(source.Length);
|
||||
foreach (var ch in source)
|
||||
{
|
||||
if (ch == ' ')
|
||||
{
|
||||
encoded.Append("&#");
|
||||
encoded.Append(160); //
|
||||
encoded.Append(';');
|
||||
}
|
||||
else if (ch > 127 || ch == '<' || ch == '>' || ch == '"' || ch == '&' || ch == '\'')
|
||||
{
|
||||
encoded.Append("&#");
|
||||
encoded.Append((int)ch);
|
||||
encoded.Append(';');
|
||||
}
|
||||
else
|
||||
{
|
||||
encoded.Append(ch);
|
||||
}
|
||||
}
|
||||
return encoded.ToString();
|
||||
}
|
||||
|
||||
public static string RemoveHtmlTags(string s, bool alsoSsaTags = false)
|
||||
{
|
||||
if (s == null || s.Length < 3)
|
||||
return s;
|
||||
|
||||
if (alsoSsaTags)
|
||||
s = Utilities.RemoveSsaTags(s);
|
||||
|
||||
if (!s.Contains('<'))
|
||||
return s;
|
||||
|
||||
if (s.Contains("< "))
|
||||
s = FixInvalidItalicTags(s);
|
||||
|
||||
return RemoveOpenCloseTags(s, TagItalic, TagBold, TagUnderline, TagParagraph, TagFont, TagCyrillicI);
|
||||
}
|
||||
|
||||
public static bool IsUrl(string text)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(text) || text.Length < 6 || !text.Contains('.') || text.Contains(' '))
|
||||
return false;
|
||||
|
||||
var allLower = text.ToLower();
|
||||
if (allLower.StartsWith("http://", StringComparison.Ordinal) || allLower.StartsWith("https://", StringComparison.Ordinal) ||
|
||||
allLower.StartsWith("www.", StringComparison.Ordinal) || allLower.EndsWith(".org", StringComparison.Ordinal) ||
|
||||
allLower.EndsWith(".com", StringComparison.Ordinal) || allLower.EndsWith(".net", StringComparison.Ordinal))
|
||||
return true;
|
||||
|
||||
if (allLower.Contains(".org/") || allLower.Contains(".com/") || allLower.Contains(".net/"))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool StartsWithUrl(string text)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
return false;
|
||||
|
||||
var arr = text.Trim().TrimEnd('.').TrimEnd().Split();
|
||||
if (arr.Length == 0)
|
||||
return false;
|
||||
|
||||
return IsUrl(arr[0]);
|
||||
}
|
||||
|
||||
public static string FixUpperTags(string text)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text))
|
||||
return text;
|
||||
var tags = new string[] { "<I>", "<U>", "<B>", "<FONT", "</I>", "</U>", "</B>", "</FONT>" };
|
||||
var idx = text.IndexOfAny(tags, StringComparison.Ordinal);
|
||||
while (idx >= 0)
|
||||
{
|
||||
var endIdx = text.IndexOf('>', idx + 2);
|
||||
if (endIdx < idx)
|
||||
break;
|
||||
var tag = text.Substring(idx, endIdx - idx).ToLowerInvariant();
|
||||
text = text.Remove(idx, endIdx - idx).Insert(idx, tag);
|
||||
idx = text.IndexOfAny(tags, StringComparison.Ordinal);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
public static string FixInvalidItalicTags(string text)
|
||||
{
|
||||
const string beginTag = "<i>";
|
||||
const string endTag = "</i>";
|
||||
|
||||
text = text.Replace("< i >", beginTag);
|
||||
text = text.Replace("< i>", beginTag);
|
||||
text = text.Replace("<i >", beginTag);
|
||||
text = text.Replace("< I>", beginTag);
|
||||
text = text.Replace("<I >", beginTag);
|
||||
|
||||
text = text.Replace("< / i >", endTag);
|
||||
text = text.Replace("< /i>", endTag);
|
||||
text = text.Replace("</ i>", endTag);
|
||||
text = text.Replace("< /i>", endTag);
|
||||
text = text.Replace("< /i >", endTag);
|
||||
text = text.Replace("</i >", endTag);
|
||||
text = text.Replace("</ i >", endTag);
|
||||
text = text.Replace("< / i>", endTag);
|
||||
text = text.Replace("< /I>", endTag);
|
||||
text = text.Replace("</ I>", endTag);
|
||||
text = text.Replace("< /I>", endTag);
|
||||
text = text.Replace("< / I >", endTag);
|
||||
|
||||
text = text.Replace("</i> <i>", "_@_");
|
||||
text = text.Replace(" _@_", "_@_");
|
||||
text = text.Replace(" _@_ ", "_@_");
|
||||
text = text.Replace("_@_", " ");
|
||||
|
||||
if (text.Contains(beginTag))
|
||||
text = text.Replace("<i/>", endTag);
|
||||
else
|
||||
text = text.Replace("<i/>", string.Empty);
|
||||
|
||||
text = text.Replace(beginTag + beginTag, beginTag);
|
||||
text = text.Replace(endTag + endTag, endTag);
|
||||
|
||||
int italicBeginTagCount = Utilities.CountTagInText(text, beginTag);
|
||||
int italicEndTagCount = Utilities.CountTagInText(text, endTag);
|
||||
int noOfLines = Utilities.GetNumberOfLines(text);
|
||||
if (italicBeginTagCount + italicEndTagCount > 0)
|
||||
{
|
||||
if (italicBeginTagCount == 1 && italicEndTagCount == 1 && text.IndexOf(beginTag, StringComparison.Ordinal) > text.IndexOf(endTag, StringComparison.Ordinal))
|
||||
{
|
||||
text = text.Replace(beginTag, "___________@");
|
||||
text = text.Replace(endTag, beginTag);
|
||||
text = text.Replace("___________@", endTag);
|
||||
}
|
||||
|
||||
if (italicBeginTagCount == 2 && italicEndTagCount == 0)
|
||||
{
|
||||
int firstIndex = text.IndexOf(beginTag, StringComparison.Ordinal);
|
||||
int lastIndex = text.LastIndexOf(beginTag, StringComparison.Ordinal);
|
||||
int lastIndexWithNewLine = text.LastIndexOf(Environment.NewLine + beginTag, StringComparison.Ordinal) + Environment.NewLine.Length;
|
||||
if (noOfLines == 2 && lastIndex == lastIndexWithNewLine && firstIndex < 2)
|
||||
text = text.Replace(Environment.NewLine, "</i>" + Environment.NewLine) + "</i>";
|
||||
else if (text.Length > lastIndex + endTag.Length)
|
||||
text = text.Substring(0, lastIndex) + endTag + text.Substring(lastIndex - 1 + endTag.Length);
|
||||
else
|
||||
text = text.Substring(0, lastIndex) + endTag;
|
||||
}
|
||||
|
||||
if (italicBeginTagCount == 1 && italicEndTagCount == 2)
|
||||
{
|
||||
int firstIndex = text.IndexOf(endTag, StringComparison.Ordinal);
|
||||
if (text.StartsWith("</i>-<i>-", StringComparison.Ordinal))
|
||||
text = text.Remove(0, 5);
|
||||
else if (text.StartsWith("</i>- <i>-", StringComparison.Ordinal))
|
||||
text = text.Remove(0, 5);
|
||||
else if (text.StartsWith("</i>- <i> -", StringComparison.Ordinal))
|
||||
text = text.Remove(0, 5);
|
||||
else if (text.StartsWith("</i>-<i> -", StringComparison.Ordinal))
|
||||
text = text.Remove(0, 5);
|
||||
else if (firstIndex == 0)
|
||||
text = text.Remove(0, 4);
|
||||
else
|
||||
text = text.Substring(0, firstIndex) + text.Substring(firstIndex + endTag.Length);
|
||||
}
|
||||
|
||||
if (italicBeginTagCount == 2 && italicEndTagCount == 1)
|
||||
{
|
||||
var lines = text.SplitToLines();
|
||||
if (lines.Length == 2 && lines[0].StartsWith("<i>", StringComparison.Ordinal) && lines[0].EndsWith("</i>", StringComparison.Ordinal) &&
|
||||
lines[1].StartsWith("<i>", StringComparison.Ordinal))
|
||||
{
|
||||
text = text.TrimEnd() + "</i>";
|
||||
}
|
||||
else
|
||||
{
|
||||
int lastIndex = text.LastIndexOf(beginTag, StringComparison.Ordinal);
|
||||
if (text.Length > lastIndex + endTag.Length)
|
||||
text = text.Substring(0, lastIndex) + text.Substring(lastIndex - 1 + endTag.Length);
|
||||
else
|
||||
text = text.Substring(0, lastIndex - 1) + endTag;
|
||||
}
|
||||
if (text.StartsWith("<i>", StringComparison.Ordinal) && text.EndsWith("</i>", StringComparison.Ordinal) && text.Contains("</i>" + Environment.NewLine + "<i>"))
|
||||
{
|
||||
text = text.Replace("</i>" + Environment.NewLine + "<i>", Environment.NewLine);
|
||||
}
|
||||
}
|
||||
|
||||
if (italicBeginTagCount == 1 && italicEndTagCount == 0)
|
||||
{
|
||||
int lastIndexWithNewLine = text.LastIndexOf(Environment.NewLine + beginTag, StringComparison.Ordinal) + Environment.NewLine.Length;
|
||||
int lastIndex = text.LastIndexOf(beginTag, StringComparison.Ordinal);
|
||||
|
||||
if (text.StartsWith(beginTag, StringComparison.Ordinal))
|
||||
text += endTag;
|
||||
else if (noOfLines == 2 && lastIndex == lastIndexWithNewLine)
|
||||
text += endTag;
|
||||
else
|
||||
text = text.Replace(beginTag, string.Empty);
|
||||
}
|
||||
|
||||
if (italicBeginTagCount == 0 && italicEndTagCount == 1)
|
||||
{
|
||||
var cleanText = HtmlUtil.RemoveOpenCloseTags(text, HtmlUtil.TagItalic, HtmlUtil.TagBold, HtmlUtil.TagUnderline, HtmlUtil.TagCyrillicI);
|
||||
bool isFixed = false;
|
||||
|
||||
// Foo.</i>
|
||||
if (text.EndsWith(endTag, StringComparison.Ordinal) && !cleanText.StartsWith('-') && !cleanText.Contains(Environment.NewLine + "-"))
|
||||
{
|
||||
text = beginTag + text;
|
||||
isFixed = true;
|
||||
}
|
||||
|
||||
// - Foo</i> | - Foo.
|
||||
// - Bar. | - Foo.</i>
|
||||
if (!isFixed && Utilities.GetNumberOfLines(cleanText) == 2)
|
||||
{
|
||||
int newLineIndex = text.IndexOf(Environment.NewLine, StringComparison.Ordinal);
|
||||
if (newLineIndex > 0)
|
||||
{
|
||||
var firstLine = text.Substring(0, newLineIndex).Trim();
|
||||
var secondLine = text.Substring(newLineIndex + 2).Trim();
|
||||
if (firstLine.EndsWith(endTag, StringComparison.Ordinal))
|
||||
{
|
||||
firstLine = beginTag + firstLine;
|
||||
isFixed = true;
|
||||
}
|
||||
if (secondLine.EndsWith(endTag, StringComparison.Ordinal))
|
||||
{
|
||||
secondLine = beginTag + secondLine;
|
||||
isFixed = true;
|
||||
}
|
||||
text = firstLine + Environment.NewLine + secondLine;
|
||||
}
|
||||
}
|
||||
if (!isFixed)
|
||||
text = text.Replace(endTag, string.Empty);
|
||||
}
|
||||
|
||||
// - foo.</i>
|
||||
// - bar.</i>
|
||||
if (italicBeginTagCount == 0 && italicEndTagCount == 2 && text.Contains(endTag + Environment.NewLine, StringComparison.Ordinal) && text.EndsWith(endTag, StringComparison.Ordinal))
|
||||
{
|
||||
text = text.Replace(endTag, string.Empty);
|
||||
text = beginTag + text + endTag;
|
||||
}
|
||||
|
||||
if (italicBeginTagCount == 0 && italicEndTagCount == 2 && text.StartsWith("</i>", StringComparison.Ordinal) && text.EndsWith("</i>", StringComparison.Ordinal))
|
||||
{
|
||||
int firstIndex = text.IndexOf(endTag, StringComparison.Ordinal);
|
||||
text = text.Remove(firstIndex, endTag.Length).Insert(firstIndex, "<i>");
|
||||
}
|
||||
|
||||
// <i>Foo</i>
|
||||
// <i>Bar</i>
|
||||
if (italicBeginTagCount == 2 && italicEndTagCount == 2 && Utilities.GetNumberOfLines(text) == 2)
|
||||
{
|
||||
int index = text.IndexOf(Environment.NewLine, StringComparison.Ordinal);
|
||||
if (index > 0 && text.Length > index + (beginTag.Length + endTag.Length))
|
||||
{
|
||||
var firstLine = text.Substring(0, index).Trim();
|
||||
var secondLine = text.Substring(index + 2).Trim();
|
||||
|
||||
if (firstLine.Length > 10 && firstLine.StartsWith("- <i>", StringComparison.Ordinal) && firstLine.EndsWith(endTag, StringComparison.Ordinal))
|
||||
{
|
||||
text = "<i>- " + firstLine.Remove(0, 5) + Environment.NewLine + secondLine;
|
||||
text = text.Replace("<i>- ", "<i>- ");
|
||||
index = text.IndexOf(Environment.NewLine, StringComparison.Ordinal);
|
||||
firstLine = text.Substring(0, index).Trim();
|
||||
secondLine = text.Substring(index + 2).Trim();
|
||||
}
|
||||
if (secondLine.Length > 10 && secondLine.StartsWith("- <i>", StringComparison.Ordinal) && secondLine.EndsWith(endTag, StringComparison.Ordinal))
|
||||
{
|
||||
text = firstLine + Environment.NewLine + "<i>- " + secondLine.Remove(0, 5);
|
||||
text = text.Replace("<i>- ", "<i>- ");
|
||||
index = text.IndexOf(Environment.NewLine, StringComparison.Ordinal);
|
||||
firstLine = text.Substring(0, index).Trim();
|
||||
secondLine = text.Substring(index + 2).Trim();
|
||||
}
|
||||
|
||||
if (Utilities.StartsAndEndsWithTag(firstLine, beginTag, endTag) && Utilities.StartsAndEndsWithTag(secondLine, beginTag, endTag))
|
||||
{
|
||||
text = text.Replace(beginTag, String.Empty).Replace(endTag, String.Empty).Trim();
|
||||
text = beginTag + text + endTag;
|
||||
}
|
||||
}
|
||||
|
||||
//FALCONE:<i> I didn't think</i><br /><i>it was going to be you,</i>
|
||||
var colIdx = text.IndexOf(':');
|
||||
if (colIdx > -1 && Utilities.CountTagInText(text, "<i>") + Utilities.CountTagInText(text, "</i>") == 4 && text.Length > colIdx + 1 && !char.IsDigit(text[colIdx + 1]))
|
||||
{
|
||||
var firstLine = text.Substring(0, index);
|
||||
var secondLine = text.Substring(index).TrimStart();
|
||||
|
||||
var secIdxCol = secondLine.IndexOf(':');
|
||||
if (secIdxCol < 0 || !Utilities.IsBetweenNumbers(secondLine, secIdxCol))
|
||||
{
|
||||
var idx = firstLine.IndexOf(':');
|
||||
if (idx > 1)
|
||||
{
|
||||
var pre = text.Substring(0, idx + 1).TrimStart();
|
||||
text = text.Remove(0, idx + 1);
|
||||
text = FixInvalidItalicTags(text).Trim();
|
||||
if (text.StartsWith("<i> ", StringComparison.OrdinalIgnoreCase))
|
||||
text = Utilities.RemoveSpaceBeforeAfterTag(text, "<i>");
|
||||
text = pre + " " + text;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//<i>- You think they're they gone?<i>
|
||||
//<i>- That can't be.</i>
|
||||
if ((italicBeginTagCount == 3 && italicEndTagCount == 1) && Utilities.GetNumberOfLines(text) == 2)
|
||||
{
|
||||
var newLineIdx = text.IndexOf(Environment.NewLine, StringComparison.Ordinal);
|
||||
var firstLine = text.Substring(0, newLineIdx).Trim();
|
||||
var secondLine = text.Substring(newLineIdx).Trim();
|
||||
|
||||
if ((Utilities.StartsAndEndsWithTag(firstLine, beginTag, beginTag) && Utilities.StartsAndEndsWithTag(secondLine, beginTag, endTag)) ||
|
||||
(Utilities.StartsAndEndsWithTag(secondLine, beginTag, beginTag) && Utilities.StartsAndEndsWithTag(firstLine, beginTag, endTag)))
|
||||
{
|
||||
text = text.Replace("<i>", string.Empty);
|
||||
text = text.Replace("</i>", string.Empty);
|
||||
text = text.Replace(" ", " ").Trim();
|
||||
text = "<i>" + text + "</i>";
|
||||
}
|
||||
}
|
||||
text = text.Replace("<i></i>", string.Empty);
|
||||
text = text.Replace("<i> </i>", string.Empty);
|
||||
text = text.Replace("<i> </i>", string.Empty);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
619
libse/IfoParser.cs
Normal file
619
libse/IfoParser.cs
Normal file
@ -0,0 +1,619 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Nikse.Core;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core
|
||||
{
|
||||
public class IfoParser : IDisposable
|
||||
{
|
||||
public struct AudioStream
|
||||
{
|
||||
public int LanguageTypeSpecified;
|
||||
public string Language;
|
||||
public string LanguageCode;
|
||||
public string CodingMode;
|
||||
public int Channels;
|
||||
public string Extension;
|
||||
};
|
||||
|
||||
public struct VideoStream
|
||||
{
|
||||
public string Aspect;
|
||||
public string Standard;
|
||||
public string CodingMode;
|
||||
public string Resolution;
|
||||
}
|
||||
|
||||
public class VtsVobs
|
||||
{
|
||||
public int NumberOfAudioStreams;
|
||||
public int NumberOfSubtitles;
|
||||
public VideoStream VideoStream;
|
||||
public List<AudioStream> AudioStreams;
|
||||
public List<string> Subtitles;
|
||||
public List<string> SubtitleIDs;
|
||||
public List<string> SubtitleTypes;
|
||||
|
||||
public List<string> GetAllLanguages()
|
||||
{
|
||||
var list = new List<string>();
|
||||
for (int i = 0; i < Subtitles.Count; i++)
|
||||
{
|
||||
if (i < SubtitleIDs.Count && i < SubtitleTypes.Count)
|
||||
{
|
||||
var ids = SubtitleIDs[i].Split(',');
|
||||
var types = SubtitleTypes[i].Split(',');
|
||||
if (ids.Length == 2 && ids[0].Trim() == ids[1].Trim() || ids.Length == 3 && ids[0].Trim() == ids[1].Trim() && ids[1].Trim() == ids[2].Trim())
|
||||
{
|
||||
list.Add(Subtitles[i] + " (" + ids[0].Trim() + ")");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ids.Length >= 1 && types.Length >= 1)
|
||||
{
|
||||
list.Add(Subtitles[i] + ", " + types[0].Trim() + " (" + ids[0].Trim() + ")");
|
||||
}
|
||||
if (ids.Length >= 2 && types.Length >= 2)
|
||||
{
|
||||
list.Add(Subtitles[i] + ", " + types[1].Trim() + " (" + ids[1].Trim() + ")");
|
||||
}
|
||||
if (ids.Length >= 3 && types.Length >= 3)
|
||||
{
|
||||
list.Add(Subtitles[i] + ", " + types[2].Trim() + " (" + ids[2].Trim() + ")");
|
||||
}
|
||||
if (ids.Length >= 4 && types.Length >= 4)
|
||||
{
|
||||
list.Add(Subtitles[i] + ", " + types[3].Trim() + " (" + ids[3].Trim() + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public VtsVobs()
|
||||
{
|
||||
VideoStream = new VideoStream();
|
||||
AudioStreams = new List<AudioStream>();
|
||||
Subtitles = new List<string>();
|
||||
SubtitleIDs = new List<string>();
|
||||
SubtitleTypes = new List<string>();
|
||||
}
|
||||
};
|
||||
|
||||
public class ProgramChain
|
||||
{
|
||||
public int NumberOfPgc;
|
||||
public int NumberOfCells;
|
||||
public string PlaybackTime;
|
||||
public List<byte> PgcEntryCells;
|
||||
public List<string> PgcPlaybackTimes;
|
||||
public List<string> PgcStartTimes;
|
||||
public List<char> AudioStreamsAvailable;
|
||||
public List<byte[]> SubtitlesAvailable;
|
||||
public List<Color> ColorLookupTable;
|
||||
|
||||
public ProgramChain()
|
||||
{
|
||||
PgcEntryCells = new List<byte>();
|
||||
PgcPlaybackTimes = new List<string>();
|
||||
PgcStartTimes = new List<string>();
|
||||
AudioStreamsAvailable = new List<char>();
|
||||
SubtitlesAvailable = new List<byte[]>();
|
||||
ColorLookupTable = new List<Color>();
|
||||
}
|
||||
|
||||
public bool Has43Subs { get; set; }
|
||||
public bool HasWideSubs { get; set; }
|
||||
public bool HasLetterSubs { get; set; }
|
||||
public bool HasPanSubs { get; set; }
|
||||
public bool HasNoSpecificSubs { get; set; }
|
||||
};
|
||||
|
||||
public class VtsPgci
|
||||
{
|
||||
public int NumberOfProgramChains;
|
||||
public List<ProgramChain> ProgramChains;
|
||||
|
||||
public VtsPgci()
|
||||
{
|
||||
ProgramChains = new List<ProgramChain>();
|
||||
}
|
||||
};
|
||||
|
||||
private readonly List<string> _arrayOfAudioMode = new List<string> { "AC3", "...", "MPEG1", "MPEG2", "LPCM", "...", "DTS" };
|
||||
private readonly List<string> _arrayOfAudioExtension = new List<string> { "unspecified", "normal", "for visually impaired", "director's comments", "alternate director's comments" };
|
||||
private readonly List<string> _arrayOfAspect = new List<string> { "4:3", "...", "...", "16:9" };
|
||||
private readonly List<string> _arrayOfStandard = new List<string> { "NTSC", "PAL", "...", "..." };
|
||||
private readonly List<string> _arrayOfCodingMode = new List<string> { "MPEG1", "MPEG2" };
|
||||
private readonly List<string> _arrayOfNtscResolution = new List<string> { "720x480", "704x480", "352x480", "352x240" };
|
||||
private readonly List<string> _arrayOfPalResolution = new List<string> { "720x576", "704x576", "352x576", "352x288" };
|
||||
public static List<string> ArrayOfLanguageCode = new List<string> { " ", "aa", "ab", "af", "am", "ar", "as", "ay", "az", "ba", "be", "bg", "bh", "bi", "bn", "bo", "br", "ca", "co", "cs", "cy", "da", "de", "dz", "el",
|
||||
"en", "eo", "es", "et", "eu", "fa", "fi", "fj", "fo", "fr", "fy", "ga", "gd", "gl", "gn", "gu", "ha", "he", "hi", "hr", "hu", "hy", "ia", "id", "ie", "ik",
|
||||
"in", "is", "it", "iu", "iw", "ja", "ji", "jw", "ka", "kk", "kl", "km", "kn", "ko", "ks", "ku", "ky", "la", "ln", "lo", "lt", "lv", "mg", "mi", "mk", "ml",
|
||||
"mn", "mo", "mr", "ms", "mt", "my", "na", "ne", "nl", "no", "oc", "om", "or", "pa", "pl", "ps", "pt", "qu", "rm", "rn", "ro", "ru", "rw", "sa", "sd", "sg",
|
||||
"sh", "si", "sk", "sl", "sm", "sn", "so", "sq", "sr", "ss", "st", "su", "sv", "sw", "ta", "te", "tg", "th", "ti", "tk", "tl", "tn", "to", "tr", "ts", "tt",
|
||||
"tw", "ug", "uk", "ur", "uz", "vi", "vo", "wo", "xh", "yi", "yo", "za", "zh", "zu", ""};
|
||||
public static List<string> ArrayOfLanguage = new List<string> { "Not Specified", "Afar", "Abkhazian", "Afrikaans", "Amharic", "Arabic", "Assamese", "Aymara", "Azerbaijani", "Bashkir", "Byelorussian", "Bulgarian", "Bihari", "Bislama", "Bengali; Bangla", "Tibetan", "Breton", "Catalan", "Corsican", "Czech(Ceske)", "Welsh", "Dansk", "Deutsch", "Bhutani", "Greek",
|
||||
"English", "Esperanto", "Espanol", "Estonian", "Basque", "Persian", "Suomi", "Fiji", "Faroese", "Français", "Frisian", "Irish", "Scots Gaelic", "Galician", "Guarani", "Gujarati", "Hausa", "Hebrew", "Hindi", "Hrvatski", "Magyar", "Armenian", "Interlingua", "Indonesian", "Interlingue", "Inupiak",
|
||||
"Indonesian", "Islenska", "Italiano", "Inuktitut", "Hebrew", "Japanese", "Yiddish", "Javanese", "Georgian", "Kazakh", "Greenlandic", "Cambodian", "Kannada", "Korean", "Kashmiri", "Kurdish", "Kirghiz", "Latin", "Lingala", "Laothian", "Lithuanian", "Latvian, Lettish", "Malagasy", "Maori", "Macedonian", "Malayalam",
|
||||
"Mongolian", "Moldavian", "Marathi", "Malay", "Maltese", "Burmese", "Nauru", "Nepali", "Nederlands", "Norsk", "Occitan", "(Afan) Oromo", "Oriya", "Punjabi", "Polish", "Pashto, Pushto", "Portugues", "Quechua", "Rhaeto-Romance", "Kirundi", "Romanian", "Russian", "Kinyarwanda", "Sanskrit", "Sindhi", "Sangho",
|
||||
"Serbo-Croatian", "Sinhalese", "Slovak", "Slovenian", "Samoan", "Shona", "Somali", "Albanian", "Serbian", "Siswati", "Sesotho", "Sundanese", "Svenska", "Swahili", "Tamil", "Telugu", "Tajik", "Thai", "Tigrinya", "Turkmen", "Tagalog", "Setswana", "Tonga", "Turkish", "Tsonga", "Tatar",
|
||||
"Twi", "Uighur", "Ukrainian", "Urdu", "Uzbek", "Vietnamese", "Volapuk", "Wolof", "Xhosa", "Yiddish", "Yoruba", "Zhuang", "Chinese", "Zulu", "???"};
|
||||
|
||||
public VtsPgci VideoTitleSetProgramChainTable { get { return _vtsPgci; } }
|
||||
public VtsVobs VideoTitleSetVobs { get { return _vtsVobs; } }
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
private readonly VtsVobs _vtsVobs = new VtsVobs();
|
||||
private readonly VtsPgci _vtsPgci = new VtsPgci();
|
||||
private FileStream _fs;
|
||||
|
||||
public IfoParser(string fileName)
|
||||
{
|
||||
try
|
||||
{
|
||||
_fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
|
||||
var buffer = new byte[12];
|
||||
_fs.Position = 0;
|
||||
_fs.Read(buffer, 0, 12);
|
||||
string id = Encoding.UTF8.GetString(buffer);
|
||||
if (id != "DVDVIDEO-VTS")
|
||||
{
|
||||
ErrorMessage = string.Format(Configuration.Settings.Language.DvdSubRip.WrongIfoType, id, Environment.NewLine, fileName);
|
||||
return;
|
||||
}
|
||||
ParseVtsVobs();
|
||||
ParseVtsPgci();
|
||||
_fs.Close();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
ErrorMessage = exception.Message + Environment.NewLine + exception.StackTrace;
|
||||
}
|
||||
}
|
||||
|
||||
private void ParseVtsVobs()
|
||||
{
|
||||
var buffer = new byte[16];
|
||||
|
||||
//retrieve video info
|
||||
_fs.Position = 0x200;
|
||||
var data = IntToBin(GetEndian(2), 16);
|
||||
_vtsVobs.VideoStream.CodingMode = _arrayOfCodingMode[BinToInt(MidStr(data, 0, 2))];
|
||||
_vtsVobs.VideoStream.Standard = _arrayOfStandard[BinToInt(MidStr(data, 2, 2))];
|
||||
_vtsVobs.VideoStream.Aspect = _arrayOfAspect[BinToInt(MidStr(data, 4, 2))];
|
||||
if (_vtsVobs.VideoStream.Standard == "PAL")
|
||||
_vtsVobs.VideoStream.Resolution = _arrayOfPalResolution[BinToInt(MidStr(data, 13, 2))];
|
||||
else if (_vtsVobs.VideoStream.Standard == "NTSC")
|
||||
_vtsVobs.VideoStream.Resolution = _arrayOfNtscResolution[BinToInt(MidStr(data, 13, 2))];
|
||||
|
||||
//retrieve audio info
|
||||
_fs.Position = 0x202; //useless but here for readability
|
||||
_vtsVobs.NumberOfAudioStreams = GetEndian(2);
|
||||
for (int i = 0; i < _vtsVobs.NumberOfAudioStreams; i++)
|
||||
{
|
||||
var audioStream = new AudioStream();
|
||||
data = IntToBin(GetEndian(2), 16);
|
||||
audioStream.LanguageTypeSpecified = Convert.ToInt32(MidStr(data, 4, 2));
|
||||
audioStream.CodingMode = _arrayOfAudioMode[(BinToInt(MidStr(data, 0, 3)))];
|
||||
audioStream.Channels = BinToInt(MidStr(data, 13, 3)) + 1;
|
||||
_fs.Read(buffer, 0, 2);
|
||||
audioStream.LanguageCode = new string(new[] { Convert.ToChar(buffer[0]), Convert.ToChar(buffer[1]) });
|
||||
if (ArrayOfLanguageCode.Contains(audioStream.LanguageCode))
|
||||
audioStream.Language = ArrayOfLanguage[ArrayOfLanguageCode.IndexOf(audioStream.LanguageCode)];
|
||||
_fs.Seek(1, SeekOrigin.Current);
|
||||
audioStream.Extension = _arrayOfAudioExtension[_fs.ReadByte()];
|
||||
_fs.Seek(2, SeekOrigin.Current);
|
||||
_vtsVobs.AudioStreams.Add(audioStream);
|
||||
}
|
||||
|
||||
//retrieve subs info (only name)
|
||||
_fs.Position = 0x254;
|
||||
_vtsVobs.NumberOfSubtitles = GetEndian(2);
|
||||
_fs.Position += 2;
|
||||
for (int i = 0; i < _vtsVobs.NumberOfSubtitles; i++)
|
||||
{
|
||||
_fs.Read(buffer, 0, 2);
|
||||
var languageTwoLetter = new string(new[] { Convert.ToChar(buffer[0]), Convert.ToChar(buffer[1]) });
|
||||
_vtsVobs.Subtitles.Add(InterpretLanguageCode(languageTwoLetter));
|
||||
_fs.Read(buffer, 0, 2); // reserved for language code extension + code extension
|
||||
|
||||
//switch (buffer[0]) // 4, 8, 10-12 unused
|
||||
//{
|
||||
// // http://dvd.sourceforge.net/dvdinfo/sprm.html
|
||||
// case 1: subtitleFormat = "(caption/normal size char)"; break; //0 = unspecified caption
|
||||
// case 2: subtitleFormat = "(caption/large size char)"; break;
|
||||
// case 3: subtitleFormat = "(caption for children)"; break;
|
||||
// case 5: subtitleFormat = "(closed caption/normal size char)"; break;
|
||||
// case 6: subtitleFormat = "(closed caption/large size char)"; break;
|
||||
// case 7: subtitleFormat = "(closed caption for children)"; break;
|
||||
// case 9: subtitleFormat = "(forced caption)"; break;
|
||||
// case 13: subtitleFormat = "(director comments/normal size char)"; break;
|
||||
// case 14: subtitleFormat = "(director comments/large size char)"; break;
|
||||
// case 15: subtitleFormat = "(director comments for children)"; break;
|
||||
//}
|
||||
|
||||
_fs.Position += 2;
|
||||
}
|
||||
}
|
||||
|
||||
private static int BinToInt(string p)
|
||||
{
|
||||
return Convert.ToInt32(p, 2);
|
||||
}
|
||||
|
||||
private static string MidStr(string data, int start, int count)
|
||||
{
|
||||
return data.Substring(start, count);
|
||||
}
|
||||
|
||||
private static string IntToBin(int value, int digits)
|
||||
{
|
||||
string result = Convert.ToString(value, 2);
|
||||
while (result.Length < digits)
|
||||
result = "0" + result;
|
||||
return result;
|
||||
}
|
||||
|
||||
private int GetEndian(int count)
|
||||
{
|
||||
int result = 0;
|
||||
for (int i = count; i > 0; i--)
|
||||
{
|
||||
int b = _fs.ReadByte();
|
||||
result = (result << 8) + b;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string InterpretLanguageCode(string code)
|
||||
{
|
||||
int i = 0;
|
||||
while (ArrayOfLanguageCode[i] != code && i < 143)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
return ArrayOfLanguage[i];
|
||||
}
|
||||
|
||||
private void ParseVtsPgci()
|
||||
{
|
||||
const int sectorSize = 2048;
|
||||
|
||||
_fs.Position = 0xCC; //Get VTS_PGCI adress
|
||||
int tableStart = sectorSize * GetEndian(4);
|
||||
|
||||
_fs.Position = tableStart;
|
||||
_vtsPgci.NumberOfProgramChains = GetEndian(2);
|
||||
_vtsPgci.ProgramChains = new List<ProgramChain>();
|
||||
|
||||
for (int i = 0; i < _vtsPgci.NumberOfProgramChains; i++)
|
||||
{
|
||||
//Parse PGC Header
|
||||
var programChain = new ProgramChain();
|
||||
_fs.Position = tableStart + 4 + 8 * (i + 1); //Get PGC adress
|
||||
int programChainAdress = GetEndian(4);
|
||||
_fs.Position = tableStart + programChainAdress + 2; //Move to PGC
|
||||
programChain.NumberOfPgc = _fs.ReadByte();
|
||||
programChain.NumberOfCells = _fs.ReadByte();
|
||||
programChain.PlaybackTime = InterpretTime(GetEndian(4));
|
||||
_fs.Seek(4, SeekOrigin.Current);
|
||||
|
||||
// check if audio streams are available for this PGC
|
||||
_fs.Position = tableStart + programChainAdress + 0xC;
|
||||
for (int j = 0; j < _vtsVobs.NumberOfAudioStreams; j++)
|
||||
{
|
||||
string temp = IntToBin(_fs.ReadByte(), 8);
|
||||
programChain.AudioStreamsAvailable.Add(temp[0]);
|
||||
_fs.Seek(1, SeekOrigin.Current);
|
||||
}
|
||||
|
||||
// check if subtitles are available for this PGC
|
||||
_fs.Position = tableStart + programChainAdress + 0x1C;
|
||||
for (int j = 0; j < _vtsVobs.NumberOfSubtitles; j++)
|
||||
{
|
||||
// read and save full subpicture stream info inside program chain
|
||||
var subtitle = new byte[4];
|
||||
_fs.Read(subtitle, 0, 4);
|
||||
programChain.SubtitlesAvailable.Add(subtitle);
|
||||
}
|
||||
|
||||
CalculateSubtitleTypes(programChain);
|
||||
|
||||
//Parse Color LookUp Table (CLUT) - offset 00A4, 16*4 (0, Y, Cr, Cb)
|
||||
_fs.Position = tableStart + programChainAdress + 0xA4;
|
||||
for (int colorNumber = 0; colorNumber < 16; colorNumber++)
|
||||
{
|
||||
var colors = new byte[4];
|
||||
_fs.Read(colors, 0, 4);
|
||||
int y = colors[1] - 16;
|
||||
int cr = colors[2] - 128;
|
||||
int cb = colors[3] - 128;
|
||||
int r = (int)Math.Min(Math.Max(Math.Round(1.1644F * y + 1.596F * cr), 0), 255);
|
||||
int g = (int)Math.Min(Math.Max(Math.Round(1.1644F * y - 0.813F * cr - 0.391F * cb), 0), 255);
|
||||
int b = (int)Math.Min(Math.Max(Math.Round(1.1644F * y + 2.018F * cb), 0), 255);
|
||||
|
||||
programChain.ColorLookupTable.Add(Color.FromArgb(r, g, b));
|
||||
}
|
||||
|
||||
//Parse Program Map
|
||||
_fs.Position = tableStart + programChainAdress + 0xE6;
|
||||
_fs.Position = tableStart + programChainAdress + GetEndian(2);
|
||||
for (int j = 0; j < programChain.NumberOfPgc; j++)
|
||||
{
|
||||
programChain.PgcEntryCells.Add((byte)_fs.ReadByte());
|
||||
}
|
||||
|
||||
// Cell Playback Info Table to retrieve duration
|
||||
_fs.Position = tableStart + programChainAdress + 0xE8;
|
||||
_fs.Position = tableStart + programChainAdress + GetEndian(2);
|
||||
var timeArray = new List<int>();
|
||||
for (int k = 0; k < programChain.NumberOfPgc; k++)
|
||||
{
|
||||
int time = 0;
|
||||
int max;
|
||||
if (k == programChain.NumberOfPgc - 1)
|
||||
max = programChain.NumberOfCells;
|
||||
else
|
||||
max = programChain.PgcEntryCells[k + 1] - 1;
|
||||
for (int j = programChain.PgcEntryCells[k]; j <= max; j++)
|
||||
{
|
||||
_fs.Seek(4, SeekOrigin.Current);
|
||||
time += TimeToMs(GetEndian(4));
|
||||
_fs.Seek(16, SeekOrigin.Current);
|
||||
}
|
||||
programChain.PgcPlaybackTimes.Add(MsToTime(time));
|
||||
timeArray.Add(time);
|
||||
|
||||
//convert to start time
|
||||
time = 0;
|
||||
for (int l = 1; l <= k; l++)
|
||||
{
|
||||
time += timeArray[l - 1];
|
||||
}
|
||||
if (k == 0)
|
||||
programChain.PgcStartTimes.Add(MsToTime(0));
|
||||
if (k > 0)
|
||||
programChain.PgcStartTimes.Add(MsToTime(time));
|
||||
}
|
||||
_vtsPgci.ProgramChains.Add(programChain);
|
||||
}
|
||||
}
|
||||
|
||||
private void CalculateSubtitleTypes(ProgramChain programChain)
|
||||
{
|
||||
// Additional Code to analyse stream bytes
|
||||
if (_vtsVobs.NumberOfSubtitles > 0)
|
||||
{
|
||||
// load the 'last' subpicture stream info,
|
||||
// because if we have more than one subtitle stream,
|
||||
// all subtitle positions > 0
|
||||
// lastSubtitle[0] is related to 4:3
|
||||
// lastSubtitle[1] is related to Wide
|
||||
// lastSubtitle[2] is related to letterboxed
|
||||
// lastSubtitle[3] is related to pan&scan
|
||||
byte[] lastSubtitle = programChain.SubtitlesAvailable[programChain.SubtitlesAvailable.Count - 1];
|
||||
|
||||
int countSubs = 0;
|
||||
|
||||
// set defaults for all possible subpicture types and positions
|
||||
programChain.Has43Subs = false;
|
||||
programChain.HasWideSubs = false;
|
||||
programChain.HasLetterSubs = false;
|
||||
programChain.HasPanSubs = false;
|
||||
programChain.HasNoSpecificSubs = true;
|
||||
|
||||
int pos43Subs = -1;
|
||||
int posWideSubs = -1;
|
||||
int posLetterSubs = -1;
|
||||
int posPanSubs = -1;
|
||||
|
||||
// parse different subtitle bytes
|
||||
if (lastSubtitle[0] > 0x80)
|
||||
{
|
||||
programChain.Has43Subs = true;
|
||||
countSubs++; // 4:3
|
||||
}
|
||||
if (lastSubtitle[1] > 0)
|
||||
{
|
||||
programChain.HasWideSubs = true;
|
||||
countSubs++; // wide
|
||||
}
|
||||
if (lastSubtitle[2] > 0)
|
||||
{
|
||||
programChain.HasLetterSubs = true;
|
||||
countSubs++; // letterboxed
|
||||
}
|
||||
if (lastSubtitle[3] > 0)
|
||||
{
|
||||
programChain.HasPanSubs = true;
|
||||
countSubs++; // pan&scan
|
||||
}
|
||||
|
||||
if (countSubs == 0)
|
||||
{
|
||||
// may be, only a 4:3 stream exists
|
||||
// -> lastSubtitle[0] = 0x80
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_vtsVobs.NumberOfSubtitles == 1)
|
||||
{
|
||||
// only 1 stream exists, may be letterboxed
|
||||
// if so we cound't find wide id, because lastSubtitle[1] = 0 !!
|
||||
// corresponding wide stream byte is 0 => wide id = 0x20
|
||||
// letterboxed = 0x21
|
||||
if (programChain.HasLetterSubs && !programChain.HasWideSubs)
|
||||
{
|
||||
// repair it
|
||||
programChain.HasWideSubs = true;
|
||||
}
|
||||
}
|
||||
programChain.HasNoSpecificSubs = false;
|
||||
}
|
||||
|
||||
// subpucture streams start with 0x20
|
||||
int subStream = 0x20;
|
||||
|
||||
// Now we know all about available subpicture streams, including position type
|
||||
// And we can create whole complete definitions for all avalable streams
|
||||
foreach (byte[] subtitle in programChain.SubtitlesAvailable)
|
||||
{
|
||||
if (programChain.HasNoSpecificSubs)
|
||||
{
|
||||
// only one unspezified subpicture stream exists
|
||||
_vtsVobs.SubtitleIDs.Add(string.Format("0x{0:x2}", subStream++));
|
||||
_vtsVobs.SubtitleTypes.Add("unspecific");
|
||||
}
|
||||
else
|
||||
{
|
||||
// read stream position for evey subtitle type from subtitle byte
|
||||
if (programChain.Has43Subs)
|
||||
{
|
||||
pos43Subs = subtitle[0] - 0x80;
|
||||
}
|
||||
if (programChain.HasWideSubs)
|
||||
{
|
||||
posWideSubs = subtitle[1];
|
||||
}
|
||||
if (programChain.HasLetterSubs)
|
||||
{
|
||||
posLetterSubs = subtitle[2];
|
||||
}
|
||||
if (programChain.HasPanSubs)
|
||||
{
|
||||
posPanSubs = subtitle[3];
|
||||
}
|
||||
|
||||
// Now we can create subpicture id's and types for every stream
|
||||
// All used subpicture id's and types will beappended to string, separated by colon
|
||||
// So it's possible to split it later
|
||||
string sub = string.Empty;
|
||||
string subType = string.Empty;
|
||||
if (programChain.Has43Subs)
|
||||
{
|
||||
sub = string.Format("0x{0:x2}", subStream + pos43Subs);
|
||||
subType = "4:3";
|
||||
}
|
||||
if (programChain.HasWideSubs)
|
||||
{
|
||||
if (sub.Length > 0)
|
||||
{
|
||||
sub += ", ";
|
||||
subType += ", ";
|
||||
}
|
||||
sub += string.Format("0x{0:x2}", subStream + posWideSubs);
|
||||
subType += "wide";
|
||||
}
|
||||
if (programChain.HasLetterSubs)
|
||||
{
|
||||
if (sub.Length > 0)
|
||||
{
|
||||
sub += ", ";
|
||||
subType += ", ";
|
||||
}
|
||||
sub += string.Format("0x{0:x2}", subStream + posLetterSubs);
|
||||
subType += "letterboxed";
|
||||
}
|
||||
if (programChain.HasPanSubs)
|
||||
{
|
||||
if (sub.Length > 0)
|
||||
{
|
||||
sub += ", ";
|
||||
subType += ", ";
|
||||
}
|
||||
sub += string.Format("0x{0:x2}", subStream + posPanSubs);
|
||||
subType += "pan&scan";
|
||||
}
|
||||
|
||||
_vtsVobs.SubtitleIDs.Add(sub);
|
||||
_vtsVobs.SubtitleTypes.Add(subType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int TimeToMs(int time)
|
||||
{
|
||||
double fps;
|
||||
|
||||
var temp = IntToBin(time, 32);
|
||||
var result = StrToInt(IntToHex(BinToInt(MidStr(temp, 0, 8)), 1)) * 3600000;
|
||||
result = result + StrToInt(IntToHex(BinToInt(MidStr(temp, 8, 8)), 2)) * 60000;
|
||||
result = result + StrToInt(IntToHex(BinToInt(MidStr(temp, 16, 8)), 2)) * 1000;
|
||||
if (temp.Substring(24, 2) == "11")
|
||||
fps = 30;
|
||||
else
|
||||
fps = 25;
|
||||
result += (int)Math.Round((TimeCode.BaseUnit / fps) * StrToFloat(IntToHex(BinToInt(MidStr(temp, 26, 6)), 3)));
|
||||
return result;
|
||||
}
|
||||
|
||||
private static double StrToFloat(string p)
|
||||
{
|
||||
return Convert.ToDouble(p, System.Globalization.CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
private static int StrToInt(string p)
|
||||
{
|
||||
return int.Parse(p);
|
||||
}
|
||||
|
||||
private static string IntToHex(int value, int digits)
|
||||
{
|
||||
string hex = value.ToString("X");
|
||||
|
||||
return hex.PadLeft(digits, '0');
|
||||
}
|
||||
|
||||
private static string MsToTime(double milliseconds)
|
||||
{
|
||||
var ts = TimeSpan.FromMilliseconds(milliseconds);
|
||||
string s = string.Format("{0:#0}:{1:00}:{2:00}.{3:000}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds);
|
||||
return s;
|
||||
}
|
||||
|
||||
private static string InterpretTime(int timeNumber)
|
||||
{
|
||||
string timeBytes = IntToBin(timeNumber, 32);
|
||||
int h = StrToInt(IntToHex(BinToInt(timeBytes.Substring(0, 8)), 1));
|
||||
int m = StrToInt(IntToHex(BinToInt(timeBytes.Substring(8, 8)), 2));
|
||||
int s = StrToInt(IntToHex(BinToInt(timeBytes.Substring(16, 8)), 2));
|
||||
int fps = 25;
|
||||
if (timeBytes.Substring(24, 2) == "11")
|
||||
fps = 30;
|
||||
int milliseconds = (int)Math.Round((TimeCode.BaseUnit / fps) * StrToFloat(IntToHex(BinToInt(timeBytes.Substring(26, 6)), 3)));
|
||||
var ts = new TimeSpan(0, h, m, s, milliseconds);
|
||||
return MsToTime(ts.TotalMilliseconds);
|
||||
}
|
||||
|
||||
private void ReleaseManagedResources()
|
||||
{
|
||||
if (_fs != null)
|
||||
{
|
||||
_fs.Dispose();
|
||||
_fs = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
ReleaseManagedResources();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
691
libse/ImageSplitter.cs
Normal file
691
libse/ImageSplitter.cs
Normal file
@ -0,0 +1,691 @@
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Drawing;
|
||||
|
||||
//namespace Nikse.SubtitleEdit.Logic
|
||||
//{
|
||||
// public class ImageSplitter
|
||||
// {
|
||||
// public static bool IsColorClose(Color a, Color b, int tolerance)
|
||||
// {
|
||||
// if (a.A < 120 && b.A < 120)
|
||||
// return true; // transparent
|
||||
|
||||
// if (a.A > 250 && a.R > 90 && a.G > 90 && a.B > 90 &&
|
||||
// b.A > 250 && b.R > 90 && b.G > 90 && b.B > 90)
|
||||
// return true; // dark, non transparent
|
||||
|
||||
// int diff = (a.R + a.G + a.B) - (b.R + b.G + b.B);
|
||||
// return diff < tolerance && diff > -tolerance;
|
||||
// }
|
||||
|
||||
// public static Bitmap Copy(Bitmap sourceBitmap, Rectangle section)
|
||||
// {
|
||||
// // Create the new bitmap and associated graphics object
|
||||
// var bmp = new Bitmap(section.Width, section.Height);
|
||||
// Graphics g = Graphics.FromImage(bmp);
|
||||
|
||||
// // Draw the specified section of the source bitmap to the new one
|
||||
// g.DrawImage(sourceBitmap, 0, 0, section, GraphicsUnit.Pixel);
|
||||
|
||||
// // Clean up
|
||||
// g.Dispose();
|
||||
|
||||
// // Return the bitmap
|
||||
// return bmp;
|
||||
// }
|
||||
|
||||
// public static Bitmap CropTopAndBottom(Bitmap bmp, out int topCropping)
|
||||
// {
|
||||
// int startTop = 0;
|
||||
// int maxTop = bmp.Height-2;
|
||||
// if (maxTop > bmp.Height)
|
||||
// maxTop = bmp.Height;
|
||||
// for (int y = 0; y < maxTop; y++)
|
||||
// {
|
||||
// bool allTransparent = true;
|
||||
// for (int x = 1; x < bmp.Width - 1; x++)
|
||||
// {
|
||||
// Color c = bmp.GetPixel(x, y);
|
||||
// if (c.A != 0)
|
||||
// {
|
||||
// allTransparent = false;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (!allTransparent)
|
||||
// break;
|
||||
// startTop++;
|
||||
// }
|
||||
// if (startTop > 9)
|
||||
// startTop -= 5; // if top space > 9, then allways leave blank 5 pixels on top (so . is not confused with ').
|
||||
// topCropping = startTop;
|
||||
|
||||
// for (int y = bmp.Height-1; y > 3; y--)
|
||||
// {
|
||||
// bool allTransparent = true;
|
||||
// for (int x = 1; x < bmp.Width-1; x++)
|
||||
// {
|
||||
// Color c = bmp.GetPixel(x, y);
|
||||
// if (c.A != 0)
|
||||
// {
|
||||
// allTransparent = false;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (allTransparent == false)
|
||||
// return Copy(bmp, new Rectangle(0, startTop, bmp.Width - 1, y-startTop+1));
|
||||
// }
|
||||
// return bmp;
|
||||
// }
|
||||
|
||||
// public static Bitmap CropTopAndBottom(Bitmap bmp, out int topCropping, int maxDifferentPixelsOnLine)
|
||||
// {
|
||||
// int startTop = 0;
|
||||
// int maxTop = bmp.Height - 2;
|
||||
// if (maxTop > bmp.Height)
|
||||
// maxTop = bmp.Height;
|
||||
|
||||
// for (int y = 0; y < maxTop; y++)
|
||||
// {
|
||||
// int difference = 0;
|
||||
// bool allTransparent = true;
|
||||
// for (int x = 1; x < bmp.Width - 1; x++)
|
||||
// {
|
||||
// Color c = bmp.GetPixel(x, y);
|
||||
// if (c.A != 0)
|
||||
// {
|
||||
// difference++;
|
||||
// if (difference >= maxDifferentPixelsOnLine)
|
||||
// {
|
||||
// allTransparent = false;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (!allTransparent)
|
||||
// break;
|
||||
// startTop++;
|
||||
// }
|
||||
// if (startTop > 9)
|
||||
// startTop -= 5; // if top space > 9, then allways leave blank 5 pixels on top (so . is not confused with ').
|
||||
// topCropping = startTop;
|
||||
|
||||
// for (int y = bmp.Height - 1; y > 3; y--)
|
||||
// {
|
||||
// int difference = 0;
|
||||
// bool allTransparent = true;
|
||||
// for (int x = 1; x < bmp.Width - 1; x++)
|
||||
// {
|
||||
// Color c = bmp.GetPixel(x, y);
|
||||
// if (c.A != 0)
|
||||
// {
|
||||
// difference++;
|
||||
// if (difference >= maxDifferentPixelsOnLine)
|
||||
// {
|
||||
// allTransparent = false;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (allTransparent == false)
|
||||
// return Copy(bmp, new Rectangle(0, startTop, bmp.Width - 1, y - startTop + 1));
|
||||
// }
|
||||
// return bmp;
|
||||
// }
|
||||
|
||||
// public static List<ImageSplitterItem> SplitVertical(Bitmap bmp)
|
||||
// { // split into lines
|
||||
// int startY = 0;
|
||||
// int size = 0;
|
||||
// var parts = new List<ImageSplitterItem>();
|
||||
// for (int y = 0; y < bmp.Height; y++)
|
||||
// {
|
||||
// bool allTransparent = true;
|
||||
// for (int x = 0; x < bmp.Width; x++)
|
||||
// {
|
||||
// Color c = bmp.GetPixel(x, y);
|
||||
// if (c.A != 0)
|
||||
// {
|
||||
// allTransparent = false;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (allTransparent)
|
||||
// {
|
||||
// if (size > 2 && size < 6)
|
||||
// {
|
||||
// size++; // at least 5 pixels, like top of 'i'
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (size > 2)
|
||||
// {
|
||||
// Bitmap part = Copy(bmp, new Rectangle(0, startY, bmp.Width, size+1));
|
||||
//// part.Save("c:\\line_0_to_width.bmp");
|
||||
// parts.Add(new ImageSplitterItem(0, startY, part));
|
||||
//// bmp.Save("c:\\original.bmp");
|
||||
// }
|
||||
// size = 0;
|
||||
// startY = y;
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// size++;
|
||||
// }
|
||||
|
||||
// }
|
||||
// if (size > 2)
|
||||
// {
|
||||
// Bitmap part = Copy(bmp, new Rectangle(0, startY, bmp.Width, size+1));
|
||||
// parts.Add(new ImageSplitterItem(0, startY, part));
|
||||
// }
|
||||
// return parts;
|
||||
// }
|
||||
|
||||
// public static List<ImageSplitterItem> SplitVertical(Bitmap bmp, int lineMinHeight)
|
||||
// { // split into lines
|
||||
// int startY = 0;
|
||||
// int size = 0;
|
||||
// var parts = new List<ImageSplitterItem>();
|
||||
// for (int y = 0; y < bmp.Height; y++)
|
||||
// {
|
||||
// bool allTransparent = true;
|
||||
// for (int x = 0; x < bmp.Width; x++)
|
||||
// {
|
||||
// Color c = bmp.GetPixel(x, y);
|
||||
// if (c.A != 0)
|
||||
// {
|
||||
// allTransparent = false;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (allTransparent)
|
||||
// {
|
||||
// if (size > 2 && size <= lineMinHeight)
|
||||
// {
|
||||
// size++; // at least 5 pixels, like top of 'i'
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (size > 2)
|
||||
// {
|
||||
// Bitmap part = Copy(bmp, new Rectangle(0, startY, bmp.Width, size + 1));
|
||||
// // part.Save("c:\\line_0_to_width.bmp");
|
||||
// parts.Add(new ImageSplitterItem(0, startY, part));
|
||||
// // bmp.Save("c:\\original.bmp");
|
||||
// }
|
||||
// size = 0;
|
||||
// startY = y;
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// size++;
|
||||
// }
|
||||
|
||||
// }
|
||||
// if (size > 2)
|
||||
// {
|
||||
// Bitmap part = Copy(bmp, new Rectangle(0, startY, bmp.Width, size + 1));
|
||||
// parts.Add(new ImageSplitterItem(0, startY, part));
|
||||
// }
|
||||
// return parts;
|
||||
// }
|
||||
|
||||
// public static int IsBitmapsAlike(Bitmap bmp1, Bitmap bmp2)
|
||||
// {
|
||||
// int different = 0;
|
||||
// int maxDiff = (int)(bmp1.Width * bmp1.Height / 5.0);
|
||||
|
||||
// for (int x = 1; x < bmp1.Width; x++)
|
||||
// {
|
||||
// for (int y = 1; y < bmp1.Height; y++)
|
||||
// {
|
||||
// if (!IsColorClose(bmp1.GetPixel(x, y), bmp2.GetPixel(x, y), 20))
|
||||
// {
|
||||
// different++;
|
||||
// }
|
||||
// }
|
||||
// if (different > maxDiff)
|
||||
// return different + 10;
|
||||
// }
|
||||
// return different;
|
||||
// }
|
||||
|
||||
// public static int IsBitmapsAlike(FastBitmap bmp1, Bitmap bmp2)
|
||||
// {
|
||||
// int different = 0;
|
||||
|
||||
// for (int x = 1; x < bmp1.Width; x++)
|
||||
// {
|
||||
// for (int y = 1; y < bmp1.Height; y++)
|
||||
// {
|
||||
// Color c1 = bmp1.GetPixel(x, y);
|
||||
// Color c2 = bmp1.GetPixel(x, y);
|
||||
// if (!IsColorClose(c1, c2, 20))
|
||||
// different++;
|
||||
// }
|
||||
// }
|
||||
// return different;
|
||||
// }
|
||||
|
||||
// private static List<ImageSplitterItem> SplitHorizontal(ImageSplitterItem verticalItem, int xOrMorePixelsMakesSpace)
|
||||
// { // split line into letters
|
||||
// Bitmap bmp = verticalItem.NikseBitmap.GetBitmap();
|
||||
// var parts = new List<ImageSplitterItem>();
|
||||
// int size = 0;
|
||||
// int startX = 0;
|
||||
// int lastEndX = 0;
|
||||
// int y = 0;
|
||||
// bool spaceJustAdded = false;
|
||||
|
||||
// for (int x = 0; x < bmp.Width - 1; x++)
|
||||
// {
|
||||
// bool allTransparent = IsVerticalLineTransparent(bmp, ref y, x);
|
||||
|
||||
// // check if line is transparent and cursive
|
||||
// bool cursiveOk = false;
|
||||
// int tempY = 0;
|
||||
// if (allTransparent == false &&
|
||||
// size > 5 &&
|
||||
// y > 3 &&
|
||||
// x < bmp.Width-2 &&
|
||||
// !IsVerticalLineTransparent(bmp, ref tempY, x + 1))
|
||||
// {
|
||||
|
||||
// //Add space?
|
||||
// if (lastEndX > 0 && lastEndX + xOrMorePixelsMakesSpace < startX)
|
||||
// {
|
||||
// int cleanCount = 0;
|
||||
// for (int j = lastEndX; j < startX; j++)
|
||||
// {
|
||||
// int y1 = j;
|
||||
// if (IsVerticalLineTransparent2(bmp, ref y1, j))
|
||||
// cleanCount++;
|
||||
// }
|
||||
// if (cleanCount > 0 && !spaceJustAdded)
|
||||
// {
|
||||
// parts.Add(new ImageSplitterItem(" "));
|
||||
// spaceJustAdded = true;
|
||||
// }
|
||||
// }
|
||||
|
||||
// var cursivePoints = new List<Point>();
|
||||
|
||||
// cursiveOk = IsCursiveVerticalLineTransparent(bmp, size, y, x, cursivePoints);
|
||||
|
||||
// if (cursiveOk)
|
||||
// {
|
||||
// // make letter image
|
||||
// int end = x + 1 - startX;
|
||||
// if (startX > 0)
|
||||
// {
|
||||
// startX--;
|
||||
// end++;
|
||||
// }
|
||||
// Bitmap b1 = Copy(bmp, new Rectangle(startX, 0, end, bmp.Height));
|
||||
//// b1.Save(@"d:\temp\cursive.bmp"); // just for debugging
|
||||
|
||||
// // make non-black/transparent stuff from other letter transparent
|
||||
// foreach (Point p in cursivePoints)
|
||||
// {
|
||||
// for (int fixY = p.Y; fixY < bmp.Height; fixY++)
|
||||
// b1.SetPixel(p.X - startX, fixY, Color.Transparent);
|
||||
// }
|
||||
|
||||
// RemoveBlackBarRight(b1);
|
||||
//// b1.Save(@"d:\temp\cursive-cleaned.bmp"); // just for debugging
|
||||
|
||||
// // crop and save image
|
||||
// int addY;
|
||||
// b1 = CropTopAndBottom(b1, out addY);
|
||||
// parts.Add(new ImageSplitterItem(startX, verticalItem.Y + addY, b1));
|
||||
// spaceJustAdded = false;
|
||||
// size = 0;
|
||||
// startX = x + 1;
|
||||
// lastEndX = x;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (!cursiveOk)
|
||||
// {
|
||||
// if (allTransparent)
|
||||
// {
|
||||
// if (size > 0)
|
||||
// {
|
||||
// if (size > 1)
|
||||
// {
|
||||
// //Add space?
|
||||
// if (lastEndX > 0 && lastEndX + xOrMorePixelsMakesSpace < startX)
|
||||
// {
|
||||
// int cleanCount = 0;
|
||||
// for (int j = lastEndX; j < startX; j++)
|
||||
// {
|
||||
// int y1=j;
|
||||
// if (IsVerticalLineTransparent2(bmp, ref y1, j))
|
||||
// cleanCount++;
|
||||
// }
|
||||
// if (cleanCount > 2 && !spaceJustAdded)
|
||||
// {
|
||||
// parts.Add(new ImageSplitterItem(" "));
|
||||
// spaceJustAdded = true;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (startX > 0)
|
||||
// startX--;
|
||||
// lastEndX = x;
|
||||
// int end = x + 1 - startX;
|
||||
// Bitmap part = Copy(bmp, new Rectangle(startX, 0, end, bmp.Height));
|
||||
// RemoveBlackBarRight(part);
|
||||
// int addY;
|
||||
// // part.Save("c:\\before" + startX.ToString() + ".bmp"); // just for debugging
|
||||
// part = CropTopAndBottom(part, out addY);
|
||||
// // part.Save("c:\\after" + startX.ToString() + ".bmp"); // just for debugging
|
||||
// parts.Add(new ImageSplitterItem(startX, verticalItem.Y + addY, part));
|
||||
// spaceJustAdded = false;
|
||||
//// part.Save(@"d:\temp\cursive.bmp"); // just for debugging
|
||||
// }
|
||||
// size = 0;
|
||||
// }
|
||||
// startX = x + 1;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// size++;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (size > 0)
|
||||
// {
|
||||
// if (lastEndX > 0 && lastEndX + xOrMorePixelsMakesSpace < startX && !spaceJustAdded)
|
||||
// parts.Add(new ImageSplitterItem(" "));
|
||||
|
||||
// if (startX > 0)
|
||||
// startX--;
|
||||
// lastEndX = bmp.Width-1;
|
||||
// int end = lastEndX + 1 - startX;
|
||||
// Bitmap part = Copy(bmp, new Rectangle(startX, 0, end, bmp.Height - 1));
|
||||
// int addY;
|
||||
// part = CropTopAndBottom(part, out addY);
|
||||
// parts.Add(new ImageSplitterItem(startX, verticalItem.Y + addY, part));
|
||||
// //part.Save(@"d:\temp\cursive.bmp"); // just for debugging
|
||||
// }
|
||||
// return parts;
|
||||
// }
|
||||
|
||||
// private static void RemoveBlackBarRight(Bitmap bmp)
|
||||
// {
|
||||
// int xRemoveBlackBar = bmp.Width-1;
|
||||
// for (int yRemoveBlackBar = 0; yRemoveBlackBar < bmp.Height; yRemoveBlackBar++)
|
||||
// {
|
||||
// Color c = bmp.GetPixel(xRemoveBlackBar, yRemoveBlackBar);
|
||||
// if (c.A == 0 || IsColorClose(c, Color.Black, 280))
|
||||
// {
|
||||
// if (bmp.GetPixel(xRemoveBlackBar - 1, yRemoveBlackBar).A == 0)
|
||||
// bmp.SetPixel(xRemoveBlackBar, yRemoveBlackBar, Color.Transparent);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// private static bool IsCursiveVerticalLineTransparent(Bitmap bmp, int size, int y, int x, List<Point> cursivePoints)
|
||||
// {
|
||||
// bool cursiveOk = true;
|
||||
// int newY = y;
|
||||
// int newX = x;
|
||||
// while (cursiveOk && newY < bmp.Height - 1)
|
||||
// {
|
||||
// Color c0 = bmp.GetPixel(newX, newY);
|
||||
// if (c0.A == 0 || IsColorClose(c0, Color.Black, 280))
|
||||
// {
|
||||
// newY++;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Color c1 = bmp.GetPixel(newX - 1, newY - 1);
|
||||
// Color c2 = bmp.GetPixel(newX - 1, newY);
|
||||
// if ((c1.A == 0 || IsColorClose(c1, Color.Black, 280)) && // still dark color...
|
||||
// (c2.A == 0 || IsColorClose(c2, Color.Black, 280)))
|
||||
// {
|
||||
// cursivePoints.Add(new Point(newX, newY));
|
||||
// if (newX > 1)
|
||||
// newX--;
|
||||
// else
|
||||
// cursiveOk = false;
|
||||
|
||||
// newY++;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// cursiveOk = false;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (newX < x - size)
|
||||
// cursiveOk = false;
|
||||
// }
|
||||
// return cursiveOk;
|
||||
// }
|
||||
|
||||
// private static bool IsVerticalLineTransparent(Bitmap bmp, ref int y, int x)
|
||||
// {
|
||||
// bool allTransparent = true;
|
||||
// for (y = 0; y < bmp.Height - 1; y++)
|
||||
// {
|
||||
// Color c = bmp.GetPixel(x, y);
|
||||
// if (c.A == 0 || //c.ToArgb() == transparentColor.ToArgb() ||
|
||||
// IsColorClose(c, Color.Black, 280)) // still dark color...
|
||||
// {
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// allTransparent = false;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// return allTransparent;
|
||||
// }
|
||||
|
||||
// private static bool IsVerticalLineTransparent2(Bitmap bmp, ref int y, int x)
|
||||
// {
|
||||
// bool allTransparent = true;
|
||||
// for (y = 0; y < bmp.Height - 1; y++)
|
||||
// {
|
||||
// Color c = bmp.GetPixel(x, y);
|
||||
// if (c.A == 0) // still dark color...
|
||||
// {
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// allTransparent = false;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// return allTransparent;
|
||||
// }
|
||||
|
||||
// public static List<ImageSplitterItem> SplitBitmapToLetters(Bitmap bmp, int xOrMorePixelsMakesSpace, bool rightToLeft, bool topToBottom)
|
||||
// {
|
||||
// var list = new List<ImageSplitterItem>();
|
||||
|
||||
// // split into seperate lines
|
||||
// List<ImageSplitterItem> verticalBitmaps = SplitVertical(bmp, xOrMorePixelsMakesSpace);
|
||||
|
||||
// if (!topToBottom)
|
||||
// verticalBitmaps.Reverse();
|
||||
|
||||
// // split into letters
|
||||
// int lineCount = 0;
|
||||
// foreach (ImageSplitterItem b in verticalBitmaps)
|
||||
// {
|
||||
// if (lineCount > 0)
|
||||
// list.Add(new ImageSplitterItem(Environment.NewLine));
|
||||
// var line = new List<ImageSplitterItem>();
|
||||
// foreach (ImageSplitterItem item in SplitHorizontal(b, xOrMorePixelsMakesSpace))
|
||||
// {
|
||||
// item.ParentY = item.Y;
|
||||
// line.Add(item);
|
||||
// }
|
||||
// if (rightToLeft)
|
||||
// line.Reverse();
|
||||
// foreach (ImageSplitterItem item in line)
|
||||
// list.Add(item);
|
||||
// lineCount++;
|
||||
// }
|
||||
|
||||
// return list;
|
||||
// }
|
||||
|
||||
// public static List<ImageSplitterItem> SplitBitmapToLetters(List<ImageSplitterItem> verticalBitmaps, int xOrMorePixelsMakesSpace, bool rightToLeft, bool topToBottom)
|
||||
// {
|
||||
// var list = new List<ImageSplitterItem>();
|
||||
// if (!topToBottom)
|
||||
// verticalBitmaps.Reverse();
|
||||
|
||||
// // split into letters
|
||||
// int lineCount = 0;
|
||||
// foreach (ImageSplitterItem b in verticalBitmaps)
|
||||
// {
|
||||
// if (lineCount > 0)
|
||||
// list.Add(new ImageSplitterItem(Environment.NewLine));
|
||||
// var line = new List<ImageSplitterItem>();
|
||||
// foreach (ImageSplitterItem item in SplitHorizontal(b, xOrMorePixelsMakesSpace))
|
||||
// {
|
||||
// item.ParentY = item.Y;
|
||||
// line.Add(item);
|
||||
// }
|
||||
// if (rightToLeft)
|
||||
// line.Reverse();
|
||||
// foreach (ImageSplitterItem item in line)
|
||||
// list.Add(item);
|
||||
// lineCount++;
|
||||
// }
|
||||
|
||||
// return list;
|
||||
// }
|
||||
|
||||
// internal static unsafe int IsBitmapsAlike(NikseBitmap bmp1, NikseBitmap bmp2)
|
||||
// {
|
||||
// int different = 0;
|
||||
// int maxDiff = (int)(bmp1.Width * bmp1.Height / 5.0);
|
||||
|
||||
// for (int x = 1; x < bmp1.Width; x++)
|
||||
// {
|
||||
// for (int y = 1; y < bmp1.Height; y++)
|
||||
// {
|
||||
// if (!IsColorClose(bmp1.GetPixel(x, y), bmp2.GetPixel(x, y), 20))
|
||||
// {
|
||||
// different++;
|
||||
// }
|
||||
// }
|
||||
// if (different > maxDiff)
|
||||
// return different + 10;
|
||||
// }
|
||||
// return different;
|
||||
// }
|
||||
|
||||
// internal static unsafe int IsBitmapsAlike(ManagedBitmap bmp1, NikseBitmap bmp2)
|
||||
// {
|
||||
// int different = 0;
|
||||
// int maxDiff = (int)(bmp1.Width * bmp1.Height / 5.0);
|
||||
|
||||
// for (int x = 1; x < bmp1.Width; x++)
|
||||
// {
|
||||
// for (int y = 1; y < bmp1.Height; y++)
|
||||
// {
|
||||
// if (!IsColorClose(bmp1.GetPixel(x, y), bmp2.GetPixel(x, y), 20))
|
||||
// {
|
||||
// different++;
|
||||
// }
|
||||
// }
|
||||
// if (different > maxDiff)
|
||||
// return different + 10;
|
||||
// }
|
||||
// return different;
|
||||
// }
|
||||
|
||||
// internal static unsafe int IsBitmapsAlike(ManagedBitmap bmp1, Bitmap bmp2)
|
||||
// {
|
||||
// int different = 0;
|
||||
// int maxDiff = (int)(bmp1.Width * bmp1.Height / 5.0);
|
||||
|
||||
// for (int x = 1; x < bmp1.Width; x++)
|
||||
// {
|
||||
// for (int y = 1; y < bmp1.Height; y++)
|
||||
// {
|
||||
// if (!IsColorClose(bmp1.GetPixel(x, y), bmp2.GetPixel(x, y), 20))
|
||||
// {
|
||||
// different++;
|
||||
// }
|
||||
// }
|
||||
// if (different > maxDiff)
|
||||
// return different + 10;
|
||||
// }
|
||||
// return different;
|
||||
// }
|
||||
|
||||
// internal static unsafe int IsBitmapsAlike(NikseBitmap bmp1, ManagedBitmap bmp2)
|
||||
// {
|
||||
// int different = 0;
|
||||
// int maxDiff = (int)(bmp1.Width * bmp1.Height / 5.0);
|
||||
|
||||
// for (int x = 1; x < bmp1.Width; x++)
|
||||
// {
|
||||
// for (int y = 1; y < bmp1.Height; y++)
|
||||
// {
|
||||
// if (!IsColorClose(bmp1.GetPixel(x, y), bmp2.GetPixel(x, y), 20))
|
||||
// {
|
||||
// different++;
|
||||
// }
|
||||
// }
|
||||
// if (different > maxDiff)
|
||||
// return different + 10;
|
||||
// }
|
||||
// return different;
|
||||
// }
|
||||
|
||||
// internal static unsafe int IsBitmapsAlike(Bitmap bmp1, NikseBitmap bmp2)
|
||||
// {
|
||||
// int different = 0;
|
||||
// int maxDiff = (int)(bmp1.Width * bmp1.Height / 5.0);
|
||||
// NikseBitmap nbmp1 = new NikseBitmap(bmp1);
|
||||
|
||||
// for (int x = 1; x < bmp1.Width; x++)
|
||||
// {
|
||||
// for (int y = 1; y < bmp1.Height; y++)
|
||||
// {
|
||||
// if (!IsColorClose(nbmp1.GetPixel(x, y), bmp2.GetPixel(x, y), 20))
|
||||
// {
|
||||
// different++;
|
||||
// }
|
||||
// }
|
||||
// if (different > maxDiff)
|
||||
// return different + 10;
|
||||
// }
|
||||
// return different;
|
||||
// }
|
||||
|
||||
// internal static unsafe int IsBitmapsAlike(NikseBitmap bmp1, Bitmap bmp2)
|
||||
// {
|
||||
// int different = 0;
|
||||
// int maxDiff = (int)(bmp1.Width * bmp1.Height / 5.0);
|
||||
|
||||
// for (int x = 1; x < bmp1.Width; x++)
|
||||
// {
|
||||
// for (int y = 1; y < bmp1.Height; y++)
|
||||
// {
|
||||
// if (!IsColorClose(bmp1.GetPixel(x, y), bmp2.GetPixel(x, y), 20))
|
||||
// {
|
||||
// different++;
|
||||
// }
|
||||
// }
|
||||
// if (different > maxDiff)
|
||||
// return different + 10;
|
||||
// }
|
||||
// return different;
|
||||
// }
|
||||
// }
|
||||
//}
|
27
libse/ImageSplitterItem.cs
Normal file
27
libse/ImageSplitterItem.cs
Normal file
@ -0,0 +1,27 @@
|
||||
namespace Nikse.SubtitleEdit.Core
|
||||
{
|
||||
public class ImageSplitterItem
|
||||
{
|
||||
public int X { get; set; }
|
||||
public int Y { get; set; }
|
||||
public int ParentY { get; set; }
|
||||
public NikseBitmap NikseBitmap { get; set; }
|
||||
public string SpecialCharacter { get; set; }
|
||||
|
||||
public ImageSplitterItem(int x, int y, NikseBitmap bitmap)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
NikseBitmap = bitmap;
|
||||
SpecialCharacter = null;
|
||||
}
|
||||
|
||||
public ImageSplitterItem(string specialCharacter)
|
||||
{
|
||||
X = 0;
|
||||
Y = 0;
|
||||
SpecialCharacter = specialCharacter;
|
||||
NikseBitmap = null;
|
||||
}
|
||||
}
|
||||
}
|
2501
libse/Language.cs
Normal file
2501
libse/Language.cs
Normal file
File diff suppressed because it is too large
Load Diff
5663
libse/LanguageDeserializer.cs
Normal file
5663
libse/LanguageDeserializer.cs
Normal file
File diff suppressed because it is too large
Load Diff
2326
libse/LanguageStructure.cs
Normal file
2326
libse/LanguageStructure.cs
Normal file
File diff suppressed because it is too large
Load Diff
447
libse/LibSE.csproj
Normal file
447
libse/LibSE.csproj
Normal file
@ -0,0 +1,447 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{3E3CB28F-3A7B-430F-9EB3-0D6C1E53B753}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Nikse.SubtitleEdit.Core</RootNamespace>
|
||||
<AssemblyName>libse</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="BluRaySup\BluRaySupPalette.cs" />
|
||||
<Compile Include="BluRaySup\BluRaySupParser.cs" />
|
||||
<Compile Include="BluRaySup\BluRaySupPicture.cs" />
|
||||
<Compile Include="BluRaySup\Core.cs" />
|
||||
<Compile Include="BluRaySup\ImageObject.cs" />
|
||||
<Compile Include="BluRaySup\ImageObjectFragment.cs" />
|
||||
<Compile Include="BluRaySup\PaletteInfo.cs" />
|
||||
<Compile Include="BluRaySup\ToolBox.cs" />
|
||||
<Compile Include="BmpReader.cs" />
|
||||
<Compile Include="Configuration.cs" />
|
||||
<Compile Include="ContainerFormats\AviRiffData.cs" />
|
||||
<Compile Include="ContainerFormats\Ebml\Element.cs" />
|
||||
<Compile Include="ContainerFormats\Ebml\ElementId.cs" />
|
||||
<Compile Include="ContainerFormats\MaterialExchangeFormat\KeyIdentifier.cs" />
|
||||
<Compile Include="ContainerFormats\MaterialExchangeFormat\KlvPacket.cs" />
|
||||
<Compile Include="ContainerFormats\MaterialExchangeFormat\MxfParser.cs" />
|
||||
<Compile Include="ContainerFormats\MaterialExchangeFormat\PartitionStatus.cs" />
|
||||
<Compile Include="ContainerFormats\Matroska\MatroskaFile.cs" />
|
||||
<Compile Include="ContainerFormats\Matroska\MatroskaSubtitle.cs" />
|
||||
<Compile Include="ContainerFormats\Matroska\MatroskaTrackInfo.cs" />
|
||||
<Compile Include="ContainerFormats\Mp4\Boxes\Box.cs" />
|
||||
<Compile Include="ContainerFormats\Mp4\Boxes\Mdhd.cs" />
|
||||
<Compile Include="ContainerFormats\Mp4\Boxes\Mdia.cs" />
|
||||
<Compile Include="ContainerFormats\Mp4\Boxes\Minf.cs" />
|
||||
<Compile Include="ContainerFormats\Mp4\Boxes\Moov.cs" />
|
||||
<Compile Include="ContainerFormats\Mp4\Boxes\Mvhd.cs" />
|
||||
<Compile Include="ContainerFormats\Mp4\Boxes\Stbl.cs" />
|
||||
<Compile Include="ContainerFormats\Mp4\Boxes\Tkhd.cs" />
|
||||
<Compile Include="ContainerFormats\Mp4\Boxes\Trak.cs" />
|
||||
<Compile Include="ContainerFormats\Mp4\Mp4Parser.cs" />
|
||||
<Compile Include="ContainerFormats\RiffDecodeHeader.cs" />
|
||||
<Compile Include="ContainerFormats\RiffParser.cs" />
|
||||
<Compile Include="DetectEncoding\EncodingTools.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\CMLangConvertCharset.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\CMLangConvertCharsetClass.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\CMLangString.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\CMLangStringClass.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\CMultiLanguage.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\CMultiLanguageClass.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\IEnumCodePage.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\IEnumRfc1766.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\IEnumScript.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\IMLangCodePages.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\IMLangConvertCharset.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\IMLangFontLink.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\IMLangFontLink2.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\IMLangLineBreakConsole.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\IMLangString.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\IMLangStringAStr.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\IMLangStringBufA.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\IMLangStringBufW.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\IMLangStringWStr.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\IMultiLanguage.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\IMultiLanguage2.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\IMultiLanguage3.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\ISequentialStream.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\IStream.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\tagDetectEncodingInfo.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\tagMIMECONTF.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\tagMIMECPINFO.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\tagMIMECSETINFO.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\tagMLCPF.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\tagMLDETECTCP.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\tagMLSTR_FLAGS.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\tagRFC1766INFO.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\tagSCRIPFONTINFO.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\tagSCRIPTINFO.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\tagSTATSTG.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\tagUNICODERANGE.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\_FILETIME.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\_LARGE_INTEGER.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\_RemotableHandle.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\_ULARGE_INTEGER.cs" />
|
||||
<Compile Include="DetectEncoding\Multilang\__MIDL_IWinTypes_0009.cs" />
|
||||
<Compile Include="Dictionaries\NamesList.cs" />
|
||||
<Compile Include="Dictionaries\OcrFixReplaceList.cs" />
|
||||
<Compile Include="Enums\FindType.cs" />
|
||||
<Compile Include="Enums\SelectionChoice.cs" />
|
||||
<Compile Include="Enums\SpellCheckAction.cs" />
|
||||
<Compile Include="Enums\SubtitleSortCriteria.cs" />
|
||||
<Compile Include="FastBitmap.cs" />
|
||||
<Compile Include="FastFileStream.cs" />
|
||||
<Compile Include="FileUtil.cs" />
|
||||
<Compile Include="FindReplaceDialogHelper.cs" />
|
||||
<Compile Include="Forms\CheckForUpdatesHelper.cs" />
|
||||
<Compile Include="Forms\FixCommonErrorsHelper.cs" />
|
||||
<Compile Include="Forms\RemoveTextForHI.cs" />
|
||||
<Compile Include="Forms\RemoveTextForHISettings.cs" />
|
||||
<Compile Include="Forms\SplitLongLinesHelper.cs" />
|
||||
<Compile Include="Fourier.cs" />
|
||||
<Compile Include="HistoryItem.cs" />
|
||||
<Compile Include="HtmlUtil.cs" />
|
||||
<Compile Include="IfoParser.cs" />
|
||||
<Compile Include="ImageSplitter.cs" />
|
||||
<Compile Include="ImageSplitterItem.cs" />
|
||||
<Compile Include="Language.cs" />
|
||||
<Compile Include="LanguageDeserializer.cs" />
|
||||
<Compile Include="LanguageStructure.cs" />
|
||||
<Compile Include="ManagedBitmap.cs" />
|
||||
<Compile Include="MurMurHash3.cs" />
|
||||
<Compile Include="NativeMethods.cs" />
|
||||
<Compile Include="NikseBitmap.cs" />
|
||||
<Compile Include="NoBreakAfterItem.cs" />
|
||||
<Compile Include="Paragraph.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="RegistryUtil.cs" />
|
||||
<Compile Include="Settings.cs" />
|
||||
<Compile Include="SpellCheckWord.cs" />
|
||||
<Compile Include="SsaStyle.cs" />
|
||||
<Compile Include="StringExtensions.cs" />
|
||||
<Compile Include="StripableText.cs" />
|
||||
<Compile Include="Subtitle.cs" />
|
||||
<Compile Include="SubtitleFormats\AbcIViewer.cs" />
|
||||
<Compile Include="SubtitleFormats\AdobeAfterEffectsFTME.cs" />
|
||||
<Compile Include="SubtitleFormats\AdobeEncore.cs" />
|
||||
<Compile Include="SubtitleFormats\AdobeEncoreLineTabNewLine.cs" />
|
||||
<Compile Include="SubtitleFormats\AdobeEncoreLineTabs.cs" />
|
||||
<Compile Include="SubtitleFormats\AdobeEncoreTabs.cs" />
|
||||
<Compile Include="SubtitleFormats\AdobeEncoreWithLineNumbers.cs" />
|
||||
<Compile Include="SubtitleFormats\AdobeEncoreWithLineNumbersNtsc.cs" />
|
||||
<Compile Include="SubtitleFormats\AdvancedSubStationAlpha.cs" />
|
||||
<Compile Include="SubtitleFormats\AQTitle.cs" />
|
||||
<Compile Include="SubtitleFormats\AvidCaption.cs" />
|
||||
<Compile Include="SubtitleFormats\AvidDvd.cs" />
|
||||
<Compile Include="SubtitleFormats\AvidStl.cs" />
|
||||
<Compile Include="SubtitleFormats\Ayato.cs" />
|
||||
<Compile Include="SubtitleFormats\BdnXml.cs" />
|
||||
<Compile Include="SubtitleFormats\BelleNuitSubtitler.cs" />
|
||||
<Compile Include="SubtitleFormats\CapMakerPlus.cs" />
|
||||
<Compile Include="SubtitleFormats\CaptionAssistant.cs" />
|
||||
<Compile Include="SubtitleFormats\Captionate.cs" />
|
||||
<Compile Include="SubtitleFormats\CaptionateMs.cs" />
|
||||
<Compile Include="SubtitleFormats\CaptionsInc.cs" />
|
||||
<Compile Include="SubtitleFormats\CaraokeXml.cs" />
|
||||
<Compile Include="SubtitleFormats\Cavena890.cs" />
|
||||
<Compile Include="SubtitleFormats\CheetahCaption.cs" />
|
||||
<Compile Include="SubtitleFormats\Chk.cs" />
|
||||
<Compile Include="SubtitleFormats\Csv.cs" />
|
||||
<Compile Include="SubtitleFormats\Csv2.cs" />
|
||||
<Compile Include="SubtitleFormats\Csv3.cs" />
|
||||
<Compile Include="SubtitleFormats\DCinemaSmpte2007.cs" />
|
||||
<Compile Include="SubtitleFormats\DCinemaSmpte2010.cs" />
|
||||
<Compile Include="SubtitleFormats\DCSubtitle.cs" />
|
||||
<Compile Include="SubtitleFormats\DigiBeta.cs" />
|
||||
<Compile Include="SubtitleFormats\Dost.cs" />
|
||||
<Compile Include="SubtitleFormats\DvdStudioPro.cs" />
|
||||
<Compile Include="SubtitleFormats\DvdStudioProSpace.cs" />
|
||||
<Compile Include="SubtitleFormats\DvdStudioProSpaceOne.cs" />
|
||||
<Compile Include="SubtitleFormats\DvdSubtitle.cs" />
|
||||
<Compile Include="SubtitleFormats\DvdSubtitleSystem.cs" />
|
||||
<Compile Include="SubtitleFormats\Ebu.cs" />
|
||||
<Compile Include="SubtitleFormats\Eeg708.cs" />
|
||||
<Compile Include="SubtitleFormats\ELRStudioClosedCaption.cs" />
|
||||
<Compile Include="SubtitleFormats\F4Rtf.cs" />
|
||||
<Compile Include="SubtitleFormats\F4Text.cs" />
|
||||
<Compile Include="SubtitleFormats\F4Xml.cs" />
|
||||
<Compile Include="SubtitleFormats\FabSubtitler.cs" />
|
||||
<Compile Include="SubtitleFormats\FilmEditXml.cs" />
|
||||
<Compile Include="SubtitleFormats\FinalCutProImage.cs" />
|
||||
<Compile Include="SubtitleFormats\FinalCutProTest2Xml.cs" />
|
||||
<Compile Include="SubtitleFormats\FinalCutProTextXml.cs" />
|
||||
<Compile Include="SubtitleFormats\FinalCutProXCM.cs" />
|
||||
<Compile Include="SubtitleFormats\FinalCutProXml.cs" />
|
||||
<Compile Include="SubtitleFormats\FinalCutProXml13.cs" />
|
||||
<Compile Include="SubtitleFormats\FinalCutProXml14.cs" />
|
||||
<Compile Include="SubtitleFormats\FinalCutProXml14Text.cs" />
|
||||
<Compile Include="SubtitleFormats\FinalCutProXmlGap.cs" />
|
||||
<Compile Include="SubtitleFormats\FinalCutProXXml.cs" />
|
||||
<Compile Include="SubtitleFormats\FlashXml.cs" />
|
||||
<Compile Include="SubtitleFormats\FLVCoreCuePoints.cs" />
|
||||
<Compile Include="SubtitleFormats\Footage.cs" />
|
||||
<Compile Include="SubtitleFormats\GpacTtxt.cs" />
|
||||
<Compile Include="SubtitleFormats\HtmlSamiArray.cs" />
|
||||
<Compile Include="SubtitleFormats\Idx.cs" />
|
||||
<Compile Include="SubtitleFormats\ImageLogicAutocaption.cs" />
|
||||
<Compile Include="SubtitleFormats\IssXml.cs" />
|
||||
<Compile Include="SubtitleFormats\ItunesTimedText.cs" />
|
||||
<Compile Include="SubtitleFormats\Json.cs" />
|
||||
<Compile Include="SubtitleFormats\JsonType2.cs" />
|
||||
<Compile Include="SubtitleFormats\JsonType3.cs" />
|
||||
<Compile Include="SubtitleFormats\JsonType4.cs" />
|
||||
<Compile Include="SubtitleFormats\JsonType5.cs" />
|
||||
<Compile Include="SubtitleFormats\JsonType6.cs" />
|
||||
<Compile Include="SubtitleFormats\Lrc.cs" />
|
||||
<Compile Include="SubtitleFormats\MacCaption.cs" />
|
||||
<Compile Include="SubtitleFormats\MicroDvd.cs" />
|
||||
<Compile Include="SubtitleFormats\MidwayInscriberCGX.cs" />
|
||||
<Compile Include="SubtitleFormats\MPlayer2.cs" />
|
||||
<Compile Include="SubtitleFormats\NciCaption.cs" />
|
||||
<Compile Include="SubtitleFormats\NciTimedRollUpCaptions.cs" />
|
||||
<Compile Include="SubtitleFormats\OpenDvt.cs" />
|
||||
<Compile Include="SubtitleFormats\Oresme.cs" />
|
||||
<Compile Include="SubtitleFormats\OresmeDocXDocument.cs" />
|
||||
<Compile Include="SubtitleFormats\Pac.cs" />
|
||||
<Compile Include="SubtitleFormats\PacUnicode.cs" />
|
||||
<Compile Include="SubtitleFormats\PE2.cs" />
|
||||
<Compile Include="SubtitleFormats\PinnacleImpression.cs" />
|
||||
<Compile Include="SubtitleFormats\PListCaption.cs" />
|
||||
<Compile Include="SubtitleFormats\Pns.cs" />
|
||||
<Compile Include="SubtitleFormats\QubeMasterImport.cs" />
|
||||
<Compile Include="SubtitleFormats\QuickTimeText.cs" />
|
||||
<Compile Include="SubtitleFormats\RealTime.cs" />
|
||||
<Compile Include="SubtitleFormats\RhozetHarmonic.cs" />
|
||||
<Compile Include="SubtitleFormats\Sami.cs" />
|
||||
<Compile Include="SubtitleFormats\SamiModern.cs" />
|
||||
<Compile Include="SubtitleFormats\SamiYouTube.cs" />
|
||||
<Compile Include="SubtitleFormats\SatBoxPng.cs" />
|
||||
<Compile Include="SubtitleFormats\Scenarist.cs" />
|
||||
<Compile Include="SubtitleFormats\ScenaristClosedCaptions.cs" />
|
||||
<Compile Include="SubtitleFormats\ScenaristClosedCaptionsDropFrame.cs" />
|
||||
<Compile Include="SubtitleFormats\SmilTimesheetData.cs" />
|
||||
<Compile Include="SubtitleFormats\SoftNiColonSub.cs" />
|
||||
<Compile Include="SubtitleFormats\SoftNiSub.cs" />
|
||||
<Compile Include="SubtitleFormats\Son.cs" />
|
||||
<Compile Include="SubtitleFormats\SonicScenaristBitmaps.cs" />
|
||||
<Compile Include="SubtitleFormats\SonyDVDArchitect.cs" />
|
||||
<Compile Include="SubtitleFormats\SonyDVDArchitectExplicitDuration.cs" />
|
||||
<Compile Include="SubtitleFormats\SonyDVDArchitectLineAndDuration.cs" />
|
||||
<Compile Include="SubtitleFormats\SonyDVDArchitectTabs.cs" />
|
||||
<Compile Include="SubtitleFormats\SonyDVDArchitectWithLineNumbers.cs" />
|
||||
<Compile Include="SubtitleFormats\Spruce.cs" />
|
||||
<Compile Include="SubtitleFormats\SpruceWithSpace.cs" />
|
||||
<Compile Include="SubtitleFormats\Spt.cs" />
|
||||
<Compile Include="SubtitleFormats\StructuredTitles.cs" />
|
||||
<Compile Include="SubtitleFormats\SubRip.cs" />
|
||||
<Compile Include="SubtitleFormats\SubStationAlpha.cs" />
|
||||
<Compile Include="SubtitleFormats\SubtitleEditorProject.cs" />
|
||||
<Compile Include="SubtitleFormats\SubtitleFormat.cs" />
|
||||
<Compile Include="SubtitleFormats\SubViewer10.cs" />
|
||||
<Compile Include="SubtitleFormats\SubViewer20.cs" />
|
||||
<Compile Include="SubtitleFormats\SwiftInterchange2.cs" />
|
||||
<Compile Include="SubtitleFormats\SwiftText.cs" />
|
||||
<Compile Include="SubtitleFormats\SwiftTextLineNoAndDur.cs" />
|
||||
<Compile Include="SubtitleFormats\SwiftTextLineNumber.cs" />
|
||||
<Compile Include="SubtitleFormats\Tek.cs" />
|
||||
<Compile Include="SubtitleFormats\TextST.cs" />
|
||||
<Compile Include="SubtitleFormats\TimedText.cs" />
|
||||
<Compile Include="SubtitleFormats\TimedText10.cs" />
|
||||
<Compile Include="SubtitleFormats\TimedText200604.cs" />
|
||||
<Compile Include="SubtitleFormats\TimedText200604CData.cs" />
|
||||
<Compile Include="SubtitleFormats\TimelineAscii.cs" />
|
||||
<Compile Include="SubtitleFormats\TimelineFootageAscii.cs" />
|
||||
<Compile Include="SubtitleFormats\TimelineMvt.cs" />
|
||||
<Compile Include="SubtitleFormats\TimeXml.cs" />
|
||||
<Compile Include="SubtitleFormats\TimeXml2.cs" />
|
||||
<Compile Include="SubtitleFormats\TitleExchangePro.cs" />
|
||||
<Compile Include="SubtitleFormats\Titra.cs" />
|
||||
<Compile Include="SubtitleFormats\TmpegEncAW5.cs" />
|
||||
<Compile Include="SubtitleFormats\TmpegEncText.cs" />
|
||||
<Compile Include="SubtitleFormats\TmpegEncXml.cs" />
|
||||
<Compile Include="SubtitleFormats\TMPlayer.cs" />
|
||||
<Compile Include="SubtitleFormats\Tmx14.cs" />
|
||||
<Compile Include="SubtitleFormats\TranscriberXml.cs" />
|
||||
<Compile Include="SubtitleFormats\TSB4.cs" />
|
||||
<Compile Include="SubtitleFormats\TurboTitler.cs" />
|
||||
<Compile Include="SubtitleFormats\UleadSubtitleFormat.cs" />
|
||||
<Compile Include="SubtitleFormats\Ultech130.cs" />
|
||||
<Compile Include="SubtitleFormats\UniversalSubtitleFormat.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle1.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle10.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle11.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle12.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle13.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle14.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle15.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle16.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle17.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle18.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle19.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle2.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle20.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle21.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle22.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle23.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle24.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle25.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle26.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle27.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle28.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle29.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle3.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle30.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle31.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle32.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle33.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle34.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle35.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle36.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle37.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle38.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle39.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle4.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle40.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle41.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle42.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle43.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle44.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle45.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle46.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle47.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle48.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle49.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle5.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle50.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle51.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle52.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle53.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle54.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle55.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle56.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle57.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle58.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle59.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle6.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle60.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle61.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle62.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle63.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle64.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle65.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle66.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle67.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle68.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle69.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle7.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle70.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle71.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle72.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle73.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle74.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle75.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle76.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle77.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle78.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle8.cs" />
|
||||
<Compile Include="SubtitleFormats\UnknownSubtitle9.cs" />
|
||||
<Compile Include="SubtitleFormats\UTSubtitleXml.cs" />
|
||||
<Compile Include="SubtitleFormats\Utx.cs" />
|
||||
<Compile Include="SubtitleFormats\UtxFrames.cs" />
|
||||
<Compile Include="SubtitleFormats\VocapiaSplit.cs" />
|
||||
<Compile Include="SubtitleFormats\WebVTT.cs" />
|
||||
<Compile Include="SubtitleFormats\WebVTTFileWithLineNumber.cs" />
|
||||
<Compile Include="SubtitleFormats\Wsb.cs" />
|
||||
<Compile Include="SubtitleFormats\Xif.cs" />
|
||||
<Compile Include="SubtitleFormats\YouTubeAnnotations.cs" />
|
||||
<Compile Include="SubtitleFormats\YouTubeSbv.cs" />
|
||||
<Compile Include="SubtitleFormats\YouTubeTranscript.cs" />
|
||||
<Compile Include="SubtitleFormats\YouTubeTranscriptOneLine.cs" />
|
||||
<Compile Include="SubtitleFormats\ZeroG.cs" />
|
||||
<Compile Include="TarHeader.cs" />
|
||||
<Compile Include="TarReader.cs" />
|
||||
<Compile Include="TaskbarList.cs" />
|
||||
<Compile Include="TextDraw.cs" />
|
||||
<Compile Include="TimeCode.cs" />
|
||||
<Compile Include="TransportStream\AdaptationField.cs" />
|
||||
<Compile Include="TransportStream\ClutDefinitionSegment.cs" />
|
||||
<Compile Include="TransportStream\DisplayDefinitionSegment.cs" />
|
||||
<Compile Include="TransportStream\DvbSubPes.cs" />
|
||||
<Compile Include="TransportStream\EbuPesDataField.cs" />
|
||||
<Compile Include="TransportStream\EbuPesDataFieldText.cs" />
|
||||
<Compile Include="TransportStream\Helper.cs" />
|
||||
<Compile Include="TransportStream\HummingDecoder.cs" />
|
||||
<Compile Include="TransportStream\ObjectDataSegment.cs" />
|
||||
<Compile Include="TransportStream\Packet.cs" />
|
||||
<Compile Include="TransportStream\PacketizedElementaryStream.cs" />
|
||||
<Compile Include="TransportStream\PageCompositionSegemnt.cs" />
|
||||
<Compile Include="TransportStream\PageCompositionSegmentRegion.cs" />
|
||||
<Compile Include="TransportStream\ProgramAssociationTable.cs" />
|
||||
<Compile Include="TransportStream\RegionClutSegmentEntry.cs" />
|
||||
<Compile Include="TransportStream\RegionCompositionSegment.cs" />
|
||||
<Compile Include="TransportStream\RegionCompositionSegmentObject.cs" />
|
||||
<Compile Include="TransportStream\SubtitleSegment.cs" />
|
||||
<Compile Include="TransportStream\TransportStreamParser.cs" />
|
||||
<Compile Include="TransportStream\TransportStreamSubtitle.cs" />
|
||||
<Compile Include="UknownFormatImporter.cs" />
|
||||
<Compile Include="Utilities.cs" />
|
||||
<Compile Include="VideoInfo.cs" />
|
||||
<Compile Include="VobSub\Helper.cs" />
|
||||
<Compile Include="VobSub\Idx.cs" />
|
||||
<Compile Include="VobSub\IdxParagraph.cs" />
|
||||
<Compile Include="VobSub\Mpeg2Header.cs" />
|
||||
<Compile Include="VobSub\PacketizedElementaryStream.cs" />
|
||||
<Compile Include="VobSub\SpHeader.cs" />
|
||||
<Compile Include="VobSub\SubPicture.cs" />
|
||||
<Compile Include="VobSub\VobSubMergedPack.cs" />
|
||||
<Compile Include="VobSub\VobSubPack.cs" />
|
||||
<Compile Include="VobSub\VobSubParser.cs" />
|
||||
<Compile Include="VobSub\VobSubWriter.cs" />
|
||||
<Compile Include="Wave.cs" />
|
||||
<Compile Include="WaveToVisualizer.cs" />
|
||||
<Compile Include="XmlDeserializerGenerator.cs" />
|
||||
<Compile Include="XSub.cs" />
|
||||
<Compile Include="ZipExtractor.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user