Ensure consistent reads and writes

This commit is contained in:
Matt Nadareski
2022-06-16 13:07:41 -07:00
parent 76e52292a8
commit c027b1798a
14 changed files with 687 additions and 434 deletions

View File

@@ -21,6 +21,7 @@
using System;
using System.IO;
using static LibGSF.GsfUtils;
namespace LibGSF
{
@@ -173,7 +174,7 @@ namespace LibGSF
byte[] data = DataBlob.Data;
uint value = BitConverter.ToUInt32(data, 0);
uint value = GSF_LE_GET_GUINT32(data, 0);
switch (value)
{

View File

@@ -27,6 +27,7 @@ using System.Text;
using LibGSF.Input;
using LibGSF.Output;
using static LibGSF.GsfMSOleUtils;
using static LibGSF.GsfUtils;
namespace LibGSF
{
@@ -195,11 +196,11 @@ namespace LibGSF
* 08 - 23 Class Identifier Usually Format ID
* 24 - 27 Section count Should be at least 1
*/
ushort os = BitConverter.ToUInt16(data, 6);
ushort version = BitConverter.ToUInt16(data, 2);
ushort os = GSF_LE_GET_GUINT16(data, 6);
ushort version = GSF_LE_GET_GUINT16(data, 2);
uint num_sections = BitConverter.ToUInt32(data, 24);
if (BitConverter.ToUInt16(data, 0) != 0xfffe
if (GSF_LE_GET_GUINT16(data, 0) != 0xfffe
|| (version != 0 && version != 1)
|| os > 2
|| num_sections > input.Size / 20
@@ -408,7 +409,7 @@ namespace LibGSF
/// <summary></summary>
/// <param name="doc_not_component">A kludge to differentiate DocumentSummary from Summary</param>
/// <returns>true on success</returns>
/// <returns>True on success</returns>
/// <remarks>Since: 1.14.24</remarks>
public bool WriteToMSOLE(GsfOutput output, bool doc_not_component)
{
@@ -466,7 +467,7 @@ namespace LibGSF
state.CharSize = CodePageCharSize(state.CodePage);
// Write stream header
buf = BitConverter.GetBytes((uint)(state.Dict != null ? 2 : 1));
GSF_LE_SET_GUINT32(buf, 0, (uint)(state.Dict != null ? 2 : 1));
if (!output.Write(header.Length, header) || !output.Write(4, buf))
{
state.IConvHandle = null;
@@ -477,7 +478,7 @@ namespace LibGSF
}
// Write section header(s)
buf = BitConverter.GetBytes((uint)(state.Dict != null ? 0x44 : 0x30));
GSF_LE_SET_GUINT32(buf, 0, (uint)(state.Dict != null ? 0x44 : 0x30));
if (!output.Write(16, doc_not_component ? DocumentGUID : ComponentGUID) || !output.Write(4, buf))
{
state.IConvHandle = null;
@@ -489,7 +490,7 @@ namespace LibGSF
if (state.Dict != null)
{
buf = BitConverter.GetBytes((uint)0);
GSF_LE_SET_GUINT32(buf, 0, 0);
if (!output.Write(UserGUID.Length, UserGUID) || !output.Write(4, buf)) // Bogus position, fix it later
{
state.IConvHandle = null;
@@ -513,7 +514,7 @@ namespace LibGSF
if (state.Dict != null)
{
long baseOffset = state.Output.CurrentOffset;
buf = BitConverter.GetBytes((uint)baseOffset);
GSF_LE_SET_GUINT32(buf, 0, (uint)baseOffset);
if (!state.Output.Seek(0x40, SeekOrigin.Begin)
|| !output.Write(4, buf)
|| !state.Output.Seek(0, SeekOrigin.End)

View File

@@ -28,6 +28,7 @@ using System.Text;
using LibGSF.Input;
using LibGSF.Output;
using static LibGSF.GsfMetaNames;
using static LibGSF.GsfUtils;
namespace LibGSF
{
@@ -784,7 +785,7 @@ namespace LibGSF
if (!NEED_RECS(4, 1, dataPtr, data_end, ref bytes_needed))
return null;
uint n = BitConverter.ToUInt32(data, dataPtr);
uint n = GSF_LE_GET_GUINT32(data, dataPtr);
dataPtr += bytes_needed;
int size1 = PropMinSize(type);
@@ -826,7 +827,7 @@ namespace LibGSF
if (!NEED_RECS(2, 1, dataPtr, data_end, ref bytes_needed))
return null;
res = BitConverter.ToInt16(data, dataPtr);
res = GSF_LE_GET_GINT16(data, dataPtr);
dataPtr += bytes_needed;
break;
@@ -835,7 +836,7 @@ namespace LibGSF
if (!NEED_RECS(4, 1, dataPtr, data_end, ref bytes_needed))
return null;
res = BitConverter.ToInt32(data, dataPtr);
res = GSF_LE_GET_GINT32(data, dataPtr);
dataPtr += bytes_needed;
break;
@@ -844,7 +845,7 @@ namespace LibGSF
if (!NEED_RECS(4, 1, dataPtr, data_end, ref bytes_needed))
return null;
res = BitConverter.ToSingle(data, dataPtr);
res = GSF_LE_GET_FLOAT(data, dataPtr);
dataPtr += bytes_needed;
break;
@@ -853,7 +854,7 @@ namespace LibGSF
if (!NEED_RECS(8, 1, dataPtr, data_end, ref bytes_needed))
return null;
res = BitConverter.ToDouble(data, dataPtr);
res = GSF_LE_GET_DOUBLE(data, dataPtr);
dataPtr += bytes_needed;
break;
@@ -863,7 +864,7 @@ namespace LibGSF
return null;
// CHEAT : just store as an int64 for now
res = BitConverter.ToInt64(data, dataPtr);
res = GSF_LE_GET_GINT64(data, dataPtr);
break;
// 64-bit floating-point number representing the number of days
@@ -905,7 +906,7 @@ namespace LibGSF
return null;
res = null;
type = (GsfMSOLEVariantType)BitConverter.ToUInt32(data, dataPtr);
type = (GsfMSOLEVariantType)GSF_LE_GET_GUINT32(data, dataPtr);
dataPtr += bytes_needed;
return PropertyParse(type, data, ref dataPtr, data_end);
@@ -914,7 +915,7 @@ namespace LibGSF
if (!NEED_RECS(1, 1, dataPtr, data_end, ref bytes_needed))
return null;
res = data[dataPtr];
res = GSF_LE_GET_GUINT8(data, dataPtr);
dataPtr += bytes_needed;
break;
@@ -923,7 +924,7 @@ namespace LibGSF
if (!NEED_RECS(1, 1, dataPtr, data_end, ref bytes_needed))
return null;
res = (sbyte)data[dataPtr];
res = GSF_LE_GET_GINT8(data, dataPtr);
dataPtr += bytes_needed;
break;
@@ -932,7 +933,7 @@ namespace LibGSF
if (!NEED_RECS(2, 1, dataPtr, data_end, ref bytes_needed))
return null;
res = BitConverter.ToUInt16(data, dataPtr);
res = GSF_LE_GET_GUINT16(data, dataPtr);
dataPtr += bytes_needed;
break;
@@ -941,7 +942,7 @@ namespace LibGSF
if (!NEED_RECS(4, 1, dataPtr, data_end, ref bytes_needed))
return null;
res = BitConverter.ToUInt32(data, dataPtr);
res = GSF_LE_GET_GUINT32(data, dataPtr);
dataPtr += bytes_needed;
break;
@@ -950,7 +951,7 @@ namespace LibGSF
if (!NEED_RECS(8, 1, dataPtr, data_end, ref bytes_needed))
return null;
res = BitConverter.ToInt64(data, dataPtr);
res = GSF_LE_GET_GINT64(data, dataPtr);
dataPtr += bytes_needed;
break;
@@ -959,7 +960,7 @@ namespace LibGSF
if (!NEED_RECS(8, 1, dataPtr, data_end, ref bytes_needed))
return null;
res = BitConverter.ToUInt64(data, dataPtr);
res = GSF_LE_GET_GUINT64(data, dataPtr);
dataPtr += bytes_needed;
break;
@@ -972,7 +973,7 @@ namespace LibGSF
if (!NEED_RECS(4, 1, dataPtr, data_end, ref bytes_needed))
return null;
len = BitConverter.ToUInt32(data, dataPtr);
len = GSF_LE_GET_GUINT32(data, dataPtr);
dataPtr += bytes_needed;
if (len >= 0x10000)
@@ -1024,7 +1025,7 @@ namespace LibGSF
if (!NEED_RECS(4, 1, dataPtr, data_end, ref bytes_needed))
return null;
len = BitConverter.ToUInt32(data, dataPtr);
len = GSF_LE_GET_GUINT32(data, dataPtr);
dataPtr += bytes_needed;
if (!NEED_RECS(len, 2, dataPtr, data_end, ref bytes_needed))
@@ -1070,7 +1071,7 @@ namespace LibGSF
return null;
// ft * 100ns since Jan 1 1601
ulong ft = BitConverter.ToUInt64(data, dataPtr);
ulong ft = GSF_LE_GET_GUINT64(data, dataPtr);
res = DateTime.FromFileTime((long)ft);
dataPtr += bytes_needed;
break;
@@ -1206,7 +1207,7 @@ namespace LibGSF
}
int dataPtr = 0; // data[0]
GsfMSOLEVariantType type = (GsfMSOLEVariantType)BitConverter.ToUInt32(data, dataPtr);
GsfMSOLEVariantType type = (GsfMSOLEVariantType)GSF_LE_GET_GUINT32(data, dataPtr);
dataPtr += 4;
// Dictionary is magic
@@ -1228,8 +1229,8 @@ namespace LibGSF
if (end - dataPtr < 8)
return false;
id = BitConverter.ToUInt32(data, dataPtr);
len = BitConverter.ToUInt32(data, dataPtr + 4);
id = GSF_LE_GET_GUINT32(data, dataPtr);
len = GSF_LE_GET_GUINT32(data, dataPtr + 4);
if (len >= 0x10000)
return false;
@@ -1341,7 +1342,7 @@ namespace LibGSF
return false;
}
uint clip_size = BitConverter.ToUInt32(data, dataPtr);
uint clip_size = GSF_LE_GET_GUINT32(data, dataPtr);
if (clip_size < 4)
{
@@ -1360,7 +1361,7 @@ namespace LibGSF
return false;
}
GsfClipFormat clip_format = (GsfClipFormat)BitConverter.ToInt32(data, dataPtr);
GsfClipFormat clip_format = (GsfClipFormat)GSF_LE_GET_GINT32(data, dataPtr);
dataPtr += 4;
switch (clip_format)
@@ -1631,7 +1632,8 @@ namespace LibGSF
long baseOffset = Output.CurrentOffset;
// Skip past the size+count and id/offset pairs
byte[] buf = BitConverter.GetBytes((uint)0);
byte[] buf = new byte[8];
GSF_LE_SET_GUINT32(buf, 0, 0);
for (int j = 0; j < 1 + 1 + 2 * count; j++)
{
Output.Write(4, buf);
@@ -1647,9 +1649,9 @@ namespace LibGSF
{
offsets[0].Id = 1;
offsets[0].Offset = Output.CurrentOffset;
buf = BitConverter.GetBytes((uint)GsfMSOLEVariantType.VT_I2);
byte[] buf2 = BitConverter.GetBytes(CodePage);
Output.Write(4, buf); Output.Write(4, buf2);
GSF_LE_SET_GUINT32(buf, 0, (uint)GsfMSOLEVariantType.VT_I2);
GSF_LE_SET_GUINT32(buf, 4, (uint)CodePage);
Output.Write(8, buf);
i++;
}
@@ -1658,7 +1660,7 @@ namespace LibGSF
{
offsets[1].Id = 0;
offsets[1].Offset = Output.CurrentOffset;
buf = BitConverter.GetBytes((uint)Dict.Count);
GSF_LE_SET_GUINT32(buf, 4, (uint)Dict.Count);
Output.Write(4, buf);
foreach (var kvp in Dict)
{
@@ -1722,17 +1724,15 @@ namespace LibGSF
long len = Output.CurrentOffset - baseOffset;
Output.Seek(baseOffset, SeekOrigin.Begin);
buf = BitConverter.GetBytes(len);
Output.Write(4, buf);
buf = BitConverter.GetBytes(count);
Output.Write(4, buf);
GSF_LE_SET_GUINT32(buf, 0, (uint)len);
GSF_LE_SET_GUINT32(buf, 0, count);
Output.Write(8, buf);
for (i = 0; i < count; i++)
{
buf = BitConverter.GetBytes(offsets[i].Id);
Output.Write(4, buf);
buf = BitConverter.GetBytes(offsets[i].Offset - baseOffset);
Output.Write(4, buf);
GSF_LE_SET_GUINT32(buf, 0, offsets[i].Id);
GSF_LE_SET_GUINT32(buf, 0, (uint)(offsets[i].Offset - baseOffset));
Output.Write(8, buf);
}
return Output.Seek(0, SeekOrigin.End);
@@ -1860,7 +1860,10 @@ namespace LibGSF
private void WriteDictionaryEntry(string name, uint id)
{
byte[] buf = BitConverter.GetBytes(id);
byte[] buf = new byte[4];
// TODO: `id` is a pointer not a value
GSF_LE_SET_GUINT32(buf, 0, id);
Output.Write(4, buf);
WriteString(name);
}
@@ -1877,7 +1880,7 @@ namespace LibGSF
GsfMSOLEVariantType type = ValueToMSOLEVariant(value, map);
if (!suppress_type)
{
buf = BitConverter.GetBytes((uint)type);
GSF_LE_SET_GUINT32(buf, 0, (uint)type);
Output.Write(4, buf);
}
@@ -1887,7 +1890,7 @@ namespace LibGSF
int n = vector.Length;
bool res;
buf = BitConverter.GetBytes(n);
GSF_LE_SET_GINT32(buf, 0, n);
res = Output.Write(4, buf);
for (int i = 0; i < n; i++)
{
@@ -1902,36 +1905,36 @@ namespace LibGSF
{
case GsfMSOLEVariantType.VT_BOOL:
if ((bool)value)
buf = BitConverter.GetBytes(0xffffffff);
GSF_LE_SET_GUINT32(buf, 0, 0xffffffff);
else
buf = BitConverter.GetBytes(0);
GSF_LE_SET_GINT32(buf, 0, 0);
return Output.Write(4, buf);
case GsfMSOLEVariantType.VT_UI1:
buf = BitConverter.GetBytes((int)(byte)value);
GSF_LE_SET_GUINT32(buf, 0, (uint)value);
return Output.Write(4, buf);
case GsfMSOLEVariantType.VT_I2:
buf = BitConverter.GetBytes((short)value);
byte[] buf2 = BitConverter.GetBytes((short)0);
return Output.Write(2, buf) && Output.Write(2, buf2);
GSF_LE_SET_GINT16(buf, 0, (short)value);
GSF_LE_SET_GUINT16(buf, 2, 0);
return Output.Write(4, buf);
case GsfMSOLEVariantType.VT_I4:
buf = BitConverter.GetBytes((int)value);
GSF_LE_SET_GINT32(buf, 0, (int)value);
return Output.Write(4, buf);
case GsfMSOLEVariantType.VT_UI2:
case GsfMSOLEVariantType.VT_UI4:
buf = BitConverter.GetBytes((uint)value);
GSF_LE_SET_GUINT32(buf, 0, (uint)value);
return Output.Write(4, buf);
case GsfMSOLEVariantType.VT_R4:
buf = BitConverter.GetBytes((float)value);
GSF_LE_SET_FLOAT(buf, 0, (float)value);
return Output.Write(4, buf);
case GsfMSOLEVariantType.VT_R8:
buf = BitConverter.GetBytes((double)value);
GSF_LE_SET_DOUBLE(buf, 0, (double)value);
return Output.Write(8, buf);
case GsfMSOLEVariantType.VT_LPSTR:
@@ -1940,8 +1943,7 @@ namespace LibGSF
case GsfMSOLEVariantType.VT_FILETIME:
{
DateTime ts = (DateTime)value;
ulong ft = (ulong)ts.ToFileTime();
buf = BitConverter.GetBytes(ft);
GSF_LE_SET_GUINT64(buf, 0, (ulong)ts.ToFileTime());
return Output.Write(8, buf);
}
@@ -1985,13 +1987,13 @@ namespace LibGSF
}
// *Bytes*, not characters, including the termination, but not the padding.
buf = BitConverter.GetBytes(bytes_written + CharSize);
GSF_LE_SET_GUINT32(buf, 0, (uint)(bytes_written + CharSize));
res = Output.Write(4, buf);
res = res && Output.Write(bytes_written, ctxt);
buf = BitConverter.GetBytes((uint)0);
res = res && Output.Write((int)CharSize, buf);
GSF_LE_SET_GUINT32(buf, 0, 0);
res = res && Output.Write(CharSize, buf);
if (CharSize > 1)
{

266
BurnOutSharp/External/libgsf/GsfUtils.cs vendored Normal file
View File

@@ -0,0 +1,266 @@
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* gsf-utils.c:
*
* Copyright (C) 2002-2006 Jody Goldberg (jody@gnome.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
using System;
namespace LibGSF
{
/// <summary>
/// Do this the ugly way so that we don't have to worry about alignment
/// </summary>
internal static class GsfUtils
{
#region GET
/// <summary>
/// Interpret binary data as an unsigned 8-bit integer in little endian order.
/// </summary>
/// <param name="data">Storage</param>
/// <param name="p">Pointer to storage</param>
/// <returns>Interpreted data</returns>
public static byte GSF_LE_GET_GUINT8(byte[] data, int p)
=> data[p];
/// <summary>
/// Interpret binary data as an unsigned 16-bit integer in little endian order.
/// </summary>
/// <param name="data">Storage</param>
/// <param name="p">Pointer to storage</param>
/// <returns>Interpreted data</returns>
public static ushort GSF_LE_GET_GUINT16(byte[] data, int p)
=> (ushort)((data[p] << 0)
| (data[p + 1] << 8));
/// <summary>
/// Interpret binary data as an unsigned 32-bit integer in little endian order.
/// </summary>
/// <param name="data">Storage</param>
/// <param name="p">Pointer to storage</param>
/// <returns>Interpreted data</returns>
public static uint GSF_LE_GET_GUINT32(byte[] data, int p)
=> (uint)((data[p] << 0)
| (data[p + 1] << 8)
| (data[p + 2] << 16)
| (data[p + 3] << 24));
/// <summary>
/// Interpret binary data as an unsigned 64-bit integer in little endian order.
/// </summary>
/// <param name="data">Storage</param>
/// <param name="p">Pointer to storage</param>
/// <returns>Interpreted data</returns>
public static ulong GSF_LE_GET_GUINT64(byte[] data, int p)
=> (uint)((data[p] << 0)
| (data[p + 1] << 8)
| (data[p + 2] << 16)
| (data[p + 3] << 24)
| (data[p + 4] << 32)
| (data[p + 5] << 40)
| (data[p + 6] << 48)
| (data[p + 7] << 56));
/// <summary>
/// Interpret binary data as a signed 8-bit integer in little endian order.
/// </summary>
/// <param name="data">Storage</param>
/// <param name="p">Pointer to storage</param>
/// <returns>Interpreted data</returns>
public static sbyte GSF_LE_GET_GINT8(byte[] data, int p) => (sbyte)GSF_LE_GET_GINT8(data, p);
/// <summary>
/// Interpret binary data as a signed 16-bit integer in little endian order.
/// </summary>
/// <param name="data">Storage</param>
/// <param name="p">Pointer to storage</param>
/// <returns>Interpreted data</returns>
public static short GSF_LE_GET_GINT16(byte[] data, int p) => (short)GSF_LE_GET_GUINT16(data, p);
/// <summary>
/// Interpret binary data as a signed 32-bit integer in little endian order.
/// </summary>
/// <param name="data">Storage</param>
/// <param name="p">Pointer to storage</param>
/// <returns>Interpreted data</returns>
public static int GSF_LE_GET_GINT32(byte[] data, int p) => (int)GSF_LE_GET_GUINT32(data, p);
/// <summary>
/// Interpret binary data as a signed 64-bit integer in little endian order.
/// </summary>
/// <param name="data">Storage</param>
/// <param name="p">Pointer to storage</param>
/// <returns>Interpreted data</returns>
public static long GSF_LE_GET_GINT64(byte[] data, int p) => (long)GSF_LE_GET_GUINT64(data, p);
/// <summary>
/// Interpret binary data as a float in little endian order.
/// </summary>
/// <param name="data">Storage</param>
/// <param name="p">Pointer to storage</param>
/// <returns>Interpreted data</returns>
public static float GSF_LE_GET_FLOAT(byte[] data, int p)
{
byte[] temp = new ReadOnlySpan<byte>(data, p, 4).ToArray();
if (!BitConverter.IsLittleEndian)
Array.Reverse(temp);
return BitConverter.ToSingle(temp, 0);
}
/// <summary>
/// Interpret binary data as a double in little endian order.
/// </summary>
/// <param name="data">Storage</param>
/// <param name="p">Pointer to storage</param>
/// <returns>Interpreted data</returns>
public static double GSF_LE_GET_DOUBLE(byte[] data, int p)
{
byte[] temp = new ReadOnlySpan<byte>(data, p, 8).ToArray();
if (!BitConverter.IsLittleEndian)
Array.Reverse(temp);
return BitConverter.ToDouble(temp, 0);
}
#endregion
#region SET
/// <summary>
/// Store <paramref name="dat"/> in little endian order in memory pointed to by <paramref name="p"/>.
/// </summary>
/// <param name="data">Storage</param>
/// <param name="p">Pointer to storage</param>
/// <param name="dat">8-bit unsigned integer</param>
public static void GSF_LE_SET_GUINT8(byte[] data, int p, byte dat)
{
data[p] = (byte)(dat & 0xff);
}
/// <summary>
/// Store <paramref name="dat"/> in little endian order in memory pointed to by <paramref name="p"/>.
/// </summary>
/// <param name="data">Storage</param>
/// <param name="p">Pointer to storage</param>
/// <param name="dat">16-bit unsigned integer</param>
public static void GSF_LE_SET_GUINT16(byte[] data, int p, ushort dat)
{
data[p + 0] = (byte)(dat & 0xff);
data[p + 1] = (byte)((dat >> 8) & 0xff);
}
/// <summary>
/// Store <paramref name="dat"/> in little endian order in memory pointed to by <paramref name="p"/>.
/// </summary>
/// <param name="data">Storage</param>
/// <param name="p">Pointer to storage</param>
/// <param name="dat">32-bit unsigned integer</param>
public static void GSF_LE_SET_GUINT32(byte[] data, int p, uint dat)
{
data[p + 0] = (byte)(dat & 0xff);
data[p + 1] = (byte)((dat >> 8) & 0xff);
data[p + 2] = (byte)((dat >> 16) & 0xff);
data[p + 3] = (byte)((dat >> 24) & 0xff);
}
/// <summary>
/// Store <paramref name="dat"/> in little endian order in memory pointed to by <paramref name="p"/>.
/// </summary>
/// <param name="data">Storage</param>
/// <param name="p">Pointer to storage</param>
/// <param name="dat">64-bit unsigned integer</param>
public static void GSF_LE_SET_GUINT64(byte[] data, int p, ulong dat)
{
data[p + 0] = (byte)(dat & 0xff);
data[p + 1] = (byte)((dat >> 8) & 0xff);
data[p + 2] = (byte)((dat >> 16) & 0xff);
data[p + 3] = (byte)((dat >> 24) & 0xff);
data[p + 4] = (byte)((dat >> 32) & 0xff);
data[p + 5] = (byte)((dat >> 40) & 0xff);
data[p + 6] = (byte)((dat >> 48) & 0xff);
data[p + 7] = (byte)((dat >> 56) & 0xff);
}
/// <summary>
/// Store <paramref name="dat"/> in little endian order in memory pointed to by <paramref name="p"/>.
/// </summary>
/// <param name="data">Storage</param>
/// <param name="p">Pointer to storage</param>
/// <param name="dat">8-bit signed integer</param>
public static void GSF_LE_SET_GINT8(byte[] data, int p, sbyte dat) => GSF_LE_SET_GUINT8(data, p, (byte)dat);
/// <summary>
/// Store <paramref name="dat"/> in little endian order in memory pointed to by <paramref name="p"/>.
/// </summary>
/// <param name="data">Storage</param>
/// <param name="p">Pointer to storage</param>
/// <param name="dat">16-bit signed integer</param>
public static void GSF_LE_SET_GINT16(byte[] data, int p, short dat) => GSF_LE_SET_GUINT16(data, p, (ushort)dat);
/// <summary>
/// Store <paramref name="dat"/> in little endian order in memory pointed to by <paramref name="p"/>.
/// </summary>
/// <param name="data">Storage</param>
/// <param name="p">Pointer to storage</param>
/// <param name="dat">32-bit signed integer</param>
public static void GSF_LE_SET_GINT32(byte[] data, int p, int dat) => GSF_LE_SET_GUINT32(data, p, (uint)dat);
/// <summary>
/// Store <paramref name="dat"/> in little endian order in memory pointed to by <paramref name="p"/>.
/// </summary>
/// <param name="data">Storage</param>
/// <param name="p">Pointer to storage</param>
/// <param name="dat">64-bit signed integer</param>
public static void GSF_LE_SET_GINT64(byte[] data, int p, long dat) => GSF_LE_SET_GUINT64(data, p, (ulong)dat);
/// <summary>
/// Store <paramref name="dat"/> in little endian order in memory pointed to by <paramref name="p"/>.
/// </summary>
/// <param name="data">Storage</param>
/// <param name="p">Pointer to storage</param>
/// <param name="dat">Float to be stored</param>
public static void GSF_LE_SET_FLOAT(byte[] data, int p, float dat)
{
byte[] temp = BitConverter.GetBytes(dat);
if (!BitConverter.IsLittleEndian)
Array.Reverse(temp);
Array.Copy(temp, 0, data, p, 4);
}
/// <summary>
/// Store <paramref name="dat"/> in little endian order in memory pointed to by <paramref name="p"/>.
/// </summary>
/// <param name="data">Storage</param>
/// <param name="p">Pointer to storage</param>
/// <param name="dat">Double to be stored</param>
public static void GSF_LE_SET_DOUBLE(byte[] data, int p, double dat)
{
byte[] temp = BitConverter.GetBytes(dat);
if (!BitConverter.IsLittleEndian)
Array.Reverse(temp);
Array.Copy(temp, 0, data, p, 8);
}
#endregion
}
}

View File

@@ -30,6 +30,7 @@ using System.IO;
using System.Linq;
using System.Text;
using static LibGSF.GsfMSOleImpl;
using static LibGSF.GsfUtils;
namespace LibGSF.Input
{
@@ -39,9 +40,7 @@ namespace LibGSF.Input
public uint[] Block { get; set; } = null;
public int BlockPointer { get; set; } = 0;
public int NumBlocks { get; set; }
public uint NumBlocks { get; set; }
#endregion
@@ -60,12 +59,13 @@ namespace LibGSF.Input
/// <param name="size_guess">An optional guess as to how many blocks are in the file</param>
/// <param name="block">The first block in the list.</param>
/// <param name="res">Where to store the result.</param>
/// <returns>true on error.</returns>
/// <returns>True on error.</returns>
public static bool Create(MSOleBAT metabat, int size_guess, uint block, out MSOleBAT res)
{
// NOTE : Only use size as a suggestion, sometimes it is wrong
uint[] bat = new uint[size_guess];
int batPtr = 0; // bat[0]
byte[] used = new byte[1 + metabat.NumBlocks / 8];
while (block < metabat.NumBlocks)
@@ -82,7 +82,7 @@ namespace LibGSF.Input
res = new MSOleBAT
{
NumBlocks = bat.Length,
NumBlocks = (uint)bat.Length,
Block = bat,
};
@@ -107,7 +107,50 @@ namespace LibGSF.Input
NumBlocks = 0;
Block = null;
BlockPointer = 0;
}
#endregion
}
public class MSOleDirent
{
#region Properties
public string Name { get; set; }
public GsfMSOleSortingKey Key { get; set; }
public int Index { get; set; }
public int Size { get; set; }
public bool UseSmallBlock { get; set; }
public uint FirstBlock { get; set; }
public bool IsDirectory { get; set; }
public List<MSOleDirent> Children { get; set; }
/// <summary>
/// 16 byte GUID used by some apps
/// </summary>
public byte[] ClassID { get; set; } = new byte[16];
public DateTime? ModTime { get; set; }
#endregion
#region Functions
private void Free()
{
foreach (MSOleDirent child in Children)
{
child.Free();
}
Children = null;
}
#endregion
@@ -117,13 +160,13 @@ namespace LibGSF.Input
{
#region Classes
public class MSOLEInfoPrivateStruct
public class MSOleInfoBlock
{
public MSOleBAT Bat { get; set; }
public int Shift { get; set; }
public uint Filter { get; set; }
public int Filter { get; set; }
public int Size { get; set; }
}
@@ -132,9 +175,9 @@ namespace LibGSF.Input
#region Properties
public MSOLEInfoPrivateStruct BigBlock { get; set; }
public MSOleInfoBlock BigBlock { get; set; }
public MSOLEInfoPrivateStruct SmallBlock { get; set; }
public MSOleInfoBlock SmallBlock { get; set; }
public long MaxBlock { get; set; }
@@ -143,11 +186,11 @@ namespace LibGSF.Input
/// </summary>
public uint Threshold { get; set; }
public uint SbatStart { get; set; }
public uint SBatStart { get; set; }
public uint NumSbat { get; set; }
public MSOLEDirectoryEntry RootDir { get; set; }
public MSOleDirent RootDir { get; set; }
public GsfInput SmallBlockFile { get; set; }
@@ -180,50 +223,6 @@ namespace LibGSF.Input
#endregion
}
public class MSOLEDirectoryEntry
{
#region Properties
public string Name { get; set; }
public GsfMSOleSortingKey Key { get; set; }
public int Index { get; set; }
public int Size { get; set; }
public bool UseSmallBlock { get; set; }
public uint FirstBlock { get; set; }
public bool IsDirectory { get; set; }
public List<MSOLEDirectoryEntry> Children { get; set; }
/// <summary>
/// 16 byte GUID used by some apps
/// </summary>
public byte[] ClassID { get; set; } = new byte[16];
public DateTime? ModTime { get; set; }
#endregion
#region Functions
private void Free()
{
foreach (MSOLEDirectoryEntry child in Children)
{
child.Free();
}
Children = null;
}
#endregion
}
public class GsfInfileMSOle : GsfInfile
{
#region Properties
@@ -232,17 +231,49 @@ namespace LibGSF.Input
public MSOleInfo Info { get; private set; } = null;
public MSOLEDirectoryEntry DirectoryEntry { get; private set; }
public MSOleDirent DirectoryEntry { get; private set; }
public MSOleBAT Bat { get; private set; }
public long CurBlock { get; private set; } = BAT_MAGIC_UNUSED;
/// <remarks>Actually `{ byte[] Buf, long BufSize }`</remarks>
public byte[] Stream { get; private set; }
#endregion
#region Destructor
#region Constructor and Destructor
/// <summary>
/// Private constructor
/// </summary>
private GsfInfileMSOle() { }
/// <summary>
/// Opens the root directory of an MS OLE file.
/// </summary>
/// <param name="source">GsfInput</param>
/// <param name="err">Optional place to store an error</param>
/// <returns>The new ole file handler</returns>
/// <remarks>This adds a reference to <paramref name="source"/>.</remarks>
public static GsfInfile Create(GsfInput source, ref Exception err)
{
GsfInfileMSOle ole = new GsfInfileMSOle
{
Input = source,
Size = 0,
};
long calling_pos = source.CurrentOffset;
if (ole.InitInfo(ref err))
{
// We do this so other kinds of archives can be tried.
source.Seek(calling_pos, SeekOrigin.Begin);
return null;
}
return ole;
}
/// <summary>
/// Destructor
@@ -348,7 +379,7 @@ namespace LibGSF.Input
/// <inheritdoc/>
public override GsfInput ChildByIndex(int i, ref Exception error)
{
foreach (MSOLEDirectoryEntry dirent in DirectoryEntry.Children)
foreach (MSOleDirent dirent in DirectoryEntry.Children)
{
if (i-- <= 0)
return CreateChild(dirent, ref error);
@@ -360,7 +391,7 @@ namespace LibGSF.Input
/// <inheritdoc/>
public override string NameByIndex(int i)
{
foreach (MSOLEDirectoryEntry dirent in DirectoryEntry.Children)
foreach (MSOleDirent dirent in DirectoryEntry.Children)
{
if (i-- <= 0)
return dirent.Name;
@@ -372,7 +403,7 @@ namespace LibGSF.Input
/// <inheritdoc/>
public override GsfInput ChildByName(string name, ref Exception error)
{
foreach (MSOLEDirectoryEntry dirent in DirectoryEntry.Children)
foreach (MSOleDirent dirent in DirectoryEntry.Children)
{
if (dirent.Name != null && dirent.Name == name)
return CreateChild(dirent, ref error);
@@ -393,38 +424,12 @@ namespace LibGSF.Input
return DirectoryEntry.Children.Count;
}
/// <summary>
/// Opens the root directory of an MS OLE file.
/// </summary>
/// <param name="source">GsfInput</param>
/// <param name="err">Optional place to store an error</param>
/// <returns>The new ole file handler</returns>
/// <remarks>This adds a reference to <paramref name="source"/>.</remarks>
public static GsfInfile Create(GsfInput source, ref Exception err)
{
GsfInfileMSOle ole = new GsfInfileMSOle
{
Input = source,
Size = 0,
};
long calling_pos = source.CurrentOffset;
if (ole.InitInfo(ref err))
{
// We do this so other kinds of archives can be tried.
source.Seek(calling_pos, SeekOrigin.Begin);
return null;
}
return ole;
}
/// <summary>
/// Retrieves the 16 byte indentifier (often a GUID in MS Windows apps)
/// stored within the directory associated with @ole and stores it in <paramref name="res"/>.
/// </summary>
/// <param name="res">16 byte identifier (often a GUID in MS Windows apps)</param>
/// <returns>true on success</returns>
/// <returns>True on success</returns>
public bool GetClassID(byte[] res)
{
if (DirectoryEntry == null)
@@ -472,9 +477,9 @@ namespace LibGSF.Input
/// either from the OLE header, or a meta-bat block.
/// </summary>
/// <returns>A pointer to the element after the last position filled</returns>
private uint[] ReadMetabat(uint[] bats, int batsPtr, int max_bat, uint[] metabat, int metabatPtr, int metabat_end)
private uint[] ReadMetabat(uint[] bats, int batsPtr, int max_bat, uint[] metabat, int metabat_end)
{
for (; metabatPtr < metabat_end; metabatPtr++)
for (int metabatPtr = 0; metabatPtr < metabat_end; metabatPtr++)
{
if (metabat[metabatPtr] != BAT_MAGIC_UNUSED)
{
@@ -482,11 +487,10 @@ namespace LibGSF.Input
if (bat == null)
return null;
int batPtr = 0; // bat[0]
int end = batPtr + Info.BigBlock.Size;
for (; batPtr < end; batPtr += BAT_INDEX_SIZE, batsPtr++)
int end = Info.BigBlock.Size;
for (int batPtr = 0; batPtr < end; batPtr += BAT_INDEX_SIZE, batsPtr++)
{
bats[batsPtr] = BitConverter.ToUInt32(bat, batPtr);
bats[batsPtr] = GSF_LE_GET_GUINT32(bat, batPtr);
if (bats[batsPtr] >= max_bat && bats[batsPtr] < BAT_MAGIC_METABAT)
{
Console.Error.WriteLine($"Invalid metabat item {bats[batsPtr]}");
@@ -518,7 +522,7 @@ namespace LibGSF.Input
{
for (; (num_bytes -= BAT_INDEX_SIZE) >= 0; srcPtr += BAT_INDEX_SIZE)
{
dst[dstPtr++] = BitConverter.ToUInt32(src, srcPtr);
dst[dstPtr++] = GSF_LE_GET_GUINT32(src, srcPtr);
}
}
@@ -538,21 +542,21 @@ namespace LibGSF.Input
if (Info.SmallBlock.Bat.Block != null)
return null;
if (MSOleBAT.Create(Info.BigBlock.Bat, (int)Info.NumSbat, Info.SbatStart, out MSOleBAT meta_sbat))
if (MSOleBAT.Create(Info.BigBlock.Bat, (int)Info.NumSbat, Info.SBatStart, out MSOleBAT meta_sbat))
return null;
Info.SmallBlock.Bat.NumBlocks = meta_sbat.NumBlocks * (Info.BigBlock.Size / BAT_INDEX_SIZE);
Info.SmallBlock.Bat.NumBlocks = (uint)(meta_sbat.NumBlocks * (Info.BigBlock.Size / BAT_INDEX_SIZE));
Info.SmallBlock.Bat.Block = new uint[Info.SmallBlock.Bat.NumBlocks];
ReadMetabat(Info.SmallBlock.Bat.Block, 0, Info.SmallBlock.Bat.NumBlocks, meta_sbat.Block, 0, meta_sbat.NumBlocks);
ReadMetabat(Info.SmallBlock.Bat.Block, 0, (int)Info.SmallBlock.Bat.NumBlocks, meta_sbat.Block, (int)meta_sbat.NumBlocks);
return Info.SmallBlockFile;
}
private static int DirectoryEntryCompare(MSOLEDirectoryEntry a, MSOLEDirectoryEntry b) => SortingKeyCompare(a.Key, b.Key);
private static int DirectoryEntryCompare(MSOleDirent a, MSOleDirent b) => SortingKeyCompare(a.Key, b.Key);
private static DateTime? DateTimeFromFileTime(ulong ft) => ft == 0 ? (DateTime?)null : DateTime.FromFileTime((long)ft);
private GsfInput CreateChild(MSOLEDirectoryEntry dirent, ref Exception err)
private GsfInput CreateChild(MSOleDirent dirent, ref Exception err)
{
GsfInfileMSOle child = PartiallyDuplicate(ref err);
if (child == null)
@@ -587,7 +591,7 @@ namespace LibGSF.Input
if (dirent.UseSmallBlock)
{
metabat = info.SmallBlock.Bat;
size_guess = dirent.Size >> (int)info.SmallBlock.Shift;
size_guess = dirent.Size >> info.SmallBlock.Shift;
sb_file = GetSmallBlockFile();
if (sb_file == null)
{
@@ -598,7 +602,7 @@ namespace LibGSF.Input
else
{
metabat = info.BigBlock.Bat;
size_guess = dirent.Size >> (int)info.BigBlock.Shift;
size_guess = dirent.Size >> info.BigBlock.Shift;
}
if (MSOleBAT.Create(metabat, size_guess + 1, dirent.FirstBlock, out MSOleBAT tempBat))
@@ -639,7 +643,7 @@ namespace LibGSF.Input
/// <summary>
/// Parse dirent number <paramref name="entry"/> and recursively handle its siblings and children.
/// parent is optional.
private MSOLEDirectoryEntry CreateDirectoryEntry(uint entry, MSOLEDirectoryEntry parent, bool[] seen_before)
private MSOleDirent CreateDirectoryEntry(uint entry, MSOleDirent parent, bool[] seen_before)
{
if (entry >= DIRENT_MAGIC_END)
return null;
@@ -663,7 +667,7 @@ namespace LibGSF.Input
int dataPtr = 0; // data[0]
dataPtr += (int)((DIRENT_SIZE * entry) % Info.BigBlock.Size);
byte type = data[dataPtr + DIRENT_TYPE];
byte type = GSF_LE_GET_GUINT8(data, dataPtr + DIRENT_TYPE);
if (type != DIRENT_TYPE_DIR && type != DIRENT_TYPE_FILE && type != DIRENT_TYPE_ROOTDIR)
{
Console.Error.WriteLine($"Unknown stream type 0x{type:x}");
@@ -678,13 +682,13 @@ namespace LibGSF.Input
}
// It looks like directory (and root directory) sizes are sometimes bogus
uint size = BitConverter.ToUInt32(data, dataPtr + DIRENT_FILE_SIZE);
uint size = GSF_LE_GET_GUINT32(data, dataPtr + DIRENT_FILE_SIZE);
if (!(type == DIRENT_TYPE_DIR || type == DIRENT_TYPE_ROOTDIR || size <= (uint)Input.Size))
return null;
ulong ft = BitConverter.ToUInt64(data, dataPtr + DIRENT_MODIFY_TIME);
ulong ft = GSF_LE_GET_GUINT64(data, dataPtr + DIRENT_MODIFY_TIME);
MSOLEDirectoryEntry dirent = new MSOLEDirectoryEntry
MSOleDirent dirent = new MSOleDirent
{
Index = (int)entry,
Size = (int)size,
@@ -696,14 +700,14 @@ namespace LibGSF.Input
// Root dir is always big block
dirent.UseSmallBlock = parent != null && (size < Info.Threshold);
dirent.FirstBlock = BitConverter.ToUInt32(data, dataPtr + DIRENT_FIRSTBLOCK);
dirent.FirstBlock = GSF_LE_GET_GUINT32(data, dataPtr + DIRENT_FIRSTBLOCK);
dirent.IsDirectory = (type != DIRENT_TYPE_FILE);
dirent.Children = null;
uint prev = BitConverter.ToUInt32(data, dataPtr + DIRENT_PREV);
uint next = BitConverter.ToUInt32(data, dataPtr + DIRENT_NEXT);
uint child = BitConverter.ToUInt32(data, dataPtr + DIRENT_CHILD);
ushort name_len = BitConverter.ToUInt16(data, dataPtr + DIRENT_NAME_LEN);
uint prev = GSF_LE_GET_GUINT32(data, dataPtr + DIRENT_PREV);
uint next = GSF_LE_GET_GUINT32(data, dataPtr + DIRENT_NEXT);
uint child = GSF_LE_GET_GUINT32(data, dataPtr + DIRENT_CHILD);
ushort name_len = GSF_LE_GET_GUINT16(data, dataPtr + DIRENT_NAME_LEN);
dirent.Name = null;
if (0 < name_len && name_len <= DIRENT_MAX_NAME_SIZE)
@@ -717,6 +721,7 @@ namespace LibGSF.Input
try { end = new UTF8Encoding(false, true).GetCharCount(data); }
catch { end = -1; }
// TODO: Read original code and rewrite this
if (end == -1 || (end + 1) != name_len)
{
byte[] direntNameBytes = Encoding.Convert(Encoding.ASCII, Encoding.UTF8, data, 0, end);
@@ -777,7 +782,7 @@ namespace LibGSF.Input
/// Read an OLE header and do some sanity checking
/// along the way.
/// </summary>
/// <returns>true on error setting <paramref name="err"/> if it is supplied.</returns>
/// <returns>True on error setting <paramref name="err"/> if it is supplied.</returns>
private bool InitInfo(ref Exception err)
{
byte[] header;
@@ -785,21 +790,21 @@ namespace LibGSF.Input
// Check the header
byte[] signature = { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 };
if (Input.Seek(0, SeekOrigin.Begin)
|| null == (header = Input.Read(OLE_HEADER_SIZE, null))
|| (header = Input.Read(OLE_HEADER_SIZE, null)) == null
|| !header.Take(signature.Length).SequenceEqual(signature))
{
err = new Exception("No OLE2 signature");
return true;
}
ushort bb_shift = BitConverter.ToUInt16(header, OLE_HEADER_BB_SHIFT);
ushort sb_shift = BitConverter.ToUInt16(header, OLE_HEADER_SB_SHIFT);
uint num_bat = BitConverter.ToUInt32(header, OLE_HEADER_NUM_BAT);
uint num_sbat = BitConverter.ToUInt32(header, OLE_HEADER_NUM_SBAT);
uint threshold = BitConverter.ToUInt32(header, OLE_HEADER_THRESHOLD);
uint dirent_start = BitConverter.ToUInt32(header, OLE_HEADER_DIRENT_START);
uint metabat_block = BitConverter.ToUInt32(header, OLE_HEADER_METABAT_BLOCK);
uint num_metabat = BitConverter.ToUInt32(header, OLE_HEADER_NUM_METABAT);
ushort bb_shift = GSF_LE_GET_GUINT16(header, OLE_HEADER_BB_SHIFT);
ushort sb_shift = GSF_LE_GET_GUINT16(header, OLE_HEADER_SB_SHIFT);
uint num_bat = GSF_LE_GET_GUINT32(header, OLE_HEADER_NUM_BAT);
uint num_sbat = GSF_LE_GET_GUINT32(header, OLE_HEADER_NUM_SBAT);
uint threshold = GSF_LE_GET_GUINT32(header, OLE_HEADER_THRESHOLD);
uint dirent_start = GSF_LE_GET_GUINT32(header, OLE_HEADER_DIRENT_START);
uint metabat_block = GSF_LE_GET_GUINT32(header, OLE_HEADER_METABAT_BLOCK);
uint num_metabat = GSF_LE_GET_GUINT32(header, OLE_HEADER_NUM_METABAT);
// Some sanity checks
// 1) There should always be at least 1 BAT block
@@ -814,22 +819,22 @@ namespace LibGSF.Input
MSOleInfo info = new MSOleInfo
{
RefCount = 1,
BigBlock = new MSOleInfo.MSOLEInfoPrivateStruct
BigBlock = new MSOleInfo.MSOleInfoBlock
{
Shift = bb_shift,
Size = 1 << bb_shift,
Filter = (uint)(1 << bb_shift) - 1,
Filter = (1 << bb_shift) - 1,
Bat = new MSOleBAT(),
},
SmallBlock = new MSOleInfo.MSOLEInfoPrivateStruct
SmallBlock = new MSOleInfo.MSOleInfoBlock
{
Shift = sb_shift,
Size = 1 << sb_shift,
Filter = (uint)(1 << sb_shift) - 1,
Filter = (1 << sb_shift) - 1,
Bat = new MSOleBAT(),
},
Threshold = threshold,
SbatStart = BitConverter.ToUInt32(header, OLE_HEADER_SBAT_START),
SBatStart = GSF_LE_GET_GUINT32(header, OLE_HEADER_SBAT_START),
NumSbat = num_sbat,
MaxBlock = (Input.Size - OLE_HEADER_SIZE + (1 << bb_shift) - 1) / (1 << bb_shift),
SmallBlockFile = null,
@@ -837,7 +842,7 @@ namespace LibGSF.Input
Info = info;
if (info.NumSbat == 0 && info.SbatStart != BAT_MAGIC_END_OF_CHAIN && info.SbatStart != BAT_MAGIC_UNUSED)
if (info.NumSbat == 0 && info.SBatStart != BAT_MAGIC_END_OF_CHAIN && info.SBatStart != BAT_MAGIC_UNUSED)
Console.Error.WriteLine("There are not supposed to be any blocks in the small block allocation table, yet there is a link to some. Ignoring it.");
uint[] metabat = null;
@@ -847,7 +852,7 @@ namespace LibGSF.Input
// Very rough heuristic, just in case
if (num_bat < info.MaxBlock && info.NumSbat < info.MaxBlock)
{
info.BigBlock.Bat.NumBlocks = (int)(num_bat * (info.BigBlock.Size / BAT_INDEX_SIZE));
info.BigBlock.Bat.NumBlocks = (uint)(num_bat * (info.BigBlock.Size / BAT_INDEX_SIZE));
info.BigBlock.Bat.Block = new uint[info.BigBlock.Bat.NumBlocks];
metabat = new uint[Math.Max(info.BigBlock.Size, OLE_HEADER_SIZE)];
@@ -858,7 +863,7 @@ namespace LibGSF.Input
if (last > OLE_HEADER_METABAT_SIZE)
last = OLE_HEADER_METABAT_SIZE;
ptr = ReadMetabat(info.BigBlock.Bat.Block, 0, info.BigBlock.Bat.NumBlocks, metabat, 0, (int)last);
ptr = ReadMetabat(info.BigBlock.Bat.Block, 0, (int)info.BigBlock.Bat.NumBlocks, metabat, (int)last);
num_bat -= last;
}
else
@@ -906,7 +911,7 @@ namespace LibGSF.Input
num_bat -= last;
}
ptr = ReadMetabat(ptr, ptrPtr, info.BigBlock.Bat.NumBlocks, metabat, 0, (int)last);
ptr = ReadMetabat(ptr, ptrPtr, (int)info.BigBlock.Bat.NumBlocks, metabat, (int)last);
}
bool fail = (ptr == null);

View File

@@ -30,6 +30,7 @@
using System;
using System.Collections.Generic;
using System.Text;
using static LibGSF.GsfUtils;
namespace LibGSF.Input
{
@@ -251,8 +252,8 @@ namespace LibGSF.Input
return false;
}
tag = BitConverter.ToUInt16(inflated_data, ptr);
uint len = BitConverter.ToUInt32(inflated_data, ptr + 2);
tag = GSF_LE_GET_GUINT16(inflated_data, ptr);
uint len = GSF_LE_GET_GUINT32(inflated_data, ptr + 2);
ptr += 6;
if ((ptr + len) > end)
@@ -286,7 +287,7 @@ namespace LibGSF.Input
break;
}
element_count = BitConverter.ToUInt16(inflated_data, ptr);
element_count = GSF_LE_GET_GUINT16(inflated_data, ptr);
break;
// Dependencies
@@ -315,7 +316,7 @@ namespace LibGSF.Input
break;
}
ExtractModuleSource(elem_stream, BitConverter.ToUInt32(inflated_data, ptr));
ExtractModuleSource(elem_stream, GSF_LE_GET_GUINT32(inflated_data, ptr));
elem_stream = null;
element_count--;
break;

View File

@@ -27,6 +27,7 @@ using System.IO;
using System.Text;
using ComponentAce.Compression.Libs.zlib;
using static ComponentAce.Compression.Libs.zlib.zlibConst;
using static LibGSF.GsfUtils;
using static LibGSF.GsfZipImpl;
namespace LibGSF.Input
@@ -394,7 +395,7 @@ namespace LibGSF.Input
for (int s = (int)(p + maplen - 1); (s >= p); s--, trailer_offset--)
{
if (data[s] == sig1 && p + maplen - 1 - s > size - 2 && BitConverter.ToUInt32(data, s) == sig)
if (data[s] == sig1 && p + maplen - 1 - s > size - 2 && GSF_LE_GET_GUINT32(data, s) == sig)
return --trailer_offset;
}
@@ -433,8 +434,8 @@ namespace LibGSF.Input
return null;
}
ExtraFieldTags ftyp = (ExtraFieldTags)BitConverter.ToUInt16(extra, extraPtr);
uint flen = BitConverter.ToUInt16(extra, extraPtr + 2);
ExtraFieldTags ftyp = (ExtraFieldTags)GSF_LE_GET_GUINT16(extra, extraPtr);
uint flen = GSF_LE_GET_GUINT16(extra, extraPtr + 2);
if (flen > elen - 4)
{
pflen = 0;
@@ -463,14 +464,14 @@ namespace LibGSF.Input
byte[] data = header;
if (Source.Seek(offset, SeekOrigin.Begin)
|| Source.Read(ZIP_DIRENT_SIZE, header) != null
|| BitConverter.ToUInt32(data, 0) != ZIP_DIRENT_SIGNATURE)
|| GSF_LE_GET_GUINT32(data, 0) != ZIP_DIRENT_SIGNATURE)
{
return null;
}
ushort name_len = BitConverter.ToUInt16(header, ZIP_DIRENT_NAME_SIZE);
ushort extras_len = BitConverter.ToUInt16(header, ZIP_DIRENT_EXTRAS_SIZE);
ushort comment_len = BitConverter.ToUInt16(header, ZIP_DIRENT_COMMENT_SIZE);
ushort name_len = GSF_LE_GET_GUINT16(header, ZIP_DIRENT_NAME_SIZE);
ushort extras_len = GSF_LE_GET_GUINT16(header, ZIP_DIRENT_EXTRAS_SIZE);
ushort comment_len = GSF_LE_GET_GUINT16(header, ZIP_DIRENT_COMMENT_SIZE);
int vlen = name_len + extras_len + comment_len;
// Read variable part
@@ -482,36 +483,36 @@ namespace LibGSF.Input
int extraPtr = 0; // extra[0];
bool zip64 = (extra != null);
uint flags = BitConverter.ToUInt32(header, ZIP_DIRENT_FLAGS);
GsfZipCompressionMethod compression_method = (GsfZipCompressionMethod)BitConverter.ToUInt16(header, ZIP_DIRENT_COMPR_METHOD);
uint dostime = BitConverter.ToUInt32(header, ZIP_DIRENT_DOSTIME);
uint crc32 = BitConverter.ToUInt32(header, ZIP_DIRENT_CRC32);
long csize = BitConverter.ToUInt32(header, ZIP_DIRENT_CSIZE);
long usize = BitConverter.ToUInt32(header, ZIP_DIRENT_USIZE);
long off = BitConverter.ToUInt32(header, ZIP_DIRENT_OFFSET);
uint disk_start = BitConverter.ToUInt16(header, ZIP_DIRENT_DISKSTART);
uint flags = GSF_LE_GET_GUINT32(header, ZIP_DIRENT_FLAGS);
GsfZipCompressionMethod compression_method = (GsfZipCompressionMethod)GSF_LE_GET_GUINT16(header, ZIP_DIRENT_COMPR_METHOD);
uint dostime = GSF_LE_GET_GUINT32(header, ZIP_DIRENT_DOSTIME);
uint crc32 = GSF_LE_GET_GUINT32(header, ZIP_DIRENT_CRC32);
long csize = GSF_LE_GET_GUINT32(header, ZIP_DIRENT_CSIZE);
long usize = GSF_LE_GET_GUINT32(header, ZIP_DIRENT_USIZE);
long off = GSF_LE_GET_GUINT32(header, ZIP_DIRENT_OFFSET);
uint disk_start = GSF_LE_GET_GUINT16(header, ZIP_DIRENT_DISKSTART);
if (usize == 0xffffffffu && elen >= 8)
{
usize = (long)BitConverter.ToUInt64(extra, extraPtr);
usize = (long)GSF_LE_GET_GUINT64(extra, extraPtr);
extraPtr += 8;
elen -= 8;
}
if (csize == 0xffffffffu && elen >= 8)
{
csize = (long)BitConverter.ToUInt64(extra, extraPtr);
csize = (long)GSF_LE_GET_GUINT64(extra, extraPtr);
extraPtr += 8;
elen -= 8;
}
if (off == 0xffffffffu && elen >= 8)
{
off = (long)BitConverter.ToUInt64(extra, extraPtr);
off = (long)GSF_LE_GET_GUINT64(extra, extraPtr);
extraPtr += 8;
elen -= 8;
}
if (disk_start == 0xffffu && elen >= 4)
{
disk_start = BitConverter.ToUInt32(extra, extraPtr);
disk_start = GSF_LE_GET_GUINT32(extra, extraPtr);
extraPtr += 4;
elen -= 4;
}
@@ -557,7 +558,7 @@ namespace LibGSF.Input
/// Read zip headers and do some sanity checking
/// along the way.
/// </summary>
/// <returns>true on error setting Err.</returns>
/// <returns>True on error setting Err.</returns>
private bool ReadDirectoryEntries()
{
// Find and check the trailing header
@@ -577,17 +578,17 @@ namespace LibGSF.Input
int data = ZIP_ZIP64_LOCATOR_SIZE; // locator + ZIP_ZIP64_LOCATOR_SIZE
ulong entries = BitConverter.ToUInt16(locator, data + ZIP_TRAILER_ENTRIES);
ulong dir_pos = BitConverter.ToUInt32(locator, data + ZIP_TRAILER_DIR_POS);
ulong entries = GSF_LE_GET_GUINT16(locator, data + ZIP_TRAILER_ENTRIES);
ulong dir_pos = GSF_LE_GET_GUINT32(locator, data + ZIP_TRAILER_DIR_POS);
if (BitConverter.ToUInt32(locator, 0) == ZIP_ZIP64_LOCATOR_SIGNATURE)
if (GSF_LE_GET_GUINT32(locator, 0) == ZIP_ZIP64_LOCATOR_SIGNATURE)
{
Zip64 = true;
data = 0; // locator[0]
uint disk = BitConverter.ToUInt32(locator, data + ZIP_ZIP64_LOCATOR_DISK);
ulong zip64_eod_offset = BitConverter.ToUInt64(locator, data + ZIP_ZIP64_LOCATOR_OFFSET);
uint disks = BitConverter.ToUInt32(locator, data + ZIP_ZIP64_LOCATOR_DISKS);
uint disk = GSF_LE_GET_GUINT32(locator, data + ZIP_ZIP64_LOCATOR_DISK);
ulong zip64_eod_offset = GSF_LE_GET_GUINT64(locator, data + ZIP_ZIP64_LOCATOR_OFFSET);
uint disks = GSF_LE_GET_GUINT32(locator, data + ZIP_ZIP64_LOCATOR_DISKS);
if (disk != 0 || disks != 1)
{
@@ -602,14 +603,14 @@ namespace LibGSF.Input
}
locator = Source.Read(ZIP_TRAILER64_SIZE, null);
if (locator == null || BitConverter.ToUInt32(locator, data) != ZIP_TRAILER64_SIGNATURE)
if (locator == null || GSF_LE_GET_GUINT32(locator, data) != ZIP_TRAILER64_SIGNATURE)
{
Err = new Exception("Broken zip file structure");
return true;
}
entries = BitConverter.ToUInt64(locator, data + ZIP_TRAILER64_ENTRIES);
dir_pos = BitConverter.ToUInt64(locator, data + ZIP_TRAILER64_DIR_POS);
entries = GSF_LE_GET_GUINT64(locator, data + ZIP_TRAILER64_ENTRIES);
dir_pos = GSF_LE_GET_GUINT64(locator, data + ZIP_TRAILER64_DIR_POS);
}
Info = new ZipInfo()
@@ -651,7 +652,7 @@ namespace LibGSF.Input
/// Read zip headers and do some sanity checking
/// along the way.
/// </summary>
/// <returns>true on error setting Err.</returns>
/// <returns>True on error setting Err.</returns>
private bool InitInfo()
{
bool ret = ReadDirectoryEntries();
@@ -684,10 +685,10 @@ namespace LibGSF.Input
{
err = "Error reading zip header";
}
else if (BitConverter.ToUInt32(data, 0) != ZIP_HEADER_SIGNATURE)
else if (GSF_LE_GET_GUINT32(data, 0) != ZIP_HEADER_SIGNATURE)
{
err = "Error incorrect zip header";
Console.Error.WriteLine("Header is 0x%x\n", BitConverter.ToUInt32(data, 0));
Console.Error.WriteLine("Header is 0x%x\n", GSF_LE_GET_GUINT32(data, 0));
Console.Error.WriteLine("Expected 0x%x\n", ZIP_HEADER_SIGNATURE);
}
@@ -697,11 +698,11 @@ namespace LibGSF.Input
return true;
}
uint name_len = BitConverter.ToUInt16(data, ZIP_HEADER_NAME_SIZE);
uint extras_len = BitConverter.ToUInt16(data, ZIP_HEADER_EXTRAS_SIZE);
uint name_len = GSF_LE_GET_GUINT16(data, ZIP_HEADER_NAME_SIZE);
uint extras_len = GSF_LE_GET_GUINT16(data, ZIP_HEADER_EXTRAS_SIZE);
dirent.DataOffset = dirent.Offset + ZIP_HEADER_SIZE + name_len + extras_len;
RestLen = dirent.UncompressedSize;
RestLen = dirent.UncompressedSize;
CRestLen = dirent.CompressedSize;
if (dirent.CompressionMethod != GsfZipCompressionMethod.GSF_ZIP_STORED)

View File

@@ -26,6 +26,7 @@ using System.Linq;
using System.Text;
using LibGSF.Output;
using static LibGSF.GsfMSOleUtils;
using static LibGSF.GsfUtils;
namespace LibGSF.Input
{
@@ -113,7 +114,7 @@ namespace LibGSF.Input
/// <summary>
/// Are we at the end of the file?
/// </summary>
/// <returns>true if the input is at the eof.</returns>
/// <returns>True if the input is at the eof.</returns>
public bool EOF() => CurrentOffset >= Size;
/// <summary>
@@ -174,7 +175,7 @@ namespace LibGSF.Input
/// Determines whether the offset is relative to the beginning or
/// the end of the stream, or to the current location.
/// </param>
/// <returns>true on error.</returns>
/// <returns>True on error.</returns>
public virtual bool Seek(long offset, SeekOrigin whence)
{
long pos = offset;
@@ -203,7 +204,7 @@ namespace LibGSF.Input
}
/// <param name="filename">The (fs-sys encoded) filename</param>
/// <returns>true if the assignment was ok.</returns>
/// <returns>True if the assignment was ok.</returns>
public bool SetNameFromFilename(string filename)
{
string name = null;
@@ -222,7 +223,7 @@ namespace LibGSF.Input
/// Emulate forward seeks by reading.
/// </summary>
/// <param name="pos">Absolute position to seek to</param>
/// <returns>true if the emulation failed.</returns>
/// <returns>True if the emulation failed.</returns>
public bool SeekEmulate(long pos)
{
if (pos < CurrentOffset)
@@ -245,7 +246,7 @@ namespace LibGSF.Input
/// output.Seek(0, SeekOrigin.Begin) first, if applicable.
/// </summary>
/// <param name="output">A non-null GsfOutput</param>
/// <returns>true on success</returns>
/// <returns>True on success</returns>
public bool Copy(GsfOutput output)
{
if (output == null)
@@ -389,7 +390,7 @@ namespace LibGSF.Input
shift = 4;
}
ushort token = BitConverter.ToUInt16(tmp, 0);
ushort token = GSF_LE_GET_GUINT16(tmp, 0);
ushort len = (ushort)((token & ((1 << (int)shift) - 1)) + 3);
uint distance = (uint)(token >> (int)shift);
clean = true;
@@ -445,7 +446,6 @@ namespace LibGSF.Input
/// <summary>
/// Decompresses VBA stream.
/// </summary>
/// <param name="input">Stream to read from</param>
/// <param name="offset">Offset into it for start byte of compressed stream</param>
/// <param name="size">Size of the returned array</param>
/// <param name="add_null_terminator">Whenever add or not null at the end of array</param>
@@ -470,7 +470,7 @@ namespace LibGSF.Input
if (tmp == null)
break;
ushort chunk_hdr = BitConverter.ToUInt16(tmp, 0);
ushort chunk_hdr = GSF_LE_GET_GUINT16(tmp, 0);
offset += 2;
GsfInput chunk;

View File

@@ -24,6 +24,7 @@ using System;
using System.IO;
using ComponentAce.Compression.Libs.zlib;
using static ComponentAce.Compression.Libs.zlib.zlibConst;
using static LibGSF.GsfUtils;
namespace LibGSF.Input
{
@@ -334,7 +335,7 @@ namespace LibGSF.Input
if (data[2] != Z_DEFLATED)
return true;
uint modutime = BitConverter.ToUInt32(data, 4);
uint modutime = GSF_LE_GET_GUINT32(data, 4);
if (modutime != 0)
{
DateTime modtime = DateTimeOffset.FromUnixTimeSeconds(modutime).DateTime;
@@ -352,7 +353,7 @@ namespace LibGSF.Input
}
// FIXME, but how? The size read here is modulo 2^32.
UncompressedSize = BitConverter.ToUInt32(data, 0);
UncompressedSize = GSF_LE_GET_GUINT32(data, 0);
if (UncompressedSize / 1000 > Source.Size)
{
@@ -369,7 +370,7 @@ namespace LibGSF.Input
if ((data = Source.Read(2, null)) == null)
return true;
len = BitConverter.ToUInt16(data, 0);
len = GSF_LE_GET_GUINT16(data, 0);
if (Source.Read((int)len, null) == null)
return true;
}

View File

@@ -183,7 +183,7 @@ namespace LibGSF.Input
/// Dumps structured blob @blob onto the <paramref name="container"/>. Will fail if the output is
/// not an Outfile and blob has multiple streams.
/// </summary>
/// <returns>true on success.</returns>
/// <returns>True on success.</returns>
public bool Write(GsfOutfile container)
{
if (container == null)

View File

@@ -26,6 +26,7 @@ using System.Linq;
using System.Text;
using LibGSF.Input;
using static LibGSF.GsfMSOleImpl;
using static LibGSF.GsfUtils;
namespace LibGSF.Output
{
@@ -194,18 +195,12 @@ namespace LibGSF.Output
byte[] buf = Enumerable.Repeat<byte>(0xFF, OLE_HEADER_SIZE).ToArray();
Array.Copy(default_header, buf, default_header.Length);
byte[] temp = BitConverter.GetBytes((ushort)ole.BigBlock.Shift);
Array.Copy(temp, 0, buf, OLE_HEADER_BB_SHIFT, temp.Length);
temp = BitConverter.GetBytes((ushort)ole.SmallBlock.Shift);
Array.Copy(temp, 0, buf, OLE_HEADER_SB_SHIFT, temp.Length);
GSF_LE_SET_GUINT16(buf, OLE_HEADER_BB_SHIFT, (ushort)ole.BigBlock.Shift);
GSF_LE_SET_GUINT16(buf, OLE_HEADER_SB_SHIFT, (ushort)ole.SmallBlock.Shift);
// 4k sector OLE files seen in the wild have version 4
if (ole.BigBlock.Size == 4096)
{
BitConverter.GetBytes((ushort)4);
Array.Copy(temp, 0, buf, OLE_HEADER_MAJOR_VER, temp.Length);
}
GSF_LE_SET_GUINT16(buf, OLE_HEADER_MAJOR_VER, 4);
sink.Write(OLE_HEADER_SIZE, buf);
@@ -433,7 +428,7 @@ namespace LibGSF.Output
/// Write <paramref name="clsid"/> to the directory associated with ole.
/// </summary>
/// <param name="clsid">Identifier (often a GUID in MS Windows apps)</param>
/// <returns>true on success.</returns>
/// <returns>True on success.</returns>
public bool SetClassID(byte[] clsid)
{
if (Type != MSOleOutfileType.MSOLE_DIR)
@@ -661,38 +656,28 @@ namespace LibGSF.Output
// Be wary about endianness
for (int j = 0; j < name_len; j++)
{
byte[] nameUtf16Temp = BitConverter.GetBytes((ushort)nameUtf16[j]);
Array.Copy(nameUtf16Temp, 0, buf, j * 2, 2);
GSF_LE_SET_GUINT16(buf, j * 2, nameUtf16[j]);
}
name_len++;
}
byte[] writeTemp = BitConverter.GetBytes((ushort)(name_len * 2));
Array.Copy(writeTemp, 0, buf, DIRENT_NAME_LEN, writeTemp.Length);
GSF_LE_SET_GUINT16(buf, DIRENT_NAME_LEN, (ushort)(name_len * 2));
if (child.Root == child)
{
buf[DIRENT_TYPE] = DIRENT_TYPE_ROOTDIR;
writeTemp = BitConverter.GetBytes((uint)((sb_data_size > 0) ? (uint)sb_data_start : BAT_MAGIC_END_OF_CHAIN));
Array.Copy(writeTemp, 0, buf, DIRENT_FIRSTBLOCK, writeTemp.Length);
writeTemp = BitConverter.GetBytes((uint)(sb_data_size));
Array.Copy(writeTemp, 0, buf, DIRENT_FILE_SIZE, writeTemp.Length);
GSF_LE_SET_GUINT8(buf, DIRENT_TYPE, DIRENT_TYPE_ROOTDIR);
GSF_LE_SET_GUINT32(buf, DIRENT_FIRSTBLOCK, (sb_data_size > 0) ? (uint)sb_data_start : BAT_MAGIC_END_OF_CHAIN);
GSF_LE_SET_GUINT32(buf, DIRENT_FILE_SIZE, (uint)sb_data_size);
// Write the class id
Array.Copy(child.ClassID, 0, buf, DIRENT_CLSID, child.ClassID.Length);
}
else if (child.Type == MSOleOutfileType.MSOLE_DIR)
{
buf[DIRENT_TYPE] = DIRENT_TYPE_DIR;
writeTemp = BitConverter.GetBytes((uint)(BAT_MAGIC_END_OF_CHAIN));
Array.Copy(writeTemp, 0, buf, DIRENT_FIRSTBLOCK, writeTemp.Length);
writeTemp = BitConverter.GetBytes((uint)(0));
Array.Copy(writeTemp, 0, buf, DIRENT_FILE_SIZE, writeTemp.Length);
GSF_LE_SET_GUINT8(buf, DIRENT_TYPE, DIRENT_TYPE_DIR);
GSF_LE_SET_GUINT32(buf, DIRENT_FIRSTBLOCK, BAT_MAGIC_END_OF_CHAIN);
GSF_LE_SET_GUINT32(buf, DIRENT_FILE_SIZE, 0);
// Write the class id
Array.Copy(child.ClassID, 0, buf, DIRENT_CLSID, child.ClassID.Length);
@@ -703,20 +688,15 @@ namespace LibGSF.Output
if (size != child.Parent.CurrentSize)
Console.Error.WriteLine("File too big");
buf[DIRENT_TYPE] = DIRENT_TYPE_FILE;
writeTemp = BitConverter.GetBytes((uint)(child.FirstBlock));
Array.Copy(writeTemp, 0, buf, DIRENT_FIRSTBLOCK, writeTemp.Length);
writeTemp = BitConverter.GetBytes((uint)(size));
Array.Copy(writeTemp, 0, buf, DIRENT_FILE_SIZE, writeTemp.Length);
GSF_LE_SET_GUINT8(buf, DIRENT_TYPE, DIRENT_TYPE_FILE);
GSF_LE_SET_GUINT32(buf, DIRENT_FIRSTBLOCK, (uint)child.FirstBlock);
GSF_LE_SET_GUINT32(buf, DIRENT_FILE_SIZE, size);
}
writeTemp = BitConverter.GetBytes((ulong)(child.ModTime?.ToFileTime() ?? 0));
Array.Copy(writeTemp, 0, buf, DIRENT_MODIFY_TIME, writeTemp.Length);
GSF_LE_SET_GUINT64(buf, DIRENT_MODIFY_TIME, (ulong)(child.ModTime?.ToFileTime() ?? 0));
// Make everything black (red == 0)
buf[DIRENT_COLOUR] = 1;
GSF_LE_SET_GUINT8(buf, DIRENT_COLOUR, 1);
GsfOutfileMSOle tmp = child.Container as GsfOutfileMSOle;
next = DIRENT_MAGIC_END;
@@ -739,11 +719,8 @@ namespace LibGSF.Output
}
// Make linked list rather than tree, only use next
writeTemp = BitConverter.GetBytes((uint)(DIRENT_MAGIC_END));
Array.Copy(writeTemp, 0, buf, DIRENT_PREV, writeTemp.Length);
writeTemp = BitConverter.GetBytes((uint)(next));
Array.Copy(writeTemp, 0, buf, DIRENT_NEXT, writeTemp.Length);
GSF_LE_SET_GUINT32(buf, DIRENT_PREV, DIRENT_MAGIC_END);
GSF_LE_SET_GUINT32(buf, DIRENT_NEXT, next);
uint child_index = DIRENT_MAGIC_END;
if (child.Type == MSOleOutfileType.MSOLE_DIR && child.Content_Dir_Children != null)
@@ -752,8 +729,7 @@ namespace LibGSF.Output
child_index = (uint)first.ChildIndex;
}
writeTemp = BitConverter.GetBytes((uint)(child_index));
Array.Copy(writeTemp, 0, buf, DIRENT_CHILD, writeTemp.Length);
GSF_LE_SET_GUINT32(buf, DIRENT_CHILD, child_index);
Sink.Write(DIRENT_SIZE, buf);
}
@@ -830,40 +806,27 @@ namespace LibGSF.Output
if (BigBlock.Size == 4096)
{
// Set _cSectDir for 4k sector files
outerTemp = BitConverter.GetBytes((uint)(num_dirent_blocks));
Array.Copy(outerTemp, 0, buf, 0, outerTemp.Length);
GSF_LE_SET_GUINT32(buf, 0, (uint)num_dirent_blocks);
Sink.Seek(OLE_HEADER_CSECTDIR, SeekOrigin.Begin);
Sink.Write(4, buf);
}
GSF_LE_SET_GUINT32(buf, 0, (uint)num_bat);
GSF_LE_SET_GUINT32(buf, 4, (uint)dirent_start);
Sink.Seek(OLE_HEADER_NUM_BAT, SeekOrigin.Begin);
outerTemp = BitConverter.GetBytes((uint)(num_bat));
Array.Copy(outerTemp, 0, buf, 0, outerTemp.Length);
Sink.Write(4, buf);
outerTemp = BitConverter.GetBytes((uint)(dirent_start));
Array.Copy(outerTemp, 0, buf, 0, outerTemp.Length);
Sink.Write(4, buf);
Sink.Write(8, buf);
GSF_LE_SET_GUINT32(buf, 0x0, (num_sbat > 0) ? (uint)sbat_start : BAT_MAGIC_END_OF_CHAIN);
GSF_LE_SET_GUINT32(buf, 0x4, (uint)num_sbat);
GSF_LE_SET_GUINT32(buf, 0x8, xbat_pos);
GSF_LE_SET_GUINT32(buf, 0xc, (uint)num_xbat);
Sink.Seek(OLE_HEADER_SBAT_START, SeekOrigin.Begin);
outerTemp = BitConverter.GetBytes((uint)((num_sbat > 0) ? (uint)sbat_start : BAT_MAGIC_END_OF_CHAIN));
Array.Copy(outerTemp, 0, buf, 0, outerTemp.Length);
Sink.Write(4, buf);
outerTemp = BitConverter.GetBytes((uint)(num_sbat));
Array.Copy(outerTemp, 0, buf, 0, outerTemp.Length);
Sink.Write(4, buf);
outerTemp = BitConverter.GetBytes((uint)(xbat_pos));
Array.Copy(outerTemp, 0, buf, 0, outerTemp.Length);
Sink.Write(4, buf);
outerTemp = BitConverter.GetBytes((uint)(num_xbat));
Array.Copy(outerTemp, 0, buf, 0, outerTemp.Length);
Sink.Write(4, buf);
Sink.Write(0x10, buf);
// Write initial Meta-BAT
for (int i = 0; i < blocks; i++)
{
outerTemp = BitConverter.GetBytes((uint)(bat_start + i));
Array.Copy(outerTemp, 0, buf, 0, outerTemp.Length);
GSF_LE_SET_GUINT32(buf, 0, (uint)(bat_start + i));
Sink.Write(BAT_INDEX_SIZE, buf);
}
@@ -878,8 +841,7 @@ namespace LibGSF.Output
blocks = (int)((num_bat > metabat_size) ? metabat_size : num_bat);
for (int j = 0; j < blocks; j++)
{
outerTemp = BitConverter.GetBytes((uint)(bat_start + j));
Array.Copy(outerTemp, 0, buf, 0, outerTemp.Length);
GSF_LE_SET_GUINT32(buf, 0, (uint)(bat_start + j));
Sink.Write(BAT_INDEX_SIZE, buf);
}
@@ -893,8 +855,7 @@ namespace LibGSF.Output
xbat_pos++;
}
outerTemp = BitConverter.GetBytes((uint)(xbat_pos));
Array.Copy(outerTemp, 0, buf, 0, outerTemp.Length);
GSF_LE_SET_GUINT32(buf, 0, xbat_pos);
Sink.Write(BAT_INDEX_SIZE, buf);
}
}

View File

@@ -26,6 +26,7 @@ using System.IO;
using System.Text;
using ComponentAce.Compression.Libs.zlib;
using static ComponentAce.Compression.Libs.zlib.zlibConst;
using static LibGSF.GsfUtils;
using static LibGSF.GsfZipImpl;
namespace LibGSF.Output
@@ -321,7 +322,7 @@ namespace LibGSF.Output
if (zip64_here)
{
List<byte> tmp = new List<byte>();
byte[] tmp = new byte[8];
// We could unconditionally store the offset here, but
// zipinfo has a known bug in which it fails to account
@@ -329,110 +330,119 @@ namespace LibGSF.Output
// and the local headers. So we try to make them the
// same.
tmp.AddRange(BitConverter.GetBytes((ushort)(ExtraFieldTags.ZIP_DIRENT_EXTRA_FIELD_ZIP64)));
tmp.AddRange(BitConverter.GetBytes((ushort)((2 + (offset_in_zip64 ? 1 : 0) * 8))));
tmp.AddRange(BitConverter.GetBytes((ulong)(dirent.UncompressedSize)));
tmp.AddRange(BitConverter.GetBytes((ulong)(dirent.CompressedSize)));
GSF_LE_SET_GUINT16(tmp, 0, (ushort)ExtraFieldTags.ZIP_DIRENT_EXTRA_FIELD_ZIP64);
GSF_LE_SET_GUINT16(tmp, 2, (ushort)(2 + (offset_in_zip64 ? 1 : 0) * 8));
extras.AddRange(new ReadOnlySpan<byte>(tmp, 0, 4).ToArray());
GSF_LE_SET_GUINT64(tmp, 0, (ulong)dirent.UncompressedSize);
extras.AddRange(new ReadOnlySpan<byte>(tmp, 0, 8).ToArray());
GSF_LE_SET_GUINT64(tmp, 0, (ulong)dirent.CompressedSize);
extras.AddRange(new ReadOnlySpan<byte>(tmp, 0, 8).ToArray());
if (offset_in_zip64)
tmp.AddRange(BitConverter.GetBytes((ulong)(dirent.Offset)));
extras.AddRange(tmp);
{
GSF_LE_SET_GUINT64(tmp, 0, (ulong)dirent.Offset);
extras.AddRange(new ReadOnlySpan<byte>(tmp, 0, 8).ToArray());
}
}
else if (dirent.Zip64 == null)
{
List<byte> tmp = new List<byte>();
byte[] tmp = new byte[8];
// Match the local header.
tmp.AddRange(BitConverter.GetBytes((ushort)(ExtraFieldTags.ZIP_DIRENT_EXTRA_FIELD_IGNORE)));
tmp.AddRange(BitConverter.GetBytes((ushort)(2 * 8)));
tmp.AddRange(BitConverter.GetBytes((ulong)(0)));
tmp.AddRange(BitConverter.GetBytes((ulong)(0)));
extras.AddRange(tmp);
GSF_LE_SET_GUINT16(tmp, 0, (ushort)ExtraFieldTags.ZIP_DIRENT_EXTRA_FIELD_IGNORE);
GSF_LE_SET_GUINT16(tmp, 2, 2 * 8);
extras.AddRange(new ReadOnlySpan<byte>(tmp, 0, 4).ToArray());
GSF_LE_SET_GUINT64(tmp, 0, 0);
extras.AddRange(new ReadOnlySpan<byte>(tmp, 0, 8).ToArray());
GSF_LE_SET_GUINT64(tmp, 0, 0);
extras.AddRange(new ReadOnlySpan<byte>(tmp, 0, 8).ToArray());
}
if (ZIP_ADD_UNIXTIME_FIELD && dirent.ModifiedTime != null && !SpecialMimetypeDirectoryEntry(dirent))
{
// Clearly a year 2038 problem here.
List<byte> tmp = new List<byte>();
byte[] tmp = new byte[4];
tmp.AddRange(BitConverter.GetBytes((ushort)(ExtraFieldTags.ZIP_DIRENT_EXTRA_FIELD_UNIXTIME)));
tmp.AddRange(BitConverter.GetBytes((ushort)(5)));
tmp.Add(1);
tmp.AddRange(BitConverter.GetBytes((uint)(new DateTimeOffset(dirent.ModifiedTime ?? DateTime.UtcNow).ToUnixTimeSeconds())));
extras.AddRange(tmp);
GSF_LE_SET_GUINT16(tmp, 0, (ushort)(ExtraFieldTags.ZIP_DIRENT_EXTRA_FIELD_UNIXTIME));
GSF_LE_SET_GUINT16(tmp, 2, 5);
extras.AddRange(new ReadOnlySpan<byte>(tmp, 0, 4).ToArray());
tmp[0] = 1;
extras.AddRange(new ReadOnlySpan<byte>(tmp, 0, 1).ToArray());
GSF_LE_SET_GUINT32(tmp, 0, (uint)new DateTimeOffset(dirent.ModifiedTime ?? DateTime.UtcNow).ToUnixTimeSeconds());
extras.AddRange(new ReadOnlySpan<byte>(tmp, 0, 4).ToArray());
}
List<byte> buf = new List<byte>(ZIP_DIRENT_SIZE);
byte[] buf = new byte[ZIP_DIRENT_SIZE];
buf.AddRange(BitConverter.GetBytes((uint)(ZIP_DIRENT_SIGNATURE)));
buf.AddRange(BitConverter.GetBytes((ushort)(((int)OSCodes.ZIP_OS_UNIX << 8) + extract)));
buf.AddRange(BitConverter.GetBytes((ushort)(((int)OSCodes.ZIP_OS_MSDOS << 8) + extract)));
buf.AddRange(BitConverter.GetBytes((ushort)(dirent.Flags)));
buf.AddRange(BitConverter.GetBytes((ushort)(dirent.CompressionMethod)));
buf.AddRange(BitConverter.GetBytes((uint)(dirent.DosTime)));
buf.AddRange(BitConverter.GetBytes((uint)(dirent.CRC32)));
buf.AddRange(BitConverter.GetBytes((uint)(zip64_here ? uint.MaxValue : dirent.CompressedSize)));
buf.AddRange(BitConverter.GetBytes((uint)(zip64_here ? uint.MaxValue : dirent.UncompressedSize)));
buf.AddRange(BitConverter.GetBytes((ushort)(nlen)));
buf.AddRange(BitConverter.GetBytes((ushort)(extras.Count)));
buf.AddRange(BitConverter.GetBytes((ushort)(0)));
buf.AddRange(BitConverter.GetBytes((ushort)(0)));
buf.AddRange(BitConverter.GetBytes((ushort)(0)));
GSF_LE_SET_GUINT32(buf, 0, ZIP_DIRENT_SIGNATURE);
GSF_LE_SET_GUINT16(buf, ZIP_DIRENT_ENCODER, (ushort)(((int)OSCodes.ZIP_OS_UNIX << 8) + extract));
GSF_LE_SET_GUINT16(buf, ZIP_DIRENT_EXTRACT, (ushort)(((int)OSCodes.ZIP_OS_MSDOS << 8) + extract));
GSF_LE_SET_GUINT16(buf, ZIP_DIRENT_FLAGS, (ushort)dirent.Flags);
GSF_LE_SET_GUINT16(buf, ZIP_DIRENT_COMPR_METHOD, (ushort)dirent.CompressionMethod);
GSF_LE_SET_GUINT32(buf, ZIP_DIRENT_DOSTIME, dirent.DosTime);
GSF_LE_SET_GUINT32(buf, ZIP_DIRENT_CRC32, dirent.CRC32);
GSF_LE_SET_GUINT32(buf, ZIP_DIRENT_CSIZE, (uint)(zip64_here ? uint.MaxValue : dirent.CompressedSize));
GSF_LE_SET_GUINT32(buf, ZIP_DIRENT_USIZE, (uint)(zip64_here ? uint.MaxValue : dirent.UncompressedSize));
GSF_LE_SET_GUINT16(buf, ZIP_DIRENT_NAME_SIZE, (ushort)nlen);
GSF_LE_SET_GUINT16(buf, ZIP_DIRENT_EXTRAS_SIZE, (ushort)extras.Count);
GSF_LE_SET_GUINT16(buf, ZIP_DIRENT_COMMENT_SIZE, 0);
GSF_LE_SET_GUINT16(buf, ZIP_DIRENT_DISKSTART, 0);
GSF_LE_SET_GUINT16(buf, ZIP_DIRENT_FILE_TYPE, 0);
// Hardcode file mode 644
buf.AddRange(BitConverter.GetBytes((uint)(0100644u << 16)));
buf.AddRange(BitConverter.GetBytes((uint)(offset_in_zip64 ? uint.MaxValue : dirent.Offset)));
GSF_LE_SET_GUINT32(buf, ZIP_DIRENT_FILE_MODE, 0100644u << 16);
GSF_LE_SET_GUINT32(buf, ZIP_DIRENT_OFFSET, (uint)(offset_in_zip64 ? uint.MaxValue : dirent.Offset));
// Stuff everything into buf so we can do just one write.
buf.AddRange(extras);
buf.AddRange(Encoding.ASCII.GetBytes(dirent.Name));
List<byte> header = new List<byte>();
header.AddRange(buf);
header.AddRange(extras);
header.AddRange(Encoding.ASCII.GetBytes(dirent.Name));
return Sink.Write(buf.Count, buf.ToArray());
return Sink.Write(header.Count, header.ToArray());
}
private bool TrailerWrite(int entries, long dirpos, long dirsize)
{
List<byte> buf = new List<byte>(ZIP_TRAILER_SIZE);
byte[] buf = new byte[ZIP_TRAILER_SIZE];
buf.AddRange(BitConverter.GetBytes((uint)(ZIP_TRAILER_SIGNATURE)));
buf.AddRange(BitConverter.GetBytes((ushort)(Math.Min(entries, ushort.MaxValue))));
buf.AddRange(BitConverter.GetBytes((ushort)(Math.Min(dirsize, ushort.MaxValue))));
buf.AddRange(BitConverter.GetBytes((ushort)(Math.Min(dirpos, ushort.MaxValue))));
GSF_LE_SET_GUINT32(buf, 0, ZIP_TRAILER_SIGNATURE);
GSF_LE_SET_GUINT16(buf, ZIP_TRAILER_ENTRIES, (ushort)Math.Min(entries, ushort.MaxValue));
GSF_LE_SET_GUINT16(buf, ZIP_TRAILER_TOTAL_ENTRIES, (ushort)Math.Min(entries, ushort.MaxValue));
GSF_LE_SET_GUINT32(buf, ZIP_TRAILER_DIR_SIZE, (uint)Math.Min(dirsize, uint.MaxValue));
GSF_LE_SET_GUINT32(buf, ZIP_TRAILER_DIR_POS, (uint)Math.Min(dirpos, uint.MaxValue));
return Sink.Write(buf.Count, buf.ToArray());
return Sink.Write(buf.Length, buf);
}
private bool Trailer64Write(int entries, long dirpos, long dirsize)
{
List<byte> buf = new List<byte>(ZIP_TRAILER64_SIZE);
byte[] buf = new byte[ZIP_TRAILER64_SIZE];
byte extract = 45;
buf.AddRange(BitConverter.GetBytes((uint)(ZIP_TRAILER64_SIGNATURE)));
buf.AddRange(BitConverter.GetBytes((ulong)(ZIP_TRAILER64_SIZE - 12)));
buf.AddRange(BitConverter.GetBytes((ushort)(((int)OSCodes.ZIP_OS_UNIX << 8) + extract)));
buf.AddRange(BitConverter.GetBytes((ushort)(((int)OSCodes.ZIP_OS_MSDOS << 8) + extract)));
buf.AddRange(BitConverter.GetBytes((uint)(0)));
buf.AddRange(BitConverter.GetBytes((uint)(0)));
buf.AddRange(BitConverter.GetBytes((uint)(entries)));
buf.AddRange(BitConverter.GetBytes((uint)(entries)));
buf.AddRange(BitConverter.GetBytes((ulong)(dirsize)));
buf.AddRange(BitConverter.GetBytes((ulong)(dirpos)));
GSF_LE_SET_GUINT32(buf, 0, ZIP_TRAILER64_SIGNATURE);
GSF_LE_SET_GUINT64(buf, ZIP_TRAILER64_RECSIZE, ZIP_TRAILER64_SIZE - 12);
GSF_LE_SET_GUINT16(buf, ZIP_TRAILER64_ENCODER, (ushort)(((int)OSCodes.ZIP_OS_UNIX << 8) + extract));
GSF_LE_SET_GUINT16(buf, ZIP_TRAILER64_EXTRACT, (ushort)(((int)OSCodes.ZIP_OS_MSDOS << 8) + extract));
GSF_LE_SET_GUINT32(buf, ZIP_TRAILER64_DISK, 0);
GSF_LE_SET_GUINT32(buf, ZIP_TRAILER64_DIR_DISK, 0);
GSF_LE_SET_GUINT32(buf, ZIP_TRAILER64_ENTRIES, (uint)entries);
GSF_LE_SET_GUINT32(buf, ZIP_TRAILER64_TOTAL_ENTRIES, (uint)entries);
GSF_LE_SET_GUINT64(buf, ZIP_TRAILER64_DIR_SIZE, (ulong)dirsize);
GSF_LE_SET_GUINT64(buf, ZIP_TRAILER64_DIR_POS, (ulong)dirpos);
return Sink.Write(buf.Count, buf.ToArray());
return Sink.Write(buf.Length, buf);
}
private bool Zip64LocatorWrite(long trailerpos)
{
List<byte> buf = new List<byte>(ZIP_ZIP64_LOCATOR_SIZE);
byte[] buf = new byte[ZIP_ZIP64_LOCATOR_SIZE];
buf.AddRange(BitConverter.GetBytes((uint)(ZIP_ZIP64_LOCATOR_SIGNATURE)));
buf.AddRange(BitConverter.GetBytes((uint)(0)));
buf.AddRange(BitConverter.GetBytes((ulong)(trailerpos)));
buf.AddRange(BitConverter.GetBytes((uint)(1)));
GSF_LE_SET_GUINT32(buf, 0, ZIP_ZIP64_LOCATOR_SIGNATURE);
GSF_LE_SET_GUINT32(buf, ZIP_ZIP64_LOCATOR_DISK, 0);
GSF_LE_SET_GUINT64(buf, ZIP_TRAILER64_DIR_POS, (ulong)trailerpos);
GSF_LE_SET_GUINT32(buf, ZIP_ZIP64_LOCATOR_DISKS, 1);
return Sink.Write(buf.Count, buf.ToArray());
return Sink.Write(buf.Length, buf);
}
private static int OffsetOrdering(GsfOutfileZip a, GsfOutfileZip b)
@@ -569,13 +579,13 @@ namespace LibGSF.Output
private bool HeaderWrite()
{
List<byte> hbuf = new List<byte>(ZIP_HEADER_SIZE);
byte[] hbuf = new byte[ZIP_HEADER_SIZE];
GsfZipDirectoryEntry dirent = VDir.DirectoryEntry;
string name = dirent.Name;
int nlen = name.Length;
hbuf.AddRange(BitConverter.GetBytes((uint)(ZIP_HEADER_SIGNATURE)));
GSF_LE_SET_GUINT32(hbuf, 0, ZIP_HEADER_SIGNATURE);
if (SinkIsSeekable == null)
{
@@ -584,12 +594,12 @@ namespace LibGSF.Output
// try to seek back onto it. If seeking back fails, just
// don't rewrite it.
if (!Sink.Write(4, hbuf.ToArray()))
if (!Sink.Write(4, hbuf))
return false;
SinkIsSeekable = Sink.Seek(dirent.Offset, SeekOrigin.Begin);
if (SinkIsSeekable == false)
hbuf.Clear();
hbuf = new byte[ZIP_HEADER_SIZE];
}
// Now figure out if we need a DDESC record.
@@ -633,47 +643,51 @@ namespace LibGSF.Output
// Auto or forced
if (dirent.Zip64 != false)
{
List<byte> tmp = new List<byte>();
byte[] tmp = new byte[8];
ExtraFieldTags typ = real_zip64
? ExtraFieldTags.ZIP_DIRENT_EXTRA_FIELD_ZIP64
: ExtraFieldTags.ZIP_DIRENT_EXTRA_FIELD_IGNORE;
tmp.AddRange(BitConverter.GetBytes((ushort)(typ)));
tmp.AddRange(BitConverter.GetBytes((ushort)(2 * 8)));
tmp.AddRange(BitConverter.GetBytes((ulong)(usize)));
tmp.AddRange(BitConverter.GetBytes((ulong)(csize)));
extras.AddRange(tmp);
GSF_LE_SET_GUINT16(tmp, 0, (ushort)typ);
GSF_LE_SET_GUINT16(tmp, 2, 2 * 8);
extras.AddRange(new ReadOnlySpan<byte>(tmp, 0, 4).ToArray());
GSF_LE_SET_GUINT64(tmp, 0, (ulong)usize);
extras.AddRange(new ReadOnlySpan<byte>(tmp, 0, 8).ToArray());
GSF_LE_SET_GUINT64(tmp, 0, (ulong)csize);
extras.AddRange(new ReadOnlySpan<byte>(tmp, 0, 8).ToArray());
}
if (ZIP_ADD_UNIXTIME_FIELD && dirent.ModifiedTime != null && !SpecialMimetypeDirectoryEntry(dirent))
{
List<byte> tmp = new List<byte>();
byte[] tmp = new byte[4];
// Clearly a year 2038 problem here.
tmp.AddRange(BitConverter.GetBytes((ushort)(ExtraFieldTags.ZIP_DIRENT_EXTRA_FIELD_UNIXTIME)));
tmp.AddRange(BitConverter.GetBytes((ushort)(5)));
tmp.Add(1);
tmp.AddRange(BitConverter.GetBytes((uint)(new DateTimeOffset(dirent.ModifiedTime ?? DateTime.UtcNow).ToUnixTimeSeconds())));
extras.AddRange(tmp);
GSF_LE_SET_GUINT16(tmp, 0, (ushort)ExtraFieldTags.ZIP_DIRENT_EXTRA_FIELD_UNIXTIME);
GSF_LE_SET_GUINT16(tmp, 2, 5);
extras.AddRange(new ReadOnlySpan<byte>(tmp, 0, 4).ToArray());
tmp[0] = 1;
extras.AddRange(new ReadOnlySpan<byte>(tmp, 0, 1).ToArray());
GSF_LE_SET_GUINT32(tmp, 0, (uint)new DateTimeOffset(dirent.ModifiedTime ?? DateTime.UtcNow).ToUnixTimeSeconds());
extras.AddRange(new ReadOnlySpan<byte>(tmp, 0, 4).ToArray());
}
hbuf.AddRange(BitConverter.GetBytes((ushort)(((int)OSCodes.ZIP_OS_MSDOS << 8) + extract)));
hbuf.AddRange(BitConverter.GetBytes((ushort)(dirent.Flags)));
hbuf.AddRange(BitConverter.GetBytes((ushort)(dirent.CompressionMethod)));
hbuf.AddRange(BitConverter.GetBytes((uint)(dirent.DosTime)));
hbuf.AddRange(BitConverter.GetBytes((uint)(crc32)));
hbuf.AddRange(BitConverter.GetBytes((uint)(real_zip64 && !has_ddesc ? uint.MaxValue : csize)));
hbuf.AddRange(BitConverter.GetBytes((uint)(real_zip64 && !has_ddesc ? uint.MaxValue : usize)));
hbuf.AddRange(BitConverter.GetBytes((ushort)(nlen)));
hbuf.AddRange(BitConverter.GetBytes((ushort)(extras.Count)));
GSF_LE_SET_GUINT16(hbuf, ZIP_HEADER_EXTRACT, (ushort)(((int)OSCodes.ZIP_OS_MSDOS << 8) + extract));
GSF_LE_SET_GUINT16(hbuf, ZIP_HEADER_FLAGS, (ushort)dirent.Flags);
GSF_LE_SET_GUINT16(hbuf, ZIP_HEADER_COMP_METHOD, (ushort)dirent.CompressionMethod);
GSF_LE_SET_GUINT32(hbuf, ZIP_HEADER_DOSTIME, dirent.DosTime);
GSF_LE_SET_GUINT32(hbuf, ZIP_HEADER_CRC32, crc32);
GSF_LE_SET_GUINT32(hbuf, ZIP_HEADER_CSIZE, (uint)(real_zip64 && !has_ddesc ? uint.MaxValue : csize));
GSF_LE_SET_GUINT32(hbuf, ZIP_HEADER_USIZE, (uint)(real_zip64 && !has_ddesc ? uint.MaxValue : usize));
GSF_LE_SET_GUINT16(hbuf, ZIP_HEADER_NAME_SIZE, (ushort)nlen);
GSF_LE_SET_GUINT16(hbuf, ZIP_HEADER_EXTRAS_SIZE, (ushort)extras.Count);
// Stuff everything into buf so we can do just one write.
hbuf.AddRange(extras);
hbuf.AddRange(Encoding.ASCII.GetBytes(name));
List<byte> header = new List<byte>();
header.AddRange(hbuf);
header.AddRange(extras);
header.AddRange(Encoding.ASCII.GetBytes(name));
bool ret = Sink.Write(hbuf.Count, hbuf.ToArray());
bool ret = Sink.Write(header.Count, header.ToArray());
if (real_zip64)
dirent.Zip64 = true;
@@ -784,7 +798,7 @@ namespace LibGSF.Output
/// </summary>
private bool DataDescriptorWrite()
{
List<byte> buf = new List<byte>(Math.Max(ZIP_DDESC_SIZE, ZIP_DDESC64_SIZE));
byte[] buf = new byte[Math.Max(ZIP_DDESC_SIZE, ZIP_DDESC64_SIZE)];
GsfZipDirectoryEntry dirent = VDir.DirectoryEntry;
int size;
@@ -792,22 +806,22 @@ namespace LibGSF.Output
if (dirent.Zip64 != false)
{
buf.AddRange(BitConverter.GetBytes((uint)(ZIP_DDESC64_SIGNATURE)));
buf.AddRange(BitConverter.GetBytes((uint)(dirent.CRC32)));
buf.AddRange(BitConverter.GetBytes((ulong)(dirent.CompressedSize)));
buf.AddRange(BitConverter.GetBytes((ulong)(dirent.UncompressedSize)));
GSF_LE_SET_GUINT32(buf, 0, ZIP_DDESC64_SIGNATURE);
GSF_LE_SET_GUINT32(buf, ZIP_DDESC64_CRC32, dirent.CRC32);
GSF_LE_SET_GUINT64(buf, ZIP_DDESC64_CSIZE, (ulong)dirent.CompressedSize);
GSF_LE_SET_GUINT64(buf, ZIP_DDESC64_USIZE, (ulong)dirent.UncompressedSize);
size = ZIP_DDESC64_SIZE;
}
else
{
buf.AddRange(BitConverter.GetBytes((uint)(ZIP_DDESC_SIGNATURE)));
buf.AddRange(BitConverter.GetBytes((uint)(dirent.CRC32)));
buf.AddRange(BitConverter.GetBytes((uint)(dirent.CompressedSize)));
buf.AddRange(BitConverter.GetBytes((uint)(dirent.UncompressedSize)));
GSF_LE_SET_GUINT32(buf, 0, ZIP_DDESC_SIGNATURE);
GSF_LE_SET_GUINT32(buf, ZIP_DDESC_CRC32, dirent.CRC32);
GSF_LE_SET_GUINT32(buf, ZIP_DDESC_CSIZE, (uint)dirent.CompressedSize);
GSF_LE_SET_GUINT32(buf, ZIP_DDESC_USIZE, (uint)dirent.UncompressedSize);
size = ZIP_DDESC_SIZE;
}
if (!Sink.Write(size, buf.ToArray()))
if (!Sink.Write(size, buf))
return false;
return true;

View File

@@ -134,7 +134,7 @@ namespace LibGSF.Output
return false;
}
/// <returns>true if the wrapping succeeded.</returns>
/// <returns>True if the wrapping succeeded.</returns>
public bool Wrap(object wrapper)
{
if (wrapper == null)
@@ -164,7 +164,7 @@ namespace LibGSF.Output
/// </summary>
/// <param name="format">The printf-style format string</param>
/// <param name="va">The arguments for @format</param>
/// <returns>true if successful, false if not</returns>
/// <returns>True if successful, false if not</returns>
public bool PrintF(string format, params string[] va) => VPrintF(format, va) >= 0;
/// <summary>

View File

@@ -25,6 +25,7 @@ using System.IO;
using System.Text;
using ComponentAce.Compression.Libs.zlib;
using static ComponentAce.Compression.Libs.zlib.zlibConst;
using static LibGSF.GsfUtils;
namespace LibGSF.Output
{
@@ -174,11 +175,11 @@ namespace LibGSF.Output
if (!Raw)
{
List<byte> buf = new List<byte>();
byte[] buf = new byte[8];
buf.AddRange(BitConverter.GetBytes((uint)(CRC)));
buf.AddRange(BitConverter.GetBytes((uint)(ISize)));
if (!Sink.Write(8, buf.ToArray()))
GSF_LE_SET_GUINT32(buf, 0, CRC);
GSF_LE_SET_GUINT32(buf, 4, (uint)(ISize));
if (!Sink.Write(8, buf))
return false;
}
}
@@ -214,7 +215,7 @@ namespace LibGSF.Output
private bool OutputHeader()
{
List<byte> buf = new List<byte>(3 + 1 + 4 + 2);
byte[] buf = new byte[3 + 1 + 4 + 2];
DateTime? modtime = ModTime;
ulong mtime = (ulong)(modtime != null ? new DateTimeOffset(modtime.Value).ToUnixTimeSeconds() : 0);
@@ -223,14 +224,13 @@ namespace LibGSF.Output
// FIXME: What to do about gz extension ... ?
int nlen = 0; // name ? strlen (name) : 0;
buf.AddRange(new byte[] { 0x1f, 0x8b, 0x08 });
Array.Copy(new byte[] { 0x1f, 0x8b, 0x08 }, buf, 3);
if (nlen > 0)
buf.Add(GZIP_ORIGINAL_NAME);
buf[3] = GZIP_ORIGINAL_NAME;
buf.AddRange(BitConverter.GetBytes((uint)(mtime)));
buf.Add(3); // UNIX
bool ret = Sink.Write(buf.Count, buf.ToArray());
GSF_LE_SET_GUINT32(buf, 4, (uint)mtime);
buf[9] = 3; // UNIX
bool ret = Sink.Write(buf.Length, buf);
if (ret && name != null && nlen > 0)
ret = Sink.Write(nlen, Encoding.ASCII.GetBytes(name));